/* ============================================================
   ARCANE SYNTHESIS · Design Tokens
   Source: DESIGN.md + PRD.md
   ============================================================ */

:root {
  /* Surfaces */
  --surface: #091609;
  --surface-dim: #051105;
  --surface-bright: #2e3d2d;
  --surface-container: #152315;
  --surface-container-high: #1f2d1f;
  --surface-container-highest: #2a3829;

  /* Text */
  --on-surface: #d6e7d1;
  --on-surface-variant: #d4c3bd;
  --on-surface-muted: rgba(214, 231, 209, 0.55);

  /* Brand accents */
  --primary: #e5beae;
  --on-primary: #432b1f;
  --primary-container: #2b160c;
  --gold: #c2a46b;
  --gold-dim: rgba(194, 164, 107, 0.35);
  /* Arcane purple — the 4th accent. Reads instantly as magic / AI,
     completing the elemental legend:
       green = growth · gold = knowledge · blue = cosmos · purple = magic/AI
     Reserved for the Arcane Core, AI-flavoured elements and special FX. */
  --arcane: #8B5CF6;
  --arcane-bright: #A855F7;
  --arcane-deep: #6D28D9;
  --ochre: #ae8452;
  --rust: #a13e1e;
  --burgundy: #831b1a;
  --tertiary: #eebe87;
  --secondary: #afcdc1;
  --secondary-container: #314c43;
  /* Tolkien forged-metal palette — drives the hero-lede manifesto
     engraving (.hero__lede). Each token mirrors the brief:
       --metal-dark    base / shadow of the inscription
       --bronze-old    bronze antigo midtone
       --gold-aged     ouro envelhecido sheen
       --ember-amber   âmbar vulcânico ember-1 core
       --ember-magma   laranja magma   ember-2 core
       --ember-incand  vermelho incandescente tail
       --gold-burning  dourado ardente inner light / hover
     Available globally so future Tolkien accents can reuse them. */
  --metal-dark:    #2B2017;
  --bronze-old:    #6A4A2C;
  --gold-aged:     #C9A15F;
  --ember-amber:   #E08A2E;
  --ember-magma:   #D9651A;
  --ember-incand:  #A63B1E;
  --gold-burning:  #F2C879;

  /* Glass */
  --glass-bg: rgba(15, 42, 34, 0.45);
  --glass-border: rgba(194, 164, 107, 0.18);
  --glass-blur: 20px;

  /* Typography
     ── Global typographic system ────────────────────────────────
     --font-display → titles & subtitles (Cinzel, all-caps Roman serif)
     --font-body    → paragraphs, buttons, card content (Inter)
     --font-mono    → terminal-style labels / eyebrows (JetBrains Mono)
     --font-tengwar → the One Ring inscription around the portrait
     NOTE — The Merlin scope, the Codex do Arquiteto scope, and the
     Codex dos Contratos Arcanos scope each keep their bespoke
     manuscript fonts (Cormorant Garamond, Libre Caslon Text) by
     declaring font-family explicitly, so the variable swap below
     never reaches them. */
  --font-display: "Cinzel", "Libre Caslon Text", Georgia, serif;
  --font-body: "Inter", "Hanken Grotesk", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", monospace;
  --font-tengwar: "Tengwar Annatar", "Libre Caslon Text", serif;

  /* Spacing */
  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 2rem;
  --space-lg: 4rem;
  --space-xl: 6rem;
  --container-max: 1200px;
  --margin-safe: 24px;

  /* Radii (shape lock: sharp architectural) */
  --radius-sm: 0.125rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-full: 9999px;

  /* Motion */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 0.2s;
  --duration-med: 0.45s;
  --duration-slow: 0.9s;

  /* Z-index scale */
  --z-bg: 0;
  --z-content: 10;
  --z-nav: 100;
  --z-merlin: 200;
  --z-grain: 60;
  /* Ambient right-rail artefact (Domínios em Expansão). Sits above
     content/grain but below nav and Merlin so it never competes
     with the focal UI — it is a quiet companion, not a widget. */
  --z-domains: 80;
}

/* ============================================================
   RESET & BASE
   ============================================================ */

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

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Root-level horizontal clip. <html> is the element that actually
     scrolls, so this is what stops sideways scrolling on mobile.
     Several decorative glows (.craft__*-aura, .relic-card__aura) use
     negative insets and bleed a few px past the viewport edge by
     design; clipping here keeps those bleeds purely cosmetic instead
     of producing a horizontal scrollbar. Paired with body's existing
     overflow-x:hidden. */
  overflow-x: hidden;
}

@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;
  }
}

body {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  color: var(--on-surface);
  background: #040810;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; border: none; background: none; color: inherit; }
ul { list-style: none; }

/* ============================================================
   ATMOSPHERIC BACKGROUND
   ============================================================ */

.bg-vault {
  position: fixed;
  inset: 0;
  z-index: var(--z-bg);
  pointer-events: none;
  overflow: hidden;
}

.bg-gradient {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 80% 60% at 50% 0%, rgba(15, 42, 34, 0.7) 0%, transparent 70%),
    radial-gradient(ellipse 60% 40% at 80% 80%, rgba(43, 22, 12, 0.5) 0%, transparent 60%),
    linear-gradient(180deg, #051105 0%, #091609 40%, #0a0d0c 100%);
}

.bg-godrays {
  position: absolute;
  inset: 0;
  background:
  conic-gradient(from 200deg at 50% -10%, transparent 0deg, rgba(194, 164, 107, 0.04) 30deg, transparent 60deg),
  conic-gradient(from 160deg at 30% -5%, transparent 0deg, rgba(175, 205, 193, 0.03) 20deg, transparent 50deg);
  animation: godray-drift 18s ease-in-out infinite alternate;
}

@keyframes godray-drift {
  from { opacity: 0.6; transform: scale(1); }
  to   { opacity: 1;   transform: scale(1.04) rotate(1deg); }
}

.bg-dust {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.7;
}

.bg-grain {
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px;
}

/* ============================================================
   NAVIGATION
   ============================================================ */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.875rem var(--margin-safe);
  max-height: 72px;
  background: rgba(15, 42, 34, 0.45);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border-bottom: 1px solid var(--glass-border);
  transition: background var(--duration-med) var(--ease-out);
}

/* Scrolled state — toggled by effects.js once the 60px threshold is
   crossed (no per-frame inline-style writes). */
.nav.is-scrolled {
  background: rgba(15, 42, 34, 0.82);
}

.nav__brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

.nav__sigil { color: var(--gold); flex-shrink: 0; display: flex; align-items: center; }

.nav__logo {
  display: block;
  width: 36px;
  height: 36px;
  object-fit: contain;
  filter: drop-shadow(0 0 7px rgba(194, 164, 107, 0.4));
}

.nav__wordmark { display: flex; flex-direction: column; gap: 0.1rem; }

.nav__wordmark-name {
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--primary);
  line-height: 1.1;
}

.nav__wordmark-meta {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-surface-muted);
}

.nav__links {
  display: none;
  gap: 2rem;
}

.nav__links a {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-surface-variant);
  transition: color var(--duration-fast);
  position: relative;
}

.nav__links a::after {
  content: "";
  position: absolute;
  bottom: -4px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transition: transform var(--duration-med) var(--ease-out);
}

.nav__links a:hover,
.nav__links a:focus-visible { color: var(--gold); }
.nav__links a:hover::after,
.nav__links a:focus-visible::after { transform: scaleX(1); }

.nav__tools {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  position: relative;
}

/* MOBILE MENU TRIGGER — hidden on desktop (the inline .nav__links show
   instead). A bronze-edged chip matching the .tool buttons, with an
   animated hamburger that folds into an ✕ when the panel is open. */
.nav__burger {
  display: none;
  width: 38px;
  height: 32px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--on-surface-variant);
  cursor: pointer;
  transition: border-color var(--duration-fast), color var(--duration-fast);
}
.nav__burger:hover,
.nav__burger:focus-visible {
  border-color: var(--gold-dim);
  color: var(--gold);
  outline: none;
}
.nav__burger-bars,
.nav__burger-bars::before,
.nav__burger-bars::after {
  content: "";
  display: block;
  width: 18px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.25s var(--ease-out), background 0.2s linear;
}
.nav__burger-bars { position: relative; }
.nav__burger-bars::before { position: absolute; left: 0; top: -6px; }
.nav__burger-bars::after  { position: absolute; left: 0; top: 6px; }
.nav__burger[aria-expanded="true"] .nav__burger-bars { background: transparent; }
.nav__burger[aria-expanded="true"] .nav__burger-bars::before { transform: translateY(6px) rotate(45deg); }
.nav__burger[aria-expanded="true"] .nav__burger-bars::after  { transform: translateY(-6px) rotate(-45deg); }

.tool {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  color: var(--on-surface-variant);
  transition: border-color var(--duration-fast), color var(--duration-fast);
}

.tool:hover,
.tool:focus-visible {
  border-color: var(--gold-dim);
  color: var(--gold);
  outline: none;
}

.tool[aria-pressed="true"] { color: var(--gold); border-color: var(--gold); }
.tool[aria-pressed="true"] .audio-wave { opacity: 1 !important; }

/* Audio toggle: pulsing waves while playing */
#audio-toggle.is-playing .audio-wave {
  animation: audio-wave-pulse 1.6s ease-in-out infinite;
  opacity: 0.9 !important;
}
#audio-toggle.is-playing .audio-wave:last-of-type {
  animation-delay: 0.4s;
}
#audio-toggle.is-playing svg {
  filter: drop-shadow(0 0 6px rgba(229, 190, 174, 0.7));
}
@keyframes audio-wave-pulse {
  0%, 100% { opacity: 0.4; transform: translateX(0); }
  50%      { opacity: 1;   transform: translateX(0.5px); }
}

/* Theme toggle: sun/moon icon swap with smooth crossfade */
#theme-toggle {
  position: relative;
  width: 32px;
  height: 28px;
  padding: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
}
#theme-toggle .theme-toggle__icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform-origin: center;
  transition: transform 0.5s cubic-bezier(.4,0,.2,1), opacity 0.4s ease;
}
#theme-toggle .theme-toggle__icon--moon {
  transform: translate(-50%, -50%) rotate(0deg) scale(1);
  opacity: 1;
}
#theme-toggle .theme-toggle__icon--sun {
  transform: translate(-50%, -50%) rotate(-90deg) scale(0.4);
  opacity: 0;
}
#theme-toggle[aria-pressed="true"] .theme-toggle__icon--moon {
  transform: translate(-50%, -50%) rotate(90deg) scale(0.4);
  opacity: 0;
}
#theme-toggle[aria-pressed="true"] .theme-toggle__icon--sun {
  transform: translate(-50%, -50%) rotate(0deg) scale(1);
  opacity: 1;
}
#theme-toggle:hover svg {
  filter: drop-shadow(0 0 6px rgba(229, 190, 174, 0.55));
}

.lang-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 130px;
  background: var(--surface-container-high);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px);
  transition: opacity var(--duration-fast), transform var(--duration-fast);
}

.lang-menu.is-open {
  opacity: 1;
  pointer-events: all;
  transform: translateY(0);
}

.lang-menu li {
  padding: 0.55rem 0.875rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  cursor: pointer;
  transition: background var(--duration-fast);
}

.lang-menu li:hover,
.lang-menu li[aria-selected="true"] {
  background: var(--surface-container-highest);
  color: var(--gold);
}

/* ============================================================
   BUTTONS
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border-radius: var(--radius-sm);
  transition: transform var(--duration-fast), box-shadow var(--duration-med), border-color var(--duration-fast);
  white-space: nowrap;
}

.btn:active { transform: scale(0.98); }

.btn--primary {
  background: var(--primary-container);
  color: var(--primary);
  border: 1px solid var(--ochre);
  position: relative;
  overflow: hidden;
}

.btn--primary::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at center, rgba(194, 164, 107, 0.25) 0%, transparent 70%);
  opacity: 0;
  transition: opacity var(--duration-med);
}

.btn--primary:hover::before,
.btn--primary:focus-visible::before { opacity: 1; }

.btn--primary:hover,
.btn--primary:focus-visible {
  border-color: var(--gold);
  box-shadow: 0 0 24px rgba(194, 164, 107, 0.2);
  outline: none;
}

.btn--ghost {
  color: var(--on-surface-variant);
  border: 1px solid transparent;
}

.btn--ghost:hover,
.btn--ghost:focus-visible {
  color: var(--gold);
  border-color: var(--glass-border);
  outline: none;
}

/* ============================================================
   SECTION HEADERS
   ============================================================ */

.section-head {
  max-width: 680px;
  margin-bottom: var(--space-lg);
}

.section-head--center {
  text-align: center;
  margin-left: auto;
  margin-right: auto;
}

.section-head__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: var(--space-sm);
}

.section-head__title {
  font-family: var(--font-display);
  /* Refined June 2026 — reduced ~18% for a more elegant, less
     headline-like scale across every section. */
  font-size: clamp(1.65rem, 4vw, 2.5rem);
  font-weight: 400;
  line-height: 1.18;
  color: var(--primary);
  margin-bottom: var(--space-sm);
}

.section-head__lede {
  font-size: 1rem;
  color: var(--on-surface-variant);
  line-height: 1.62;
  max-width: 58ch;
}

.section-head--center .section-head__lede {
  margin-left: auto;
  margin-right: auto;
}

/* ============================================================
   HERO · Compact character profile panel
   ----------------------------------------------------------------
   Layout refactor (visual hierarchy):
     1. Arcane Tree (background wallpaper) — primary focus
     2. Memory Crystals — secondary focus
     3. Welcome Message (temporary) — centred greeting
     4. Hero Profile — supporting; lives in the UPPER-LEFT of the
        first viewport so it doesn't compete with the tree, the
        crystals or the welcome message.

   The .hero <section> still anchors the first viewport (min-height
   100dvh) but its content is squeezed into a narrow upper-left
   column. The right side of the grid is intentionally empty so the
   tree breathes and the welcome message has room to materialize.

   Typography (font family / weight / style / colors / animations)
   is preserved; only sizes, spacing and alignment changed to make
   the panel feel compact and intentional.
   ============================================================ */

.hero {
  position: relative;
  z-index: var(--z-content);
  min-height: 100dvh;
  display: grid;
  /* Left column hosts the panel; right column stays empty so
     the tree + welcome can breathe. Widened to fit the enlarged
     portrait (~420px) and the original 52ch lede comfortably. */
  grid-template-columns: minmax(440px, 780px) 1fr;
  align-items: start;
  padding: clamp(4.5rem, 7vh, 6.5rem) var(--margin-safe) var(--space-md);
  text-align: left;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-md);
  max-width: 780px;
  width: 100%;
}

/* ONE RING + Portrait combined: the ring is the photo's frame.
   Slightly bumped beyond the original size at the user's request.
   All child elements — frame, glow, rune-ring, fire — scale
   proportionally via their percentage-based insets. */
.hero__portrait {
  position: relative;
  width: min(420px, 84vw);
  height: min(420px, 84vw);
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero__rune-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  animation: ring-rotate 60s linear infinite;
  pointer-events: none;
  /* Promote to its own GPU layer so the continuous rotation reuses a
     cached raster of the SVG/Tengwar text instead of re-rasterising the
     vector glyphs every frame (cause of the subtle ring stutter). */
  will-change: transform;
  transform: translateZ(0);
  backface-visibility: hidden;
}

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

.hero__rune-text {
  fill: var(--gold);
  font-family: var(--font-tengwar);
  /* Brighter living inscription — the ring's engraving now glows. */
  fill-opacity: 0.95;
  filter: drop-shadow(0 0 4px rgba(242, 200, 121, 0.6));
}

.hero__rune-fire {
  position: absolute;
  inset: 6%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(161, 62, 30, 0.17) 0%, rgba(194, 164, 107, 0.06) 35%, transparent 75%);
  animation: fire-pulse 3s ease-in-out infinite alternate;
  pointer-events: none;
  will-change: transform, opacity;
  transform: translateZ(0);
  backface-visibility: hidden;
}

@keyframes fire-pulse {
  from { opacity: 0.5; transform: scale(0.97); }
  to   { opacity: 1;   transform: scale(1.03); }
}

.hero__portrait-frame {
  position: relative;
  width: 50%;
  height: 50%;
  border-radius: 50%;
  overflow: hidden;
  /* Frame dialed back ~18% (size + golden glow) so the portrait
     yields focus to the living constellation behind it — the tree,
     not the face, is now the star of the scene. */
  border: 2px solid rgba(194, 164, 107, 0.48);
  box-shadow:
    0 0 0 1.5px rgba(229, 190, 174, 0.16),
    0 0 26px rgba(194, 164, 107, 0.12),
    inset 0 0 30px rgba(0, 0, 0, 0.6);
  z-index: 2;
}

.hero__portrait-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}

.hero__portrait-glow {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(229, 190, 174, 0.26) 0%, transparent 65%);
  z-index: 1;
  animation: portrait-glow 4s ease-in-out infinite alternate;
  pointer-events: none;
}

@keyframes portrait-glow {
  from { opacity: 0.6; }
  to   { opacity: 1; }
}

.hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-sm);
  width: 100%;
}

.hero__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.hero__name {
  font-family: var(--font-display);
  /* Dialed back further (June 2026 refinement, ~15%) so the name reads
     as an elegant title rather than a modern headline. */
  font-size: clamp(2.1rem, 6vw, 3.35rem);
  font-weight: 400;
  /* Tightened (June 2026): user asked for "Vaz" to sit closer to
     "Carlos". 0.92 collapses the visual gap to barely a hairline
     while still leaving room for the italic descenders + glow
     halo configured on the line-padding below. */
  line-height: 0.92;
  color: var(--primary);
}

.hero__name-first { display: block; }
.hero__name-last  { display: block; font-style: italic; color: var(--tertiary); }

.hero__tagline {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold);
}

/* ─────────────────────────────────────────────────────────────
   HERO LEDE · Tolkien-inspired forged-metal manifesto
   ─────────────────────────────────────────────────────────────
   The developer manifesto sits directly below the H1 "Carlos Vaz"
   and reads as an inscription on an old artefact of Middle-earth.
   Three stacked background layers compose the engraving:

     1 · LINEAR (metal sheen)
         dark metal → bronze → aged gold → bronze → dark metal
         a slow horizontal pan suggests polished light gliding
         across the metal surface.
     2 · RADIAL · ember-1  (warm dourado-ardente patch on the left)
         travels slowly RIGHT.
     3 · RADIAL · ember-2  (cooler laranja-magma patch on the right)
         travels slowly LEFT — counter-phase from ember-1, so the
         two heat sources are never aligned (no pulse).

   The base palette comes straight from the brief:
     #2B2017  metal escuro      ── shadow / base
     #6A4A2C  bronze antigo     ── midtone
     #C9A15F  ouro envelhecido  ── highlight
     #E08A2E  âmbar vulcânico   ── ember-1 core
     #D9651A  laranja magma     ── ember-2 core
     #A63B1E  vermelho incand.  ── ember-2 tail
     #F2C879  dourado ardente   ── inner light / hover

   Engraved appearance is reinforced by a hairline dark text-
   shadow underneath the warm halo, simulating the inked side of
   the chiselled letter. drop-shadow paints the heat halo OUTSIDE
   the clipped glyphs without bleeding into the rest of the page.
   ───────────────────────────────────────────────────────────── */
.hero__lede {
  position: relative;
  z-index: 1;
  font-family: 'Cinzel', 'Cormorant Garamond', Georgia, serif;
  font-size: 18px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.035em;             /* slightly wider — engraved feel */
  max-width: 56ch;
  margin: 0;
  background:
    /* Ember 1 · warm dourado-ardente patch, slides left → right */
    radial-gradient(ellipse 38% 140% at 20% 50%,
      rgba(242, 200, 121, 0.55) 0%,
      rgba(224, 138, 46, 0.28) 38%,
      transparent 72%),
    /* Ember 2 · cooler laranja-magma patch, slides right → left */
    radial-gradient(ellipse 34% 130% at 80% 50%,
      rgba(217, 101, 26, 0.45) 0%,
      rgba(166, 59, 30, 0.22) 42%,
      transparent 75%),
    /* Metal sheen · dark → bronze → aged-gold → bronze → dark */
    linear-gradient(96deg,
      #2B2017 0%,
      #6A4A2C 22%,
      #C9A15F 50%,
      #6A4A2C 78%,
      #2B2017 100%);
  background-size:
    260% 240%,
    240% 220%,
    220% 100%;
  background-position:
    0%   50%,
    100% 50%,
    0%   50%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* The warm halo — soft amber leaking from the inscription
     (text-shadow paints behind transparent text, so it becomes
     the heat that the metal radiates). The thin black layer at
     +0/+1px is the chisel shadow, anchoring the glyphs in place. */
  text-shadow:
    0 0 18px rgba(242, 200, 121, 0.12),
    0 0 32px rgba(217, 101, 26, 0.08),
    0 1px 0  rgba(0, 0, 0, 0.55);
  filter: drop-shadow(0 0 5px rgba(217, 101, 26, 0.10));
  animation: hero-lede-forge 11s ease-in-out infinite;
  will-change: background-position;
  transition: filter 0.6s ease, text-shadow 0.6s ease;
}

/* FORGE BREATH · the embers breathe across the engraving.
   Both radial gradients drift to their opposite end of the text
   while the metal sheen pans gently — the layers never realign,
   so the line never pulses; it just glows differently as you
   look at it. 11s cycle keeps the motion ambient (8–12s window
   prescribed by the brief). */
@keyframes hero-lede-forge {
  0%, 100% {
    background-position:
      0%   50%,
      100% 50%,
      0%   50%;
  }
  50% {
    background-position:
      100% 50%,
      0%   50%,
      100% 50%;
  }
}

/* HOVER · the inscription warms gently — no scale, no particles,
   no explosion. Halo widens and a touch of dourado-ardente
   strengthens through the drop-shadow. */
.hero__lede:hover {
  filter: drop-shadow(0 0 11px rgba(242, 200, 121, 0.24));
  text-shadow:
    0 0 22px rgba(242, 200, 121, 0.22),
    0 0 38px rgba(224, 138, 46, 0.14),
    0 1px 0  rgba(0, 0, 0, 0.55);
}

/* Honour the user's reduced-motion preference: freeze the embers
   at the middle of the cycle so the inscription stays readable
   and warm, but never moves. */
@media (prefers-reduced-motion: reduce) {
  .hero__lede {
    animation: none;
    background-position:
      50% 50%,
      50% 50%,
      50% 50%;
  }
}

/* HERO ACTIONS · two in-page CTAs that bridge the visitor into
   Act II ("Explorar Árvore" → #knowledge) and the memory crystals
   ("Ver Cristais" → #memories). They are deliberately not card-
   shaped — they read as ritual invitations rather than UI buttons:
     · primary  · gold-bronze ink on a parchment wash, hairline
                  bronze border, slight inner glow that brightens
                  on hover (the "open the gate" feel)
     · ghost    · pure outline in muted gold, fills softly on hover
   Both share the same hairline geometry so the pair feels like a
   matched set carved from the same metal. */
.hero__actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.65rem 0.85rem;
  margin-top: 1.25rem;
  align-items: center;
  /* CTAs stay visible at all times — they must not participate in the
     delayed act1-fade-up (3.65s) which snaps opacity to 0 when the
     keyframe starts while the visitor is still scrolling the hero. */
  opacity: 1;
  transform: none;
}
.hero__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.62rem 1.1rem;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color 0.45s ease,
    border-color 0.45s ease,
    background 0.45s ease,
    box-shadow 0.45s ease,
    transform 0.35s var(--ease-out, cubic-bezier(.16,1,.3,1));
  isolation: isolate;
}
.hero__cta:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px rgba(255, 231, 160, 0.55),
    0 0 24px rgba(255, 231, 160, 0.32);
}
.hero__cta-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: currentColor;
  opacity: 0.92;
  transition: transform 0.45s var(--ease-out, cubic-bezier(.16,1,.3,1)), opacity 0.35s ease;
}
.hero__cta-label { position: relative; }

/* PRIMARY — the headline action. Reads like an inked seal: a warm
   parchment gradient with a hairline antique-gold ring and a
   whisper of inner glow. On hover it brightens (without becoming
   garish) and rises 1px to suggest the seal lifting off the page. */
.hero__cta--primary {
  color: #2A1808;
  /* Dominant headline action — still leads, but refined (June 2026):
     slimmer footprint and a quieter aura so it reads like an inked seal,
     not an oversized modern button. */
  padding: 0.66rem 1.4rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  background: linear-gradient(160deg,
    rgba(244, 221, 192, 0.96) 0%,
    rgba(229, 190, 174, 0.92) 50%,
    rgba(194, 164, 107, 0.92) 100%);
  border: 1px solid rgba(120, 80, 40, 0.55);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.45),
    inset 0 -2px 8px rgba(120, 80, 40, 0.18),
    0 6px 18px rgba(0, 0, 0, 0.36),
    0 0 14px rgba(255, 231, 160, 0.12);
}
/* Breathing attention halo behind the primary CTA. */
.hero__cta--primary::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  z-index: -1;
  background: radial-gradient(ellipse at center, rgba(255, 231, 160, 0.4), transparent 70%);
  opacity: 0;
  animation: hero-cta-breathe 3.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes hero-cta-breathe {
  0%, 100% { opacity: 0.16; transform: scale(0.98); }
  50%      { opacity: 0.4;  transform: scale(1.04); }
}
.hero__cta--primary:hover {
  transform: translateY(-1px);
  background: linear-gradient(160deg,
    rgba(255, 240, 210, 0.98) 0%,
    rgba(244, 221, 192, 0.95) 50%,
    rgba(216, 174, 99, 0.95) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.55),
    inset 0 -2px 8px rgba(120, 80, 40, 0.18),
    0 9px 24px rgba(0, 0, 0, 0.42),
    0 0 22px rgba(255, 231, 160, 0.28);
}
.hero__cta--primary:hover .hero__cta-icon {
  transform: translateY(-1px);
}

/* GHOST — the secondary, quieter invitation. Pure outline in
   muted gold over the live wallpaper, with a soft glass fill that
   warms on hover. Stays legible against the busy background
   without ever feeling like a button. */
.hero__cta--ghost {
  /* Secondary CTA — stays subordinate to the gold seal (smaller, lighter
     type), but now carries a cool CRYSTALLINE glow so it unmistakably
     reads as a button. The aura is teal/cyan — the colour of the Memory
     Crystals — to set it apart from the warm-gold primary while it gently
     breathes (see ::after). */
  color: #CFEFEA;
  padding: 0.52rem 0.95rem;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  opacity: 0.96;
  background: linear-gradient(160deg,
    rgba(28, 54, 60, 0.30),
    rgba(14, 26, 34, 0.22));
  border: 1px solid rgba(150, 226, 224, 0.42);
  box-shadow:
    inset 0 0 12px rgba(150, 226, 224, 0.12),
    0 2px 10px rgba(0, 0, 0, 0.28);
}
/* Breathing crystalline aura — soft, subordinate to the primary's
   warmer/larger glow, just enough to signal interactivity. */
.hero__cta--ghost::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  pointer-events: none;
  z-index: -1;
  box-shadow:
    0 0 12px rgba(127, 224, 216, 0.20),
    inset 0 0 9px rgba(127, 224, 216, 0.12);
  animation: hero-crystal-breathe 3.8s ease-in-out infinite;
}
.hero__cta--ghost .hero__cta-icon {
  color: #9FECE4;
  filter: drop-shadow(0 0 4px rgba(127, 224, 216, 0.55));
}
.hero__cta--ghost:hover {
  transform: translateY(-1px);
  opacity: 1;
  color: #ECFFFB;
  border-color: rgba(176, 244, 238, 0.7);
  background: linear-gradient(160deg,
    rgba(32, 64, 70, 0.50),
    rgba(16, 30, 38, 0.42));
  box-shadow:
    inset 0 0 16px rgba(150, 226, 224, 0.20),
    0 6px 18px rgba(0, 0, 0, 0.34),
    0 0 22px rgba(127, 224, 216, 0.32);
}
.hero__cta--ghost:hover .hero__cta-icon {
  transform: rotate(-3deg) scale(1.06);
  filter: drop-shadow(0 0 7px rgba(150, 240, 232, 0.85));
}
@keyframes hero-crystal-breathe {
  0%, 100% {
    opacity: 0.5;
    box-shadow:
      0 0 9px rgba(127, 224, 216, 0.15),
      inset 0 0 7px rgba(127, 224, 216, 0.10);
  }
  50% {
    opacity: 0.9;
    box-shadow:
      0 0 20px rgba(127, 224, 216, 0.34),
      inset 0 0 12px rgba(127, 224, 216, 0.17);
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero__cta--ghost::after { animation: none; opacity: 0.7; }
}

/* HERO ROLE · plain-language professional line under the poetic lede.
   Quiet, legible, never competing with the gold tagline — its job is
   pure clarity for a recruiter scanning the fold. */
.hero__role {
  margin-top: 0.85rem;
  max-width: 46ch;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 400;
  line-height: 1.62;
  color: var(--on-surface-variant);
  text-wrap: pretty;
}
html[data-theme="light"] .hero__role { color: #5b4a33; }

/* ════════════════════════════════════════════════════════════════════
   HERO ROLE · "Ring-inscription" treatment (Lord of the Rings core)
   --------------------------------------------------------------------
   The professional subtitle is framed like the One Ring's fiery
   inscription: a warm molten-gold gradient that slowly drifts, an
   ember glow that breathes, and an elven flourish rule above it.
   The text stays fully legible — the gilding is subtle, not neon.
   ════════════════════════════════════════════════════════════════════ */
.hero__role--inscription {
  position: relative;
  margin-top: 1.2rem;
  padding-top: 1.05rem;
  letter-spacing: 0.012em;
  /* Molten-gold inscription gradient (Mordor firelight → elven gold) */
  background-image: linear-gradient(
    100deg,
    #b9893f 0%,
    #e9c87e 22%,
    #fff0c2 38%,
    #e9c87e 52%,
    #c79a4e 70%,
    #f0d693 86%,
    #c79a4e 100%
  );
  background-size: 220% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  text-shadow: 0 0 18px rgba(228, 184, 102, 0.16);
  animation: hero-ring-inscription 13s ease-in-out infinite;
}
/* Elven flourish rule above the inscription — a thin gold line with a
   central ✧, evoking a Rivendell engraving. */
.hero__role--inscription::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: clamp(120px, 40%, 230px);
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(228, 184, 102, 0.55) 18%,
    rgba(255, 240, 194, 0.85) 50%,
    rgba(228, 184, 102, 0.55) 82%,
    transparent 100%);
}
.hero__role--inscription::after {
  content: "\2727";   /* ✧ — elven star mark */
  position: absolute;
  top: -0.62rem;
  left: clamp(58px, 20%, 114px);
  transform: translateX(-50%);
  font-size: 0.74rem;
  color: #f0d693;
  text-shadow: 0 0 10px rgba(228, 184, 102, 0.6);
  -webkit-text-fill-color: #f0d693;
  animation: hero-ring-twinkle 5.5s ease-in-out infinite;
}
@keyframes hero-ring-inscription {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
@keyframes hero-ring-twinkle {
  0%, 100% { opacity: 0.65; transform: translateX(-50%) scale(1); }
  50%      { opacity: 1;    transform: translateX(-50%) scale(1.18); }
}
/* Light theme — deeper bronze so the gilding stays readable on parchment */
html[data-theme="light"] .hero__role--inscription {
  background-image: linear-gradient(
    100deg,
    #8a5a1f 0%,
    #b8842f 26%,
    #d9a94e 44%,
    #b8842f 64%,
    #9a6a24 100%
  );
  text-shadow: none;
}
@media (prefers-reduced-motion: reduce) {
  .hero__role--inscription { animation: none; background-position: 50% 50%; }
  .hero__role--inscription::after { animation: none; }
}

/* TERTIARY CTA · understated text link that still opens the living
   tree. No fill, no ring — just an underline that warms on hover, so
   it stays subordinate to the gold seal + crystalline ghost. */
.hero__cta--text {
  padding: 0.5rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--gold-aged, #c2a46b);
  background: none;
  border: 1px solid transparent;
}
.hero__cta--text .hero__cta-label {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size 0.4s var(--ease-out, cubic-bezier(.16,1,.3,1));
}
.hero__cta--text:hover { color: var(--gold-burning, #f2c879); }
.hero__cta--text:hover .hero__cta-label { background-size: 100% 1px; }
.hero__cta--text:hover .hero__cta-icon { transform: translateY(-1px) rotate(-2deg); }
html[data-theme="light"] .hero__cta--text { color: #8a5a1f; }
html[data-theme="light"] .hero__cta--text:hover { color: #6b3f18; }

/* NARRATIVE CAPTION STRIP · the three-act chapter list anchored
   to the left edge of the viewport. The list is always visible
   (chapters are part of the experience), but only the active act
   is fully lit — past and upcoming acts sit quietly in the wings.
   On medium screens the strip hides itself entirely to avoid
   competing with the body content. */
.narrative {
  position: fixed;
  top: 50%;
  left: 1.5rem;
  transform: translateY(-50%);
  z-index: 50;
  pointer-events: none;
  /* Match the body fade-in: invisible until SkillTree paints its
     first frame. Effects.js doesn't gate this — instead we trust
     the parent body fade. */
  opacity: 0;
  animation: narrative-fade-in 1.4s ease 0.6s forwards;
}
@keyframes narrative-fade-in {
  to { opacity: 1; }
}
.narrative__list {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}
/* Subtle vertical thread connecting the three roman numerals.
   It's the spine of the journey — a hairline so the chapter
   markers feel like beads on a single arcane line. */
.narrative__list::before {
  content: "";
  position: absolute;
  top: 0.45rem;
  bottom: 0.45rem;
  left: 0.55rem;
  width: 1px;
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(229, 190, 174, 0.25) 12%,
    rgba(229, 190, 174, 0.42) 50%,
    rgba(229, 190, 174, 0.25) 88%,
    transparent 100%);
  pointer-events: none;
}
.narrative__act {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  opacity: 0.36;
  transform: translateX(-2px);
  transition:
    opacity 0.7s ease,
    transform 0.7s var(--ease-out, cubic-bezier(.16,1,.3,1)),
    filter 0.6s ease;
  filter: saturate(0.7) brightness(0.85);
  position: relative;
}
.narrative__roman {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  font-family: "Cinzel", "Libre Caslon Text", serif;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--gold);
  background: rgba(9, 14, 22, 0.65);
  border: 1px solid rgba(194, 164, 107, 0.35);
  border-radius: 50%;
  text-shadow: 0 0 8px rgba(255, 231, 160, 0.18);
  transition:
    color 0.6s ease,
    background 0.6s ease,
    border-color 0.6s ease,
    box-shadow 0.6s ease;
  flex-shrink: 0;
}
.narrative__copy {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  /* The labels collapse to zero width when their act isn't active.
     Past/upcoming acts show only the roman numeral, which keeps the
     strip narrow and reads like a quiet table of contents. */
  max-width: 0;
  overflow: hidden;
  transition: max-width 0.7s var(--ease-out, cubic-bezier(.16,1,.3,1));
}
.narrative__label {
  font-family: "Cinzel", "Libre Caslon Text", serif;
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--primary);
  white-space: nowrap;
}
.narrative__hint {
  font-family: var(--font-body);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  color: var(--on-surface-muted);
  white-space: nowrap;
  opacity: 0.85;
}

/* ACTIVE STATE · driven by html[data-narrative-act="X"].
   Each rule lights up exactly one chapter marker — the others
   stay visible but quietly recede. The text panel expands so the
   chapter title slides into view from the spine. */
html[data-narrative-act="1"] .narrative__act[data-act="1"],
html[data-narrative-act="2"] .narrative__act[data-act="2"],
html[data-narrative-act="3"] .narrative__act[data-act="3"],
html[data-narrative-act="4"] .narrative__act[data-act="4"],
html[data-narrative-act="5"] .narrative__act[data-act="5"] {
  opacity: 1;
  transform: translateX(0);
  filter: saturate(1) brightness(1);
}
html[data-narrative-act="1"] .narrative__act[data-act="1"] .narrative__roman,
html[data-narrative-act="2"] .narrative__act[data-act="2"] .narrative__roman,
html[data-narrative-act="3"] .narrative__act[data-act="3"] .narrative__roman,
html[data-narrative-act="4"] .narrative__act[data-act="4"] .narrative__roman,
html[data-narrative-act="5"] .narrative__act[data-act="5"] .narrative__roman {
  color: #FFE7A0;
  background: linear-gradient(160deg, rgba(60, 30, 8, 0.95), rgba(20, 10, 4, 0.95));
  border-color: rgba(255, 231, 160, 0.7);
  box-shadow:
    inset 0 0 8px rgba(255, 231, 160, 0.25),
    0 0 22px rgba(255, 231, 160, 0.35),
    0 0 44px rgba(155, 124, 214, 0.18);
}
html[data-narrative-act="1"] .narrative__act[data-act="1"] .narrative__copy,
html[data-narrative-act="2"] .narrative__act[data-act="2"] .narrative__copy,
html[data-narrative-act="3"] .narrative__act[data-act="3"] .narrative__copy,
html[data-narrative-act="4"] .narrative__act[data-act="4"] .narrative__copy,
html[data-narrative-act="5"] .narrative__act[data-act="5"] .narrative__copy {
  max-width: 230px;
}

/* On smaller screens the chapter spine would crowd the content —
   hide it entirely. The page still works without the visual
   chapter marks because the narrative still drives the wallpaper
   and the constellation reveal. */
@media (max-width: 1100px) {
  .narrative { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .narrative,
  .narrative__act,
  .narrative__copy {
    transition: none !important;
    animation: none !important;
  }
  .narrative { opacity: 1; }
}

/* ============================================================
   SKILL TREE WALLPAPER · Body-wide PoE-style tree
   ============================================================ */

/* The tree fills the entire viewport, behind ALL content. */
.tree-wall {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
}

.tree-wall__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.tree-wall__canvas--bg { z-index: 1; }
.tree-wall__canvas--fg { z-index: 2; }

/* Memory Crystals share the SAME fixed plane as the skill tree.
   No separate stage, no rectangular field — the crystals float
   directly over the tree wallpaper as siblings of its canvases. */
.tree-wall__crystal-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 3;
  pointer-events: none;
  touch-action: none;
  background: transparent;
  border: 0;
  outline: 0;
}
.tree-wall__crystal-overlay {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  overflow: visible;
  background: transparent;
}

/* Bring background atmospherics behind the tree */
.bg-vault { z-index: 0; }

/* All real content sits ABOVE the tree visually, but the tree captures
   pointer events at the window level and skips over interactive UI. */
.nav { z-index: 100; }
main { position: relative; z-index: 10; }
.footer { z-index: 10; }
.merlin { z-index: 200; }

/* Legacy atmospheric layer: subtle only (tree canvas owns the sky) */
.bg-vault { opacity: 0.35; }

/* Make content sections semi-transparent so the tree shows through */
.hero,
.tree-vault,
.memories,
.portal {
  background: transparent;
}

/* Hero gets a soft vignette so content stays readable over the tree.
   Anchored at the upper-left to match the compact panel position;
   sized generously to cover the full-scale portrait + text. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(ellipse 62% 65% at 24% 40%,
    rgba(9, 22, 9, 0.80) 0%,
    rgba(9, 22, 9, 0.42) 55%,
    transparent 90%);
  pointer-events: none;
}

/* Floating tooltip near hovered node */
.tree-tooltip {
  position: fixed;
  z-index: 250;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.55rem 0.85rem;
  background: rgba(9, 22, 9, 0.94);
  border: 1px solid var(--gold-dim);
  border-radius: var(--radius-sm);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  opacity: 0;
  transform: translate(-50%, calc(-100% - 18px));
  transition: opacity 0.15s var(--ease-out);
  white-space: nowrap;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), 0 0 24px rgba(194, 164, 107, 0.12);
}

.tree-tooltip.is-visible { opacity: 1; }

.tree-tooltip__title {
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--primary);
}

.tree-tooltip__meta {
  font-family: var(--font-mono);
  font-size: 0.55rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
}

/* The tree-vault section is now just a header + HUD over the wallpaper */
.tree-vault {
  position: relative;
  min-height: 100dvh;
  width: 100%;
  padding: var(--space-xl) var(--margin-safe) var(--space-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tree-vault__header {
  position: relative;
  z-index: 3;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
  padding: 1rem 1.25rem;
  /* Marginalia only — no glass rectangle over the skill-tree wallpaper
     (Visual Boundary Audit, June 2026). Legibility via text-shadow. */
  background: transparent;
  border: none;
  border-radius: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
.tree-vault__title,
.tree-vault__lede {
  text-shadow:
    0 0 28px rgba(9, 22, 9, 0.85),
    0 1px 2px rgba(0, 0, 0, 0.75);
}

.tree-vault__title {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 4vw, 2.5rem);
  font-weight: 400;
  line-height: 1.15;
  color: var(--primary);
  margin-bottom: var(--space-sm);
}

.tree-vault__lede {
  font-size: 1rem;
  color: var(--on-surface-variant);
  line-height: 1.65;
  max-width: 58ch;
  margin: 0 auto;
  letter-spacing: 0.02em;
}

/* ============================================================
   CRAFT CONSTELLATION
   ------------------------------------------------------------
   Sits between the tree-vault header and the skill-tree HUD.
   A six-pointed constellation of crystal nodes orbits a central
   "core" (the architect). Each crystal lights up its connection
   line and pushes a poetic description into the plate below.

   Layering:
     .craft__stage         · the constellation viewport
       .craft__field       · soft starfield (radial gradient)
       .craft__lines       · SVG layer for the 6 connecting lines
       .craft__core        · the central node ("VOCÊ")
       .craft__node[]      · 6 satellite crystals
     .craft__plate         · description panel below the stage
     .craft__epilogue      · closing tagline

   The HTML sits inside #knowledge so the page wallpaper canvas
   (the actual Skill Tree behind everything) shows through the
   gaps in the constellation — making the section feel embedded
   in the same cosmic substrate.
============================================================ */
.craft {
  --craft-fg:          #E5BEAE;
  --craft-fg-bright:   #F4DDC0;
  --craft-line:        rgba(229, 190, 174, 0.42);
  --craft-line-hot:    #FFE7A0;
  --craft-cyan:        #5BC0EB;
  --craft-violet:      #9B7CD6;
  --craft-deep:        #0B1320;
  --craft-glass:       rgba(12, 18, 28, 0.42);
  --craft-glass-edge:  rgba(229, 190, 174, 0.28);

  position: relative;
  z-index: 4;
  margin: 3.4rem auto 4.5rem;
  max-width: 1180px;
  padding: 0 1.25rem;
  isolation: isolate;

  /* NARRATIVE REVEAL · the constellation does NOT exist on Act I.
     As the user enters #knowledge, narrative.js animates
     --craft-reveal from 0 → 1 (eased), and three properties on the
     section interpolate in lockstep:
       · opacity      0 → 1
       · translateY  +28px → 0
       · blur         6px → 0
     We deliberately don't put a CSS `transition` on these because
     the JS already smooths the input — adding a transition would
     introduce lag against the scroll wheel. */
  opacity: var(--craft-reveal, 1);
  transform: translateY(calc((1 - var(--craft-reveal, 1)) * 28px));
  filter: blur(calc((1 - var(--craft-reveal, 1)) * 6px));
}

/* ── HEADER ─────────────────────────────────────────────────────
   The header avoids any solid card / banner treatment. Instead it
   floats over a soft, drifting luminosity mask (::before) — a
   blurred warm-violet glow that makes the title read with weight
   against the live skill-tree wallpaper without ever boxing it in.
   The mask breathes via `craft-title-breath`, so the title sits
   over an atmosphere that's never frozen. */
.craft__head {
  position: relative;
  text-align: center;
  max-width: 740px;
  margin: 0 auto 2.2rem;
  isolation: isolate;
}
.craft__head::before {
  content: "";
  position: absolute;
  inset: -28% -22% -42% -22%;
  background:
    radial-gradient(ellipse at 50% 45%,
      rgba(244, 221, 192, 0.16) 0%,
      rgba(200, 164, 221, 0.10) 28%,
      rgba(91, 192, 235, 0.06) 52%,
      transparent 72%);
  filter: blur(38px);
  z-index: -1;
  pointer-events: none;
  animation: craft-title-breath 11s ease-in-out infinite;
}
/* The lede + sub gain a whisper of inner glow so they survive
   against the busy wallpaper without a hard backdrop. */
.craft__title,
.craft__sub {
  position: relative;
}
.craft__eyebrow {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 0.7rem;
  letter-spacing: 0.42em;
  color: var(--craft-fg);
  opacity: 0.72;
  margin: 0 0 0.85rem;
  text-transform: uppercase;
}
.craft__title {
  font-family: "Cinzel", "Cormorant Garamond", serif;
  font-size: clamp(1.55rem, 2.55vw, 2.15rem);
  line-height: 1.22;
  font-weight: 500;
  margin: 0 0 0.95rem;
  background: linear-gradient(135deg,
    #F4DDC0 0%,
    #E5BEAE 35%,
    #C8A4DD 65%,
    #5BC0EB 100%);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  text-shadow: 0 0 32px rgba(229, 190, 174, 0.18);
}
.craft__sub {
  font-family: "Cinzel", "Cormorant Garamond", serif;
  font-weight: 400;
  font-size: clamp(0.92rem, 1.05vw, 1.05rem);
  letter-spacing: 0.08em;
  line-height: 1.55;
  color: var(--on-surface-variant);
  margin: 0;
  opacity: 0.86;
}

/* ── STAGE · the constellation viewport ─────────────────────── */
.craft__stage {
  position: relative;
  width: 100%;
  max-width: 820px;
  margin: 0 auto;
  aspect-ratio: 800 / 540;
  /* The stage hosts absolutely-positioned crystals on top of an
     SVG line layer. Both share the same 800×540 logical space. */
  --stage-pad: 0;
}

/* Decorative starfield behind the constellation. Uses layered
   radial gradients to suggest cosmic dust without burdening the
   page with another canvas. */
.craft__field {
  position: absolute;
  inset: -8% -6%;
  pointer-events: none;
  background:
    radial-gradient(circle at 22% 30%, rgba(91, 192, 235, 0.10) 0%, transparent 38%),
    radial-gradient(circle at 78% 70%, rgba(155, 124, 214, 0.10) 0%, transparent 42%),
    radial-gradient(circle at 50% 50%, rgba(229, 190, 174, 0.06) 0%, transparent 55%);
  filter: blur(14px);
  opacity: 0.85;
  z-index: 0;
}
.craft__field::before {
  /* Sparse star motes — two layers of tiny radial dots at different
     scales so the field feels parallaxed when the page scrolls. */
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle, rgba(244, 221, 192, 0.7) 0%, transparent 60%),
    radial-gradient(circle, rgba(91, 192, 235, 0.55) 0%, transparent 60%);
  background-size: 3px 3px, 4px 4px;
  background-position: 0 0, 30px 40px;
  opacity: 0.18;
  mix-blend-mode: screen;
  -webkit-mask-image: radial-gradient(ellipse at center, black 40%, transparent 75%);
  mask-image: radial-gradient(ellipse at center, black 40%, transparent 75%);
}

/* ── CONNECTION LINES (SVG) ─────────────────────────────────── */
.craft__lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
  overflow: visible;
}
.craft__line {
  transition:
    stroke 0.45s ease,
    stroke-opacity 0.45s ease,
    stroke-width 0.45s ease,
    filter 0.45s ease;
  filter: drop-shadow(0 0 1px rgba(229, 190, 174, 0.3));
}
/* Resting noise reduction — the dashed connections used to compete
   with the crystals. Primary axes stay readable, secondary axes
   (theme · identity · ambience) recede so the constellation breathes. */
.craft__stage:not([data-active]) .craft__line { stroke-opacity: 0.45; }
.craft__stage:not([data-active]) .craft__line[data-key="theme"],
.craft__stage:not([data-active]) .craft__line[data-key="identity"],
.craft__stage:not([data-active]) .craft__line[data-key="ambience"] {
  stroke-opacity: 0.22;
}
/* Perpetual energy flow — the dashed connections crawl outward from
   the core toward each crystal, so the constellation always reads as
   "powered from the centre". Cheap: a single dashoffset loop on six
   thin lines. The dasharray period is 8 (2 6), so an 8px shift loops
   seamlessly. Stops automatically on the active (solid) line. */
.craft__line { animation: craft-line-flow 2.6s linear infinite; }
@keyframes craft-line-flow {
  to { stroke-dashoffset: -8; }
}
/* When the stage marks a key active, brighten that line and dull
   the others slightly to draw the eye along the highlighted axis. */
.craft__stage[data-active] .craft__line {
  stroke-opacity: 0.18;
}
.craft__stage[data-active="story"]     .craft__line[data-key="story"],
.craft__stage[data-active="ux"]        .craft__line[data-key="ux"],
.craft__stage[data-active="direction"] .craft__line[data-key="direction"],
.craft__stage[data-active="theme"]     .craft__line[data-key="theme"],
.craft__stage[data-active="identity"]  .craft__line[data-key="identity"],
.craft__stage[data-active="ambience"]  .craft__line[data-key="ambience"] {
  stroke: var(--craft-line-hot);
  stroke-opacity: 1;
  stroke-width: 1.6;
  stroke-dasharray: 0;
  filter:
    drop-shadow(0 0 4px var(--craft-line-hot))
    drop-shadow(0 0 10px rgba(255, 231, 160, 0.42));
}

/* ── CENTRAL CORE ───────────────────────────────────────────────
   The architect ("VOCÊ"). Sits at the gravitational center of the
   constellation and is intentionally the largest, most luminous
   crystal so the hierarchy reads instantly:
       CORE (anchor)  >  PRIMARY satellites  >  SECONDARY satellites
   No text label is needed to communicate the priority — scale and
   glow do the work. */
.craft__core {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 196px;
  height: 196px;
  display: grid;
  place-items: center;
  z-index: 3;
  pointer-events: none;
  color: var(--craft-fg-bright);
}
.craft__core-aura {
  position: absolute;
  inset: -52%;
  border-radius: 50%;
  /* Brighter, more arcane-purple bloom — the Núcleo Arcano now reads
     as the luminous heart of the constellation. */
  background: radial-gradient(circle,
    rgba(244, 221, 192, 0.42) 0%,
    rgba(168, 85, 247, 0.34) 30%,
    rgba(139, 92, 246, 0.20) 50%,
    rgba(91, 192, 235, 0.10) 66%,
    transparent 78%);
  filter: blur(20px);
  animation: craft-aura 6.5s ease-in-out infinite;
  z-index: -1;
}
.craft__core-ring {
  position: absolute;
  inset: 8%;
  border-radius: 50%;
  border: 1px solid rgba(229, 190, 174, 0.45);
  animation: craft-ring 9s linear infinite;
}
/* Orbital mote riding each ring — because the ring rotates, the dot
   orbits the core like a captured spark of energy. */
.craft__core-ring::after {
  content: "";
  position: absolute;
  top: -3.5px;
  left: 50%;
  width: 7px;
  height: 7px;
  margin-left: -3.5px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, var(--arcane-bright) 55%, transparent 75%);
  box-shadow:
    0 0 8px var(--arcane-bright),
    0 0 16px rgba(168, 85, 247, 0.7);
}
.craft__core-ring--alt {
  inset: 18%;
  border-color: rgba(168, 85, 247, 0.45);
  border-style: dashed;
  animation:
    craft-ring 14s linear infinite reverse,
    craft-aura 5s ease-in-out infinite;
}
.craft__core-ring--alt::after {
  width: 5px;
  height: 5px;
  margin-left: -2.5px;
  top: -2.5px;
  background: radial-gradient(circle, #fff 0%, var(--craft-cyan, #5BC0EB) 55%, transparent 75%);
  box-shadow:
    0 0 6px var(--craft-cyan, #5BC0EB),
    0 0 12px rgba(91, 192, 235, 0.7);
}

/* Slow ring of orbital runes — the artefact's inscription, turning
   on its own axis between the rings and the central crystal. */
.craft__core-runes {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  color: var(--arcane-bright);
  animation: craft-ring 46s linear infinite;
  will-change: transform;
}
.craft__core-rune-text {
  fill: currentColor;
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  letter-spacing: 2.5px;
  opacity: 0.55;
  filter: drop-shadow(0 0 4px rgba(168, 85, 247, 0.65));
}
.craft__core-mark {
  position: relative;
  z-index: 1;
  width: 106px;
  height: 106px;
  display: grid;
  place-items: center;
  border-radius: 24%;
  background:
    radial-gradient(circle at 30% 28%, rgba(244, 221, 192, 0.22), transparent 65%),
    radial-gradient(circle at 70% 75%, rgba(168, 85, 247, 0.30), transparent 65%),
    linear-gradient(160deg, rgba(26, 16, 40, 0.80), rgba(8, 12, 22, 0.92));
  border: 1px solid rgba(229, 190, 174, 0.5);
  box-shadow:
    inset 0 0 26px rgba(244, 221, 192, 0.22),
    0 0 40px rgba(139, 92, 246, 0.42),
    0 0 70px rgba(139, 92, 246, 0.20),
    0 0 0 1px rgba(255, 231, 160, 0.16);
  /* float (position) + pulse (glow heartbeat) run together. */
  animation:
    craft-core-float 7s ease-in-out infinite,
    craft-core-pulse 4.5s ease-in-out infinite;
}
/* The central crystal turns slowly on its own axis — the living
   heart of the cosmology. */
.craft__core-mark svg {
  color: var(--craft-fg-bright);
  animation: craft-crystal-spin 64s linear infinite;
}
@keyframes craft-core-pulse {
  0%, 100% {
    box-shadow:
      inset 0 0 26px rgba(244, 221, 192, 0.22),
      0 0 40px rgba(139, 92, 246, 0.42),
      0 0 70px rgba(139, 92, 246, 0.20),
      0 0 0 1px rgba(255, 231, 160, 0.16);
  }
  50% {
    box-shadow:
      inset 0 0 32px rgba(244, 221, 192, 0.32),
      0 0 56px rgba(168, 85, 247, 0.62),
      0 0 96px rgba(139, 92, 246, 0.34),
      0 0 0 1px rgba(255, 231, 160, 0.28);
  }
}
.craft__core-label {
  position: absolute;
  bottom: -1.4rem;
  left: 50%;
  transform: translateX(-50%);
  font-family: "JetBrains Mono", monospace;
  font-size: 0.66rem;
  letter-spacing: 0.5em;
  color: var(--craft-fg);
  margin: 0;
  text-transform: uppercase;
  text-shadow: 0 0 12px rgba(255, 231, 160, 0.35);
}

/* ── SATELLITE NODES ────────────────────────────────────────── */
.craft__node {
  position: absolute;
  width: 138px;
  display: grid;
  place-items: center;
  gap: 0.45rem;
  transform: translate(-50%, -50%);
  background: transparent;
  border: 0;
  padding: 0;
  color: var(--craft-fg-bright);
  cursor: pointer;
  z-index: 4;
  font-family: inherit;
  /* Each crystal floats with a unique phase so the constellation
     breathes rather than pulsing in unison. */
  animation: craft-node-float 7s ease-in-out infinite;
  transition: transform 0.5s var(--ease-out, cubic-bezier(.42,0,.58,1)), filter 0.4s ease;
}
.craft__node[data-pos="n"]  { top: 11%; left: 50%; }
.craft__node[data-pos="ne"] { top: 31%; left: 73.5%; animation-delay: -1.1s; }
.craft__node[data-pos="se"] { top: 69%; left: 73.5%; animation-delay: -2.2s; }
.craft__node[data-pos="s"]  { top: 89%; left: 50%;   animation-delay: -3.3s; }
.craft__node[data-pos="sw"] { top: 69%; left: 26.5%; animation-delay: -4.4s; }
.craft__node[data-pos="nw"] { top: 31%; left: 26.5%; animation-delay: -5.5s; }

.craft__node-aura {
  position: absolute;
  inset: -20% -20% 30% -20%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(244, 221, 192, 0.35) 0%,
    rgba(155, 124, 214, 0.18) 35%,
    transparent 70%);
  filter: blur(12px);
  opacity: 0.55;
  transition: opacity 0.45s ease, transform 0.45s ease;
  pointer-events: none;
  z-index: -1;
}
.craft__node-crystal {
  position: relative;
  /* Default size — overridden per tier below. Kept as a sensible
     fallback in case a future node ships without a data-tier. */
  width: 78px;
  height: 78px;
  display: grid;
  place-items: center;
  border-radius: 22%;
  background:
    radial-gradient(circle at 32% 28%, rgba(244, 221, 192, 0.16), transparent 60%),
    radial-gradient(circle at 70% 70%, rgba(91, 192, 235, 0.18), transparent 60%),
    linear-gradient(160deg, rgba(18, 14, 26, 0.82), rgba(6, 10, 18, 0.92));
  border: 1px solid rgba(229, 190, 174, 0.35);
  box-shadow:
    inset 0 0 16px rgba(244, 221, 192, 0.12),
    0 0 0 1px rgba(255, 231, 160, 0.08),
    0 0 24px rgba(155, 124, 214, 0.18);
  color: var(--craft-fg-bright);
  transition:
    transform 0.4s var(--ease-out, cubic-bezier(.42,0,.58,1)),
    box-shadow 0.4s ease,
    border-color 0.4s ease,
    color 0.4s ease;
}

/* ── TIER · visual hierarchy between the three primary pillars
   (Storytelling, UX, Art Direction) and the three secondary ones
   (Theme, Identity, Ambience). Primary crystals read with more
   weight; secondaries feel like quieter satellites without ever
   losing presence. The aura scales follow so the glow stays
   proportional to the body. */
.craft__node[data-tier="primary"] .craft__node-crystal {
  width: 88px;
  height: 88px;
  /* Higher contrast so the three core domains clearly outrank the
     secondary satellites and read as the pillars of the craft. */
  border-color: rgba(244, 221, 192, 0.62);
  background:
    radial-gradient(circle at 32% 28%, rgba(244, 221, 192, 0.24), transparent 60%),
    radial-gradient(circle at 70% 70%, rgba(168, 85, 247, 0.24), transparent 60%),
    linear-gradient(160deg, rgba(22, 16, 32, 0.86), rgba(6, 10, 18, 0.94));
  box-shadow:
    inset 0 0 22px rgba(244, 221, 192, 0.24),
    0 0 0 1px rgba(255, 231, 160, 0.2),
    0 0 38px rgba(168, 85, 247, 0.3);
}
.craft__node[data-tier="primary"] .craft__node-aura {
  inset: -28% -28% 26% -28%;
  opacity: 0.78;
}
.craft__node[data-tier="secondary"] .craft__node-crystal {
  width: 66px;
  height: 66px;
  border-color: rgba(229, 190, 174, 0.28);
  box-shadow:
    inset 0 0 14px rgba(244, 221, 192, 0.10),
    0 0 0 1px rgba(255, 231, 160, 0.06),
    0 0 20px rgba(155, 124, 214, 0.14);
}
.craft__node[data-tier="secondary"] .craft__node-aura {
  inset: -16% -16% 32% -16%;
  opacity: 0.48;
}
.craft__node[data-tier="secondary"] .craft__node-label {
  font-size: 0.82rem;
  opacity: 0.78;
}
.craft__node-crystal::before {
  /* A subtle inner facet line — gives the crystal a hexagonal cut. */
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 18%;
  border: 1px solid rgba(229, 190, 174, 0.14);
  pointer-events: none;
}

/* LIVING ARTIFACT · continuous micro-motion.
   Each crystal hosts two ambient layers that never stop moving:
     ::after  → a soft luminous halo that breathes (opacity + scale)
                 every ~6s, giving the impression of an inner ember.
     svg      → the rune mark drifts in an ultra-slow rotation
                 (~64s per turn) so the glyph never sits perfectly
                 still without ever feeling busy.
   The two layers carry per-crystal animation-delays (see the
   data-key blocks further down) so the constellation breathes
   asynchronously — no two crystals pulse in lockstep. */
.craft__node-crystal::after {
  content: "";
  position: absolute;
  inset: -22%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255, 231, 160, 0.22) 0%,
    rgba(155, 124, 214, 0.16) 40%,
    transparent 72%);
  filter: blur(10px);
  opacity: 0.45;
  z-index: -1;
  pointer-events: none;
  animation: craft-crystal-breath 6.4s ease-in-out infinite;
}
.craft__node-crystal svg {
  animation: craft-crystal-spin 64s linear infinite;
  transform-origin: 50% 50%;
}
/* Stagger the breath + spin per crystal so the rhythm feels
   organic instead of metronomic. Numbers chosen to avoid harmonic
   alignment (no two delays are integer multiples). */
.craft__node[data-key="story"]     .craft__node-crystal::after { animation-delay: -0.4s;  }
.craft__node[data-key="ux"]        .craft__node-crystal::after { animation-delay: -1.9s;  }
.craft__node[data-key="direction"] .craft__node-crystal::after { animation-delay: -3.1s;  }
.craft__node[data-key="theme"]     .craft__node-crystal::after { animation-delay: -4.7s;  }
.craft__node[data-key="identity"]  .craft__node-crystal::after { animation-delay: -2.3s;  }
.craft__node[data-key="ambience"]  .craft__node-crystal::after { animation-delay: -5.6s;  }
.craft__node[data-key="ux"]        .craft__node-crystal svg { animation-duration: 78s;   }
.craft__node[data-key="direction"] .craft__node-crystal svg { animation-duration: 56s; animation-direction: reverse; }
.craft__node[data-key="theme"]     .craft__node-crystal svg { animation-duration: 92s; animation-direction: reverse; }
.craft__node[data-key="identity"]  .craft__node-crystal svg { animation-duration: 72s;   }
.craft__node[data-key="ambience"]  .craft__node-crystal svg { animation-duration: 84s; animation-direction: reverse; }
.craft__node-label {
  font-family: "Inter", system-ui, sans-serif;
  font-weight: 500;
  font-size: 0.88rem;
  letter-spacing: 0.04em;
  color: var(--craft-fg);
  text-align: center;
  line-height: 1.25;
  opacity: 0.86;
  transition: color 0.35s ease, opacity 0.35s ease, transform 0.35s ease;
  pointer-events: none;
  max-width: 12ch;
}

/* HOVER / FOCUS · the chosen node lifts, brightens and casts a
   stronger glow; the rest dim slightly to focus the eye. */
.craft__node:hover,
.craft__node:focus-visible {
  outline: none;
  transform: translate(-50%, calc(-50% - 6px));
  filter: drop-shadow(0 6px 18px rgba(255, 231, 160, 0.22));
}
.craft__node:hover .craft__node-aura,
.craft__node:focus-visible .craft__node-aura,
.craft__stage[data-active="story"]     .craft__node[data-key="story"]     .craft__node-aura,
.craft__stage[data-active="ux"]        .craft__node[data-key="ux"]        .craft__node-aura,
.craft__stage[data-active="direction"] .craft__node[data-key="direction"] .craft__node-aura,
.craft__stage[data-active="theme"]     .craft__node[data-key="theme"]     .craft__node-aura,
.craft__stage[data-active="identity"]  .craft__node[data-key="identity"]  .craft__node-aura,
.craft__stage[data-active="ambience"]  .craft__node[data-key="ambience"]  .craft__node-aura {
  opacity: 1;
  transform: scale(1.18);
}
/* Mirror the hover/focus crystal emphasis for the JS-driven active
   state so the node stays bright while its description is on the
   plate (e.g. after a tap on touch screens). */
.craft__stage[data-active="story"]     .craft__node[data-key="story"]     .craft__node-crystal,
.craft__stage[data-active="ux"]        .craft__node[data-key="ux"]        .craft__node-crystal,
.craft__stage[data-active="direction"] .craft__node[data-key="direction"] .craft__node-crystal,
.craft__stage[data-active="theme"]     .craft__node[data-key="theme"]     .craft__node-crystal,
.craft__stage[data-active="identity"]  .craft__node[data-key="identity"]  .craft__node-crystal,
.craft__stage[data-active="ambience"]  .craft__node[data-key="ambience"]  .craft__node-crystal {
  border-color: rgba(255, 231, 160, 0.7);
  box-shadow:
    inset 0 0 24px rgba(244, 221, 192, 0.22),
    0 0 0 1px rgba(255, 231, 160, 0.45),
    0 0 28px rgba(255, 231, 160, 0.35),
    0 0 52px rgba(155, 124, 214, 0.28);
  color: var(--craft-line-hot);
}
.craft__node:hover .craft__node-crystal,
.craft__node:focus-visible .craft__node-crystal {
  transform: rotate(-6deg) scale(1.06);
  border-color: rgba(255, 231, 160, 0.7);
  box-shadow:
    inset 0 0 24px rgba(244, 221, 192, 0.22),
    0 0 0 1px rgba(255, 231, 160, 0.45),
    0 0 32px rgba(255, 231, 160, 0.45),
    0 0 60px rgba(155, 124, 214, 0.35);
  color: var(--craft-line-hot);
}
.craft__node:hover .craft__node-label,
.craft__node:focus-visible .craft__node-label {
  color: var(--craft-fg-bright);
  opacity: 1;
  transform: translateY(2px);
}

/* CONTEXTUAL FOCUS · dim the unrelated, never the universe.
   When any crystal is active, the others step back just enough to
   let the chosen one read first — but they remain fully legible.
   The intent is "I'm exploring this region" not "everything else
   shut off". Compared to a heavy filter, we use a gentler
   brightness drop combined with a small opacity nudge so the
   diff is felt rather than seen. */
.craft__stage[data-active] .craft__node:not(:hover):not(:focus-visible) {
  filter: brightness(0.9) saturate(0.94);
  opacity: 0.78;
}
.craft__stage[data-active] .craft__node:not(:hover):not(:focus-visible) .craft__node-label {
  opacity: 0.7;
}
/* The central core also softens — it never competes with an active
   satellite but stays visibly present, anchoring the constellation. */
.craft__stage[data-active] ~ * .craft__core,
.craft__stage[data-active] .craft__core {
  filter: brightness(0.88) saturate(0.96);
  opacity: 0.86;
  transition: filter 0.5s ease, opacity 0.5s ease;
}

/* ── DESCRIPTION PLATE ──────────────────────────────────────── */
.craft__plate {
  position: relative;
  max-width: 720px;
  margin: 2.6rem auto 1.4rem;
  padding: 1.25rem 1.75rem 1.4rem;
  background:
    linear-gradient(160deg, rgba(18, 14, 26, 0.55), rgba(8, 12, 22, 0.7));
  border: 1px solid var(--craft-glass-edge);
  border-radius: 14px;
  box-shadow:
    inset 0 0 22px rgba(244, 221, 192, 0.08),
    0 12px 36px rgba(0, 0, 0, 0.45);
  text-align: center;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition:
    border-color 0.5s ease,
    box-shadow 0.5s ease,
    transform 0.5s ease;
}
.craft__plate.is-active {
  border-color: rgba(255, 231, 160, 0.5);
  box-shadow:
    inset 0 0 22px rgba(255, 231, 160, 0.12),
    0 14px 42px rgba(0, 0, 0, 0.5),
    0 0 40px rgba(255, 231, 160, 0.18);
  transform: translateY(-2px);
}
.craft__plate-key {
  display: block;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.72rem;
  letter-spacing: 0.4em;
  color: var(--craft-line-hot);
  margin-bottom: 0.55rem;
  text-transform: uppercase;
  text-shadow: 0 0 18px rgba(255, 231, 160, 0.35);
}
.craft__plate-body {
  font-family: "Inter", system-ui, sans-serif;
  font-weight: 400;
  font-size: clamp(0.95rem, 1.05vw, 1.05rem);
  line-height: 1.65;
  color: var(--on-surface);
  margin: 0;
  max-width: 60ch;
  margin-inline: auto;
  transition: opacity 0.35s ease;
}

/* ── KNOWLEDGE ECHO · the 4 allied disciplines that orbit each
   craft pillar. Rendered as small parchment chips at the bottom
   of the description plate. Hidden when no crystal is active;
   fades in on hover/focus with a 70ms cascade so the chips read
   like a slow reveal rather than a flash. Each chip carries a
   tiny sigil (✦) before the label to keep visual ties to the
   crystal universe. */
.craft__echo {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 0.55rem;
  margin: 1.05rem auto 0;
  padding: 0;
  max-width: 600px;
  min-height: 28px;
  list-style: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  pointer-events: none;
}
.craft__plate.is-active .craft__echo {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.craft__echo-tag {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0.34rem 0.78rem;
  border-radius: 999px;
  background: linear-gradient(160deg,
    rgba(244, 221, 192, 0.08),
    rgba(155, 124, 214, 0.06));
  border: 1px solid rgba(255, 231, 160, 0.22);
  color: var(--craft-fg);
  font-family: "Inter", system-ui, sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(6px) scale(0.96);
  transition:
    opacity 0.45s ease,
    transform 0.45s ease,
    border-color 0.35s ease,
    color 0.35s ease,
    background 0.35s ease;
}
.craft__echo-tag:empty { display: none; }
.craft__echo-tag::before {
  content: "✦";
  margin-right: 0.45em;
  font-size: 0.7em;
  color: var(--craft-line-hot);
  opacity: 0.65;
  vertical-align: 0.05em;
}
.craft__plate.is-active .craft__echo-tag {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.craft__plate.is-active .craft__echo-tag:nth-child(1) { transition-delay: 0.06s; }
.craft__plate.is-active .craft__echo-tag:nth-child(2) { transition-delay: 0.14s; }
.craft__plate.is-active .craft__echo-tag:nth-child(3) { transition-delay: 0.22s; }
.craft__plate.is-active .craft__echo-tag:nth-child(4) { transition-delay: 0.30s; }
.craft__echo-tag:hover,
.craft__echo-tag:focus-visible {
  color: var(--craft-line-hot);
  border-color: rgba(255, 231, 160, 0.55);
  background: linear-gradient(160deg,
    rgba(255, 231, 160, 0.14),
    rgba(155, 124, 214, 0.10));
  outline: none;
}

/* ── EPILOGUE · closing tagline below the constellation ─────── */
.craft__epilogue {
  max-width: 760px;
  margin: 1.4rem auto 0;
  text-align: center;
  font-family: "Inter", system-ui, sans-serif;
  font-weight: 400;
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--on-surface-variant);
  opacity: 0.78;
  letter-spacing: 0.03em;
}

/* WALLPAPER FOCUS · the live skill-tree wallpaper retreats by two
   independent forces, multiplied:
     1. NARRATIVE PROGRESS — as the user scrolls through #knowledge,
        --tree-wall-dim (0..0.55, set by narrative.js) gently pulls
        brightness down so the universe stays alive but lets the
        constellation read forward.
     2. CRAFT HOVER — when any craft crystal is hovered, an extra
        nudge layers on so the eye anchors on the active region.
   We compose both into one filter declaration via calc() instead of
   overriding, so the two effects accumulate gracefully. */
.tree-wall {
  filter:
    brightness(calc(1 - var(--tree-wall-dim, 0) * 0.32))
    saturate(calc(1 - var(--tree-wall-dim, 0) * 0.20));
  transition: filter 0.7s ease;
}
html[data-craft-active] .tree-wall {
  filter:
    brightness(calc((1 - var(--tree-wall-dim, 0) * 0.32) * 0.92))
    saturate(calc((1 - var(--tree-wall-dim, 0) * 0.20) * 0.94));
}

/* ── ANIMATIONS ─────────────────────────────────────────────── */
@keyframes craft-aura {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.08); }
}
@keyframes craft-ring {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@keyframes craft-core-float {
  0%, 100% { transform: translateY(0) rotate(0); }
  50%      { transform: translateY(-4px) rotate(2deg); }
}
@keyframes craft-node-float {
  0%, 100% { transform: translate(-50%, -50%); }
  50%      { transform: translate(-50%, calc(-50% - 5px)); }
}
/* The slow ember beneath each crystal — barely visible, but it
   guarantees the constellation is never frozen. The pulse is
   asymmetric so the rise and fall don't read as a beat. */
@keyframes craft-crystal-breath {
  0%, 100% { opacity: 0.32; transform: scale(0.96); }
  45%      { opacity: 0.58; transform: scale(1.06); }
}
/* Ultra-slow rotation applied to the rune SVG inside each crystal.
   At 60s+ per turn, the eye reads it as "alive" rather than
   "moving". The hover state does NOT cancel it; it runs over the
   hover transform because it lives on a child element. */
@keyframes craft-crystal-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
/* Title halo · soft luminous mask that lives behind .craft__head.
   Drifts gently so the title never sits over a static glow. */
@keyframes craft-title-breath {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 0.9; transform: scale(1.04); }
}

/* Reduced motion — keep the visuals legible, drop the breathing.
   The ambient ember and slow spin both pause; only structural
   layout and hover responses remain. */
@media (prefers-reduced-motion: reduce) {
  .craft__node,
  .craft__node-crystal::after,
  .craft__node-crystal svg,
  .craft__core-aura,
  .craft__core-ring,
  .craft__core-mark,
  .craft__core-mark svg,
  .craft__core-runes,
  .craft__line,
  .craft__head::before {
    animation: none !important;
  }
}

/* ── RESPONSIVE ─────────────────────────────────────────────────
   On medium screens we shrink everything but preserve the
   primary > secondary visual gap. Selectors include [data-tier]
   so they out-specify the desktop tier rules above. */
@media (max-width: 880px) {
  .craft__stage { max-width: 640px; aspect-ratio: 800 / 600; }
  .craft__core  { width: 164px; height: 164px; }
  .craft__core-mark { width: 88px; height: 88px; }
  .craft__node      { width: 118px; }
  .craft__node-crystal { width: 66px; height: 66px; }
  .craft__node[data-tier="primary"]   .craft__node-crystal { width: 74px; height: 74px; }
  .craft__node[data-tier="secondary"] .craft__node-crystal { width: 56px; height: 56px; }
  .craft__node-label   { font-size: 0.82rem; }
}
@media (max-width: 640px) {
  /* On narrow screens the constellation would clip — collapse the
     6 satellites into a 2-column grid below the central core. Lines
     are hidden because they no longer connect to the right targets. */
  .craft { margin: 2.6rem auto 3.4rem; }
  .craft__stage {
    aspect-ratio: auto;
    max-width: 100%;
    padding-top: 220px;        /* space reserved for the central core */
    padding-bottom: 0;
  }
  .craft__field { display: none; }
  .craft__lines { display: none; }
  .craft__core {
    top: 110px; left: 50%;
    width: 178px; height: 178px;
  }
  .craft__node {
    position: relative;
    top: auto !important;
    left: auto !important;
    transform: none !important;
    width: 100%;
    animation: none;
  }
  .craft__node:hover,
  .craft__node:focus-visible {
    transform: translateY(-3px) !important;
  }
  .craft__stage {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1.2rem 0.6rem;
    place-items: center;
  }
  /* Span the core full-width above the grid. */
  .craft__core { grid-column: 1 / -1; position: relative; top: auto; left: auto; transform: none; margin: 0 auto 1.5rem; }
}

/* ── LIGHT THEME · sepia/parchment crystals ─────────────────── */
html[data-theme="light"] .craft {
  --craft-fg:          #5C2B1F;
  --craft-fg-bright:   #8C5A2F;
  --craft-line:        rgba(140, 90, 47, 0.45);
  --craft-line-hot:    #8C5A2F;
  --craft-glass:       rgba(248, 232, 196, 0.55);
  --craft-glass-edge:  rgba(140, 90, 47, 0.32);
}
html[data-theme="light"] .craft__title {
  background: linear-gradient(135deg, #6B3018 0%, #8C5A2F 45%, #5C2B1F 100%);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  text-shadow: none;
}
html[data-theme="light"] .craft__sub,
html[data-theme="light"] .craft__epilogue {
  color: var(--burgundy, #5C2B1F);
  opacity: 0.86;
}
html[data-theme="light"] .craft__core-mark,
html[data-theme="light"] .craft__node-crystal {
  background:
    radial-gradient(circle at 30% 30%, rgba(248, 232, 196, 0.85), transparent 60%),
    linear-gradient(160deg, rgba(232, 210, 168, 0.95), rgba(204, 168, 110, 0.95));
  border-color: rgba(140, 90, 47, 0.5);
  box-shadow:
    inset 0 0 18px rgba(255, 240, 200, 0.55),
    0 0 0 1px rgba(140, 90, 47, 0.2),
    0 0 18px rgba(212, 168, 110, 0.35);
  color: var(--burgundy, #5C2B1F);
}
html[data-theme="light"] .craft__plate {
  background:
    linear-gradient(160deg, rgba(248, 232, 196, 0.7), rgba(228, 200, 150, 0.55));
  border-color: rgba(140, 90, 47, 0.4);
  box-shadow:
    inset 0 0 22px rgba(255, 240, 200, 0.4),
    0 12px 30px rgba(60, 30, 8, 0.18);
}
html[data-theme="light"] .craft__plate-key  { color: var(--burgundy, #5C2B1F); text-shadow: none; }
html[data-theme="light"] .craft__plate-body { color: var(--ink-deep, #3a1810); }
html[data-theme="light"] .craft__line { filter: none; }
/* Echo chips · sepia-bronze wax on light parchment */
html[data-theme="light"] .craft__echo-tag {
  background: linear-gradient(160deg,
    rgba(248, 232, 196, 0.85),
    rgba(228, 200, 150, 0.6));
  border-color: rgba(140, 90, 47, 0.45);
  color: var(--burgundy, #5C2B1F);
}
html[data-theme="light"] .craft__echo-tag::before {
  color: var(--burgundy, #5C2B1F);
  opacity: 0.7;
}
html[data-theme="light"] .craft__echo-tag:hover,
html[data-theme="light"] .craft__echo-tag:focus-visible {
  background: linear-gradient(160deg,
    rgba(255, 240, 200, 0.95),
    rgba(232, 192, 130, 0.75));
  border-color: rgba(140, 90, 47, 0.7);
  color: var(--rust, #A13E1E);
}
/* In light mode the wallpaper canvas is already very subdued
   (bg fully hidden, fg multiply-blended). A heavy filter would
   wash it out entirely — use the lightest possible nudge. */
html[data-theme="light"][data-craft-active] .tree-wall {
  filter: brightness(0.95) saturate(0.96);
}
html[data-theme="light"] .craft__stage[data-active="story"]     .craft__line[data-key="story"],
html[data-theme="light"] .craft__stage[data-active="ux"]        .craft__line[data-key="ux"],
html[data-theme="light"] .craft__stage[data-active="direction"] .craft__line[data-key="direction"],
html[data-theme="light"] .craft__stage[data-active="theme"]     .craft__line[data-key="theme"],
html[data-theme="light"] .craft__stage[data-active="identity"]  .craft__line[data-key="identity"],
html[data-theme="light"] .craft__stage[data-active="ambience"]  .craft__line[data-key="ambience"] {
  stroke: #8C5A2F;
  filter:
    drop-shadow(0 0 4px rgba(140, 90, 47, 0.45))
    drop-shadow(0 0 10px rgba(212, 168, 110, 0.3));
}

/* HUD floats fixed at the TOP-RIGHT corner (just below the nav)
   so it doesn't compete with the upper-left Hero panel and, more
   importantly, leaves the bottom-right free for Merlin who likes
   to teleport around that corner.

   Sizing note: the panel is intentionally compact — the Skill
   Tree itself is the primary visual focus, the HUD is just an
   instrument readout. Roughly 20% smaller than the original
   bottom-right design.                                          */
.tree-hud {
  position: fixed;
  z-index: 90;
  top: 5rem;
  right: 1rem;
  bottom: auto;
  left: auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4rem;
  max-width: 240px;
  pointer-events: none;
}

.tree-hud__panel {
  pointer-events: all;
  padding: 0.6rem 0.75rem;
  background: rgba(9, 22, 9, 0.78);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

.tree-hud__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.tree-hud__label {
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-surface-muted);
}

.tree-hud__count {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  color: var(--gold);
}

.tree-hud__count strong {
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--primary);
  margin-right: 0.1rem;
}

.tree-hud__divider { color: var(--on-surface-muted); margin: 0 0.25rem; }

.tree-hud__bar {
  height: 1.5px;
  background: var(--surface-container-highest);
  border-radius: var(--radius-full);
  overflow: hidden;
}

.tree-hud__bar > div {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, #4a8db5 0%, #afcdc1 30%, #c2a46b 65%, #e5beae 100%);
  border-radius: var(--radius-full);
  transition: width 0.6s var(--ease-out);
  box-shadow: 0 0 8px rgba(194, 164, 107, 0.4);
}

.tree-hud__clusters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.25rem 0.4rem;
}

.cluster-tag {
  display: flex;
  align-items: center;
  gap: 0.32rem;
  font-family: var(--font-mono);
  font-size: 0.46rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--on-surface-muted);
  transition: color 0.3s;
  white-space: nowrap;
}

.cluster-tag.is-mastered { color: var(--primary); }

.cluster-tag__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--cluster-color, #6f7f6c);
  box-shadow: 0 0 5px var(--cluster-color, #6f7f6c);
  flex-shrink: 0;
  opacity: 0.45;
  transition: opacity 0.3s;
}

.cluster-tag.is-mastered .cluster-tag__dot { opacity: 1; }

.cluster-tag__count {
  margin-left: auto;
  color: var(--on-surface-muted);
  font-size: 0.44rem;
}

.tree-hud__actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  border-top: 1px solid var(--glass-border);
  padding-top: 0.45rem;
}

.tree-hud__action {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.28rem 0.45rem;
  font-family: var(--font-mono);
  font-size: 0.44rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-surface-muted);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  transition: color 0.2s, border-color 0.2s;
}

.tree-hud__action:hover,
.tree-hud__action:focus-visible {
  color: var(--gold);
  border-color: var(--gold-dim);
  outline: none;
}

.tree-hud__action--reset { margin-left: auto; }
.tree-hud__action--reset:hover,
.tree-hud__action--reset:focus-visible {
  color: var(--rust);
  border-color: rgba(161, 62, 30, 0.4);
}

.tree-hud__hint {
  pointer-events: none;
  align-self: flex-end;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.85rem;
  background: rgba(9, 22, 9, 0.78);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-full);
  backdrop-filter: blur(10px);
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-surface-variant);
  opacity: 1;
  transition: opacity 0.5s;
}

.tree-hud__hint.is-fading { opacity: 0; }

.tree-hud__hint-pulse {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 8px var(--gold);
  animation: hint-pulse 1.6s ease-in-out infinite;
}

@keyframes hint-pulse {
  0%, 100% { transform: scale(0.8); opacity: 0.5; }
  50%       { transform: scale(1.3); opacity: 1; }
}

/* Ritual overlay (unchanged structure, refined) */
.ritual {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0);
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.2s var(--ease-out), background 1.2s var(--ease-out);
}

.ritual.is-active {
  opacity: 1;
  pointer-events: all;
  background: rgba(2, 6, 4, 0.94);
}

.ritual__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.ritual__center {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  text-align: center;
  padding: 0 1.5rem;
}

.ritual__rune {
  position: relative;
  width: 200px;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.4) rotate(-180deg);
  transition: opacity 1.4s 0.3s var(--ease-out), transform 1.8s 0.3s var(--ease-out);
}

.ritual.is-active .ritual__rune {
  opacity: 1;
  transform: scale(1) rotate(0deg);
}

.ritual__rune svg { animation: rune-spin 36s linear infinite; }

@keyframes rune-spin {
  from { transform: rotate(0); }
  to   { transform: rotate(360deg); }
}

.ritual__rune-inner { animation: rune-glow 3s ease-in-out infinite alternate; }

@keyframes rune-glow {
  from { filter: drop-shadow(0 0 4px rgba(194,164,107,0.4)); }
  to   { filter: drop-shadow(0 0 22px rgba(229,190,174,0.85)); }
}

.ritual__photo {
  position: absolute;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--gold);
  opacity: 0;
  transform: scale(0.3);
  transition: opacity 1.6s 2.6s var(--ease-out), transform 2s 2.6s var(--ease-out);
}

.ritual.is-active.is-revealed .ritual__photo {
  opacity: 1;
  transform: scale(1);
}

.ritual__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

.ritual__photo-halo {
  position: absolute;
  inset: -50%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(229,190,174,0.4) 0%, transparent 60%);
  pointer-events: none;
  animation: photo-halo 4s ease-in-out infinite alternate;
}

@keyframes photo-halo {
  from { opacity: 0.6; transform: scale(0.95); }
  to   { opacity: 1;   transform: scale(1.08); }
}

.ritual__title {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 4vw, 2.8rem);
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--primary);
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 1s 4s var(--ease-out), transform 1s 4s var(--ease-out);
  margin-top: 1.5rem;
}

.ritual.is-active.is-revealed .ritual__title {
  opacity: 1;
  transform: translateY(0);
}

.ritual__subtitle {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold);
  opacity: 0;
  transition: opacity 1s 4.4s var(--ease-out);
}

.ritual.is-active.is-revealed .ritual__subtitle { opacity: 1; }

.ritual__close {
  margin-top: 2rem;
  padding: 0.7rem 1.4rem;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--primary);
  background: var(--primary-container);
  border: 1px solid var(--ochre);
  border-radius: var(--radius-sm);
  opacity: 0;
  transition: opacity 1s 5s var(--ease-out), border-color 0.3s, box-shadow 0.3s;
}

.ritual.is-active.is-revealed .ritual__close { opacity: 1; }

.ritual__close:hover,
.ritual__close:focus-visible {
  border-color: var(--gold);
  box-shadow: 0 0 24px rgba(194, 164, 107, 0.3);
  outline: none;
}

@media (max-width: 767px) {
  /* MOBILE TREE-HUD · hidden entirely.
     -----------------------------------------------
     The "DOMINADO" mastery panel has no interaction on touch (its
     hover legend / actions are desktop-only), so on phones it was
     just chrome cluttering the top-right corner. Remove it. The
     mastery count still tracks internally; it simply isn't shown. */
  .tree-hud { display: none; }

  .tree-vault__header { padding: 0.85rem 1rem; }
}

/* ============================================================
   MEMORY CRYSTALS · Narrative anchor only
   ------------------------------------------------------------
   The Memory Crystals do NOT live inside this section anymore.
   The 3D scene is rendered globally inside .tree-wall, sharing
   the exact plane of the skill-tree canvases. This section is
   pure prose (header + legend + info card) — a scroll target
   that explains what the floating crystals are.
   ============================================================ */

.memories {
  position: relative;
  z-index: var(--z-content);
  padding: var(--space-xl) var(--margin-safe);
  max-width: 1400px;
  margin: 0 auto;
  /* isolation: isolate removed (June 2026) — it boxed mix-blend-mode
     children and drew a faint rectangular stack boundary during the
     singularity / Big Bang sequence ("borda fantasma"). */
  overflow: visible;
  border: none;
  outline: none;
  box-shadow: none;
  background: transparent;
  pointer-events: none;            /* tree wallpaper receives idle hits */
  /* Parallax driver (set by JS) — read by the crystal scene */
  --mx: 0;
  --my: 0;
}

/* Interactive memories UI — re-enables pointer events */
.memories__head,
.crystal-caption,
.crystal-loader {
  pointer-events: auto;
}

/* No vignette, no decorative box: the section must not introduce
   any visual frame around the wallpaper. */
.memories::before { display: none !important; content: none !important; }

/* ------------------------------------------------------------ */
/*  Header (text marginalia)                                     */
/* ------------------------------------------------------------ */

.memories__head {
  position: relative;
  z-index: 2;
  max-width: 760px;
  margin: 0 auto var(--space-lg);
  text-align: center;
  padding: 1.4rem 1.5rem;
  /* Aligns with .memories design note: no decorative frame on the
     wallpaper — only typographic marginalia (VBA, June 2026). */
  background: transparent;
  border: none;
  border-radius: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
  /* HUD parallax — barely moves (closest UI plane) */
  translate: calc(var(--mx) * 3px) calc(var(--my) * 3px);
}

.memories__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.6rem;
  opacity: 0.85;
  text-shadow:
    0 0 12px rgba(194, 164, 107, 0.35),
    0 0 24px rgba(9, 22, 9, 0.9),
    0 1px 2px rgba(0, 0, 0, 0.8);
}

.memories__title {
  font-family: var(--font-display);
  font-size: clamp(1.65rem, 3.6vw, 2.35rem);
  color: var(--primary);
  line-height: 1.1;
  margin-bottom: 0.8rem;
  letter-spacing: -0.005em;
  text-shadow:
    0 0 22px rgba(229, 190, 174, 0.25),
    0 0 32px rgba(9, 22, 9, 0.88),
    0 1px 3px rgba(0, 0, 0, 0.82);
}

.memories__lede {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--on-surface-variant);
  max-width: 56ch;
  margin: 0 auto 1.4rem;
  text-shadow:
    0 0 20px rgba(9, 22, 9, 0.9),
    0 1px 2px rgba(0, 0, 0, 0.75);
}

.memories__legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem 1.4rem;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.memories__legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--on-surface-muted);
}

.memories__legend-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  box-shadow: 0 0 10px currentColor;
}

.memories__legend-item[data-rarity="common"]    .memories__legend-dot { background: #3FD68B; color: #3FD68B; }
.memories__legend-item[data-rarity="rare"]      .memories__legend-dot { background: #3F9CD6; color: #3F9CD6; }
.memories__legend-item[data-rarity="epic"]      .memories__legend-dot { background: #9B5CD9; color: #9B5CD9; }
.memories__legend-item[data-rarity="legendary"] .memories__legend-dot { background: #E5BEAE; color: #E5BEAE; }

/* ------------------------------------------------------------ */
/*  "Explorar Relíquias" — gateway to the guided relic-card tour */
/* ------------------------------------------------------------ */
.memories__explore {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin: 1.5rem auto 0;
  padding: 0.6rem 1.35rem;
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  color: #2a1808;
  background: linear-gradient(160deg, #f1dcb8 0%, #d8b984 52%, #bc954f 100%);
  border: 1px solid rgba(120, 80, 40, 0.6);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.45),
    0 4px 14px rgba(0, 0, 0, 0.34);
  transition: transform 0.35s var(--ease-out, cubic-bezier(.16,1,.3,1)),
    box-shadow 0.45s ease, background 0.45s ease;
  isolation: isolate;
}
.memories__explore-sigil {
  display: inline-flex;
  color: #4a2e12;
  filter: drop-shadow(0 0 3px rgba(255, 240, 200, 0.4));
}
.memories__explore-arrow {
  display: inline-flex;
  transition: transform 0.4s var(--ease-out, cubic-bezier(.16,1,.3,1));
}
.memories__explore:hover,
.memories__explore:focus-visible {
  outline: none;
  transform: translateY(-1px);
  background: linear-gradient(160deg, #f8e7c6 0%, #e3c590 52%, #c8a056 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.6),
    0 7px 20px rgba(0, 0, 0, 0.4),
    0 0 20px rgba(255, 231, 160, 0.32);
}
.memories__explore:hover .memories__explore-arrow,
.memories__explore:focus-visible .memories__explore-arrow {
  transform: translateX(3px);
}
.memories__explore:active { transform: translateY(0) scale(0.99); }
@media (prefers-reduced-motion: reduce) {
  .memories__explore,
  .memories__explore-arrow { transition: none; }
}

/* ------------------------------------------------------------ */
/*  Floating loader — bottom-right, no stage                    */
/* ------------------------------------------------------------ */

.crystal-loader {
  position: fixed;
  bottom: 1.2rem;
  right: 1.2rem;
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.85rem 0.55rem 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--on-surface-muted);
  background: rgba(9, 22, 9, 0.55);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-full);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  pointer-events: none;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.32);
}

/* ------------------------------------------------------------ */
/*  Crystal captions — projected from 3D positions               */
/* ------------------------------------------------------------ */

.crystal-caption {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  text-align: center;
  pointer-events: auto;
  cursor: pointer;
  transition: opacity 0.35s var(--ease-out), filter 0.35s var(--ease-out);
  will-change: transform, opacity;
  z-index: 1;
  
}

/* Rarity pill · phantom-border fix (June 2026): the previous
   `border: 1px solid` + opaque background + backdrop-filter
   rendered as a tiny rectangle floating beside each crystal
   ("borda fantasma" in Memories). It is now a typographic
   marginalia: pure colour + glow, no frame, no panel. */
.crystal-caption__rarity {
  font-family: var(--font-mono);
  font-size: 0.48rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--c-light);
  padding: 0.15rem 0.5rem;
  border: none;
  border-radius: 0;
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  text-shadow:
    0 0 10px var(--c-glow),
    0 0 18px rgba(9, 22, 9, 0.9),
    0 1px 2px rgba(0, 0, 0, 0.75);
}

.crystal-caption__name {
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--primary);
  line-height: 1.15;
  text-shadow:
    0 0 12px color-mix(in srgb, var(--c-glow) 80%, transparent),
    0 0 1px rgba(0, 0, 0, 0.9);
  max-width: 160px;
}

.crystal-caption__type {
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--c-light) 65%, var(--on-surface-muted) 35%);
  opacity: 0.8;
}

.crystal-caption--common .crystal-caption__name { font-size: 0.82rem; }
.crystal-caption--legendary .crystal-caption__name { font-size: 1.15rem; letter-spacing: 0.01em; }

.crystal-caption.is-hovered,
.crystal-caption:hover,
.crystal-caption:focus-visible {
  filter: brightness(1.25);
  z-index: 10;
}

.crystal-caption:focus-visible {
  outline: none;
  filter: brightness(1.4) drop-shadow(0 0 8px var(--c-glow));
}

/* ============================================================
   ZERO INSPECTION MARKS · Crystal plane
   --------------------------------------------------------------
   The crystals must show only the rendered visuals.
   No outlines, focus rings, debug rectangles, dev grids, tap
   flashes, drag-select rectangles, browser highlights, or any
   user-agent-injected indicator.
   ============================================================ */

#crystal-canvas,
#crystal-canvas:hover,
#crystal-canvas:focus,
#crystal-canvas:focus-visible,
#crystal-canvas:active,
#crystal-overlay,
#crystal-overlay *,
.crystal-caption,
.crystal-caption *,
.memories,
.memories *,
.memories *::before,
.memories *::after {
  -webkit-tap-highlight-color: transparent !important;
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  outline: none !important;
  outline-offset: 0 !important;
  -webkit-appearance: none;
  appearance: none;
}

#crystal-canvas,
#crystal-overlay {
  border: 0 !important;
  box-shadow: none !important;
  background: transparent;
}

/* Block native text-selection rectangles so a stray drag never
   draws an inspection-style box over the gems. The lede paragraph
   re-enables selection below. */
.memories,
.memories *,
#crystal-overlay,
#crystal-overlay * {
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}
.memories ::selection      { background: transparent; color: inherit; }
.memories ::-moz-selection { background: transparent; color: inherit; }

/* Re-enable selection just for the explanatory prose */
.memories__head .memories__lede,
.memories__head .memories__eyebrow {
  user-select: text;
  -webkit-user-select: text;
}

/* Legacy .crystal card styles removed — 3D WebGL replaces them */

.loader-rune {
  display: block;
  width: 28px;
  height: 28px;
  border: 1px solid var(--gold);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

@keyframes crystal-float {
  0%, 100% { transform: translateY(0) rotate(-0.4deg); }
  50%      { transform: translateY(-7px) rotate(0.4deg); }
}

@keyframes orbit-spin { to { transform: rotate(360deg); } }

/* "Como Funciona" floating info card removed at user request
   (June 2026) — its DOM <aside class="memories__info"> was
   also stripped from index.html. Light-theme overrides for the
   same element were removed below. */

/* ============================================================
   MEMORY VAULT · Arcane Relic Card (MTG-inspired)
   ------------------------------------------------------------
   Each crystal reveals a collectible relic card. The overlay
   keeps the cinematic open/close behaviour, but everything
   inside is now ONE vertical card with:
     · large illustrated artwork at the top (~58% of height)
     · ornate gold frame + corner sigils
     · Relic · Type · Rarity type-line
     · embossed title plate
     · flavour description + technology sigils
     · wax-seal "Open Artifact" CTA → GitHub

   Colour palette is rarity-driven via --c-light / --c-mid /
   --c-dark / --c-glow set per-project from JS. The frame uses
   antique gold (#B89858) as a fixed base, with rarity colour
   blooming around the illustration and across the seal.
   ============================================================ */

.crystal-vault {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: grid;
  place-items: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.45s var(--ease-out);
}

.crystal-vault.is-open {
  pointer-events: auto;
  opacity: 1;
}

/* Backdrop: deeper than before — a true grimoire-vault darkness
   with a faint sepia haze that hints at parchment behind. */
.crystal-vault__backdrop {
  position: absolute;
  inset: 0;
  /* Opaque vault darkness — no backdrop-filter. Blurring a live WebGL
     canvas behind the modal forces per-frame recompositing and reads
     as background "shimmer" while the vault is open. */
  background:
    radial-gradient(ellipse 60% 50% at 50% 45%, rgba(90, 45, 18, 0.22), transparent 70%),
    radial-gradient(ellipse at center, rgba(8, 6, 12, 0.88) 0%, rgba(2, 1, 4, 0.97) 70%);
  cursor: zoom-out;
}

/* Body class: while vault is open, mute the rest of the page so the
   tree wallpaper is felt but recedes behind the memory. */
body.vault-open {
  overflow: hidden;
}

body.vault-open .nav,
body.vault-open .footer,
body.vault-open .merlin {
  opacity: 0.35;
  pointer-events: none;
  transition: opacity 0.4s var(--ease-out);
}

/* Two-column stage:
     · LEFT  → cinematic 3D crystal (Three.js mini-scene)
     · RIGHT → relic card (project info) */
.crystal-vault__stage {
  --c-light: #E5BEAE;
  --c-mid: #C2A46B;
  --c-dark: #A13E1E;
  --c-glow: rgba(229, 190, 174, 0.6);
  /* Antique-gold frame palette for the relic card. */
  --gold-frame:       #B89858;
  --gold-frame-bright:#E5C97A;
  --gold-frame-deep:  #6E4C1E;
  --gold-emboss-hi:   rgba(255, 232, 168, 0.55);
  --gold-emboss-lo:   rgba(40, 22, 8, 0.85);
  --ink-card:         #2A1D0E;
  --vellum-card:      #ECD8A6;
  --vellum-card-deep: #C8AC68;

  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(360px, 1fr) minmax(360px, 460px);
  align-items: center;
  gap: 1.6rem 3rem;
  width: min(1180px, 96vw);
  max-height: 92vh;
  padding: 2.4rem 2.6rem 2rem;
  background: transparent;
  border: 0;
  box-shadow: none;
  opacity: 0;
  /* Opacity-only entrance — scaling the stage shifted the whole grid
     (~120px card jump) while the relic card was summoning. */
  transition: opacity 0.45s var(--ease-out);
}

.crystal-vault.is-open .crystal-vault__stage {
  opacity: 1;
}

/* Top-left brand mark inside the vault */
.crystal-vault__brand {
  position: absolute;
  top: 1.2rem;
  left: 1.4rem;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--c-light);
  opacity: 0.78;
  z-index: 5;
  pointer-events: none;
  text-shadow: 0 0 10px color-mix(in srgb, var(--c-glow) 70%, transparent);
}
.crystal-vault__brand-mark {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  color: var(--c-light);
  opacity: 0.85;
}

/* Close button — small bronze sigil at the top-right of the stage */
.crystal-vault__close {
  position: absolute;
  top: 1.05rem;
  right: 1.2rem;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 30%, #2A1A0A 0%, #0E0703 70%);
  border: 1.5px solid var(--gold-frame);
  color: var(--gold-frame-bright);
  cursor: pointer;
  transition: transform var(--duration-fast), background var(--duration-fast),
              box-shadow var(--duration-fast), border-color var(--duration-fast);
  z-index: 6;
  box-shadow:
    0 0 0 1px var(--gold-emboss-lo),
    inset 0 0 0 1px var(--gold-emboss-hi),
    0 6px 18px rgba(0, 0, 0, 0.55),
    0 0 18px color-mix(in srgb, var(--c-glow) 50%, transparent);
}

/* ============================================================
   CRYSTAL VAULT · GUIDED TOUR controls (prev/next + counter)
   ------------------------------------------------------------
   Activated by Crystals.openTour() — entered from the hero
   "Ver Cristais" CTA. Stage carries data-tour="true" while the
   visitor is moving through the curated 4-project sequence.
   Controls share the same bronze sigil language as the close
   button to keep visual cohesion inside the vault.
   ============================================================ */
.crystal-vault__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  display: none;
  place-items: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 30%, #2A1A0A 0%, #0E0703 70%);
  border: 1.5px solid var(--gold-frame);
  color: var(--gold-frame-bright);
  cursor: pointer;
  transition:
    transform var(--duration-fast),
    background var(--duration-fast),
    box-shadow var(--duration-fast),
    border-color var(--duration-fast),
    color var(--duration-fast);
  z-index: 6;
  box-shadow:
    0 0 0 1px var(--gold-emboss-lo),
    inset 0 0 0 1px var(--gold-emboss-hi),
    0 6px 18px rgba(0, 0, 0, 0.55),
    0 0 22px color-mix(in srgb, var(--c-glow, rgba(229, 190, 174, 0.4)) 55%, transparent);
}
.crystal-vault__stage[data-tour="true"] .crystal-vault__nav {
  display: grid;
  animation: vault-nav-fade-in 0.45s ease both;
}
/* Anchored INSIDE the stage (left/right with positive offsets) so the
   arrows always stay within the viewport regardless of how wide the
   vault stage grows. They float over the cinematic crystal column on
   the left and the relic card on the right. */
.crystal-vault__nav--prev { left: 18px; }
.crystal-vault__nav--next { right: 18px; }
.crystal-vault__nav:hover {
  border-color: var(--gold-frame-bright);
  color: #FFE2B0;
  transform: translateY(-50%) scale(1.08);
  box-shadow:
    0 0 0 1px var(--gold-emboss-lo),
    inset 0 0 0 1px var(--gold-emboss-hi),
    0 8px 24px rgba(0, 0, 0, 0.6),
    0 0 32px color-mix(in srgb, var(--c-glow, rgba(229, 190, 174, 0.6)) 80%, transparent);
}
.crystal-vault__nav--prev:hover { transform: translateY(-50%) translateX(-3px) scale(1.08); }
.crystal-vault__nav--next:hover { transform: translateY(-50%) translateX(3px)  scale(1.08); }
.crystal-vault__nav:focus-visible {
  outline: 1px solid var(--gold-frame-bright);
  outline-offset: 4px;
}
.crystal-vault__nav:active { transform: translateY(-50%) scale(0.96); }
.crystal-vault__nav[disabled],
.crystal-vault__nav.is-disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}
@keyframes vault-nav-fade-in {
  from { opacity: 0; transform: translateY(-50%) scale(0.6); }
  to   { opacity: 1; transform: translateY(-50%) scale(1);   }
}

/* Counter "I · IV" — Roman numerals in a parchment pill, bottom-centre */
.crystal-vault__counter {
  position: absolute;
  bottom: 1.05rem;
  left: 50%;
  transform: translateX(-50%);
  display: none;
  align-items: baseline;
  gap: 0.45rem;
  padding: 0.36rem 0.85rem;
  background:
    linear-gradient(180deg, rgba(20, 12, 5, 0.78), rgba(10, 6, 3, 0.55));
  border: 1px solid var(--gold-frame);
  border-radius: 999px;
  font-family: "Cinzel", "Libre Caslon Text", Georgia, serif;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  color: var(--gold-frame-bright);
  z-index: 6;
  box-shadow:
    0 0 0 1px var(--gold-emboss-lo),
    0 4px 14px rgba(0, 0, 0, 0.5),
    0 0 18px color-mix(in srgb, var(--c-glow, rgba(229, 190, 174, 0.4)) 40%, transparent);
}
.crystal-vault__stage[data-tour="true"] .crystal-vault__counter {
  display: inline-flex;
  animation: vault-nav-fade-in 0.5s 0.1s ease both;
}
.crystal-vault__counter-sep    { opacity: 0.55; padding: 0 0.1rem; }
.crystal-vault__counter-current { color: #FFE6B5; text-shadow: 0 0 8px rgba(255, 230, 181, 0.45); }

/* Mobile: keep arrows inside the stage and slightly tighter. */
@media (max-width: 720px) {
  .crystal-vault__nav { width: 40px; height: 40px; }
  .crystal-vault__nav--prev { left: 8px; }
  .crystal-vault__nav--next { right: 8px; }
  .crystal-vault__counter {
    bottom: 0.65rem;
    font-size: 0.62rem;
    letter-spacing: 0.26em;
    padding: 0.3rem 0.7rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .crystal-vault__nav,
  .crystal-vault__counter {
    animation: none !important;
    transition: none;
  }
}

.crystal-vault__close:hover {
  transform: rotate(90deg) scale(1.06);
  border-color: var(--gold-frame-bright);
  color: #FFE2B0;
  box-shadow:
    0 0 0 1px var(--gold-emboss-lo),
    inset 0 0 0 1px var(--gold-emboss-hi),
    0 6px 22px rgba(0, 0, 0, 0.7),
    0 0 26px color-mix(in srgb, var(--c-glow) 80%, transparent);
}

/* ============================================================
   LEFT COLUMN · cinematic 3D crystal (preserved from old vault)
   ============================================================ */

.crystal-vault__core {
  position: relative;
  width: 100%;
  height: clamp(340px, 58vh, 600px);
  display: grid;
  place-items: center;
  isolation: isolate;
}

.crystal-vault__halo {
  position: absolute;
  inset: 8%;
  border-radius: 50%;
  background:
    radial-gradient(circle, var(--c-glow) 0%, transparent 60%),
    radial-gradient(circle, color-mix(in srgb, var(--c-light) 25%, transparent) 0%, transparent 75%);
  filter: blur(48px);
  opacity: 0.85;
  z-index: 0;
  animation: vault-halo-pulse 4s ease-in-out infinite;
}

@keyframes vault-halo-pulse {
  0%, 100% { opacity: 0.7; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.08); }
}

.crystal-vault__gem {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  display: block;
  animation: vault-gem-pop 0.9s var(--ease-out);
}

.crystal-vault__gem-canvas {
  width: 100% !important;
  height: 100% !important;
  display: block;
  filter:
    drop-shadow(0 16px 40px rgba(0, 0, 0, 0.7))
    drop-shadow(0 0 60px var(--c-glow));
}

@keyframes vault-gem-pop {
  0%   { transform: scale(0.4) rotate(-12deg); opacity: 0; }
  60%  { transform: scale(1.06) rotate(2deg);  opacity: 1; }
  100% { transform: scale(1)    rotate(0deg);  opacity: 1; }
}

.crystal-vault__particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
}

.crystal-vault__particle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--s, 3px);
  height: var(--s, 3px);
  margin: calc(var(--s, 3px) / -2) 0 0 calc(var(--s, 3px) / -2);
  border-radius: 50%;
  background: var(--c-light);
  box-shadow: 0 0 8px var(--c-light), 0 0 14px var(--c-glow);
  transform: rotate(var(--a)) translateX(var(--r));
  animation: vault-particle var(--dur) linear infinite;
  animation-delay: var(--delay);
  opacity: 0.85;
}

@keyframes vault-particle {
  0%   { transform: rotate(var(--a))                translateX(var(--r)) scale(0.6); opacity: 0; }
  10%  {                                                                              opacity: 0.95; }
  50%  { transform: rotate(calc(var(--a) + 180deg)) translateX(var(--r)) scale(1);   }
  90%  {                                                                              opacity: 0.95; }
  100% { transform: rotate(calc(var(--a) + 360deg)) translateX(var(--r)) scale(0.6); opacity: 0; }
}

/* ============================================================
   RIGHT COLUMN · the relic card (project info as MTG-style art)
   ============================================================ */

.relic-card {
  position: relative;
  z-index: 3;
  width: 100%;
  aspect-ratio: 63 / 88; /* classic MTG card proportions */
  max-height: 86vh;
  isolation: isolate;
  opacity: 0;
  filter: drop-shadow(0 18px 38px rgba(0, 0, 0, 0.55));
  contain: layout style;
}

/* Summon runs on the outer card; float runs on the inner frame so
   two keyframes never fight over the same transform property. */
.crystal-vault.is-open .relic-card {
  animation: relic-card-summon 0.55s var(--ease-out) both;
}

.crystal-vault.is-open .relic-card__frame {
  animation: relic-card-float 7s ease-in-out 0.55s infinite;
  will-change: transform;
}

@keyframes relic-card-summon {
  0%   { transform: translateX(16px); opacity: 0; }
  100% { transform: translateX(0);    opacity: 1; }
}

@keyframes relic-card-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

/* Outer rarity-tinted aura that bleeds out from behind the card */
.relic-card__aura {
  position: absolute;
  inset: -14%;
  z-index: 0;
  border-radius: 24px;
  background:
    radial-gradient(ellipse 70% 65% at 50% 50%, var(--c-glow) 0%, transparent 65%),
    radial-gradient(ellipse 55% 80% at 50% 100%, color-mix(in srgb, var(--c-mid) 50%, transparent) 0%, transparent 70%);
  filter: blur(38px);
  opacity: 0.78;
  animation: relic-aura-pulse 5s ease-in-out infinite;
  pointer-events: none;
}

@keyframes relic-aura-pulse {
  0%, 100% { opacity: 0.62; transform: scale(1); }
  50%      { opacity: 0.88; transform: scale(1.04); }
}

/* The frame is the card body — antique gold ring + dark vellum inner.
   Achieved with a triple-layer background (border-box gradient for the
   outer gold ring, padding-box gradient for the inner card body, plus
   inset emboss highlights). */
.relic-card__frame {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  padding: clamp(10px, 2.4vmin, 18px);
  border-radius: 14px;
  display: grid;
  /* Rows: art (large) · typeline · title · textbox · footer */
  grid-template-rows: minmax(0, 1fr) auto auto minmax(0, 1.05fr) auto;
  gap: clamp(6px, 1.2vmin, 12px);
  /* Outer antique-gold ring composited via dual backgrounds. */
  background:
    /* Inner card body (dark grimoire leather) */
    linear-gradient(180deg,
      #1B130A 0%,
      #120A04 45%,
      #0C0602 100%) padding-box,
    /* Outer ring: bronze gradient with highlights */
    linear-gradient(135deg,
      var(--gold-frame-deep) 0%,
      var(--gold-frame) 22%,
      var(--gold-frame-bright) 38%,
      var(--gold-frame) 55%,
      var(--gold-frame-deep) 72%,
      var(--gold-frame) 86%,
      var(--gold-frame-bright) 100%) border-box;
  border: 4px solid transparent;
  box-shadow:
    /* Inset emboss: bright top edge + dark bottom edge */
    inset 0 0 0 1px var(--gold-emboss-hi),
    inset 0 0 0 2px var(--gold-emboss-lo),
    /* Rarity halo bleed */
    0 0 32px color-mix(in srgb, var(--c-glow) 35%, transparent),
    /* Card weight + depth */
    0 28px 60px rgba(0, 0, 0, 0.6);
}

/* ------------------------------------------------------------------ *
 *  TOP ART · illuminated illustration with bronze frame
 * ------------------------------------------------------------------ */
.relic-card__art {
  position: relative;
  margin: 0;
  border-radius: 8px;
  overflow: hidden;
  isolation: isolate;
  background:
    radial-gradient(circle at 30% 30%, color-mix(in srgb, var(--c-mid) 40%, transparent) 0%, transparent 60%),
    linear-gradient(180deg, #2A1F12 0%, #110A04 100%);
  /* Bronze inner frame */
  box-shadow:
    inset 0 0 0 1px var(--gold-emboss-lo),
    inset 0 0 0 2px var(--gold-frame),
    inset 0 0 0 3px var(--gold-emboss-hi),
    inset 0 14px 28px rgba(0, 0, 0, 0.45);
}

.relic-card__art-inner,
.relic-card__art-inner img,
.relic-card__art-inner .crystal-vault__shot-fallback {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

/* Sepia + rarity-tinted overlay on the artwork so every illustration
   reads as part of the same illuminated manuscript. */
.relic-card__art-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 90% 70% at 50% 40%, transparent 35%, rgba(20, 12, 4, 0.55) 100%),
    linear-gradient(180deg, transparent 55%, rgba(8, 4, 1, 0.45) 100%),
    radial-gradient(ellipse 65% 55% at 50% 20%, color-mix(in srgb, var(--c-glow) 35%, transparent) 0%, transparent 70%);
  mix-blend-mode: multiply;
  z-index: 2;
}

/* Floating sigil in the upper-right of the art frame */
.relic-card__art-sigil {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  color: var(--gold-frame-bright);
  z-index: 3;
  filter:
    drop-shadow(0 0 4px rgba(0, 0, 0, 0.85))
    drop-shadow(0 0 10px var(--c-glow));
  animation: relic-sigil-shimmer 4s ease-in-out infinite;
}

@keyframes relic-sigil-shimmer {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.08); }
}

.crystal-vault__shot-fallback {
  display: grid;
  place-items: center;
  padding: 1rem;
  text-align: center;
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: 0.06em;
  color: var(--gold-frame-bright);
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--c-mid) 38%, transparent) 0%, color-mix(in srgb, var(--c-dark) 70%, transparent) 100%),
    radial-gradient(circle at 30% 30%, var(--c-glow) 0%, transparent 60%);
}

/* ------------------------------------------------------------------ *
 *  TYPELINE · "Relíquia · Sistema Web · Lendário"
 * ------------------------------------------------------------------ */
.relic-card__typeline {
  margin: 0;
  padding: 0.3rem 0.6rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4em;
  font-family: var(--font-mono);
  font-size: clamp(0.56rem, 1.55vmin, 0.7rem);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #E8D29E;
  background:
    linear-gradient(180deg, rgba(60, 38, 12, 0.85) 0%, rgba(28, 16, 6, 0.85) 100%);
  border: 1px solid var(--gold-frame);
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 var(--gold-emboss-hi),
    inset 0 -1px 0 rgba(0, 0, 0, 0.6);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.85);
}

.relic-card__typeline-prefix { color: #F0D38C; font-weight: 600; }
.relic-card__typeline-sep    { opacity: 0.55; }
.relic-card__typeline-type   { color: #E5BEAE; }
.relic-card__typeline-rarity {
  color: var(--c-light);
  font-weight: 700;
  letter-spacing: 0.28em;
}

/* ------------------------------------------------------------------ *
 *  TITLE PLATE · embossed name block with flourishes
 * ------------------------------------------------------------------ */
.relic-card__title-plate {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.55rem;
  padding: 0.4rem 0.8rem 0.55rem;
  background:
    linear-gradient(180deg,
      rgba(70, 46, 18, 0.9) 0%,
      rgba(32, 20, 8, 0.92) 60%,
      rgba(18, 10, 4, 0.95) 100%);
  border: 1px solid var(--gold-frame);
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 var(--gold-emboss-hi),
    inset 0 -1px 0 rgba(0, 0, 0, 0.6),
    0 1px 0 var(--gold-emboss-lo);
}

.relic-card__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1rem, 2.6vmin, 1.55rem);
  line-height: 1.05;
  text-align: center;
  letter-spacing: 0.005em;
  color: #FFE6B0;
  background: linear-gradient(180deg, #FFEFC9 0%, #E5BC74 65%, #B68340 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.6),
    0 0 12px color-mix(in srgb, var(--c-glow) 60%, transparent);
  filter: drop-shadow(0 1px 0 var(--gold-emboss-lo));
}

.relic-card__title-flourish {
  width: 14px;
  height: 1.5px;
  background: linear-gradient(90deg, transparent, var(--gold-frame-bright), transparent);
  opacity: 0.85;
}
.relic-card__title-flourish--l { background: linear-gradient(90deg, transparent, var(--gold-frame-bright)); }
.relic-card__title-flourish--r { background: linear-gradient(90deg, var(--gold-frame-bright), transparent); }

/* ------------------------------------------------------------------ *
 *  TEXTBOX · flavour description + sigils
 * ------------------------------------------------------------------ */
.relic-card__textbox {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.7rem 0.85rem 0.75rem;
  background:
    /* Vellum on dark — subtle aged paper sandwiched inside the leather. */
    linear-gradient(180deg,
      #E6D29A 0%,
      #D4BC80 100%);
  border: 1px solid var(--gold-frame);
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 rgba(255, 240, 200, 0.55),
    inset 0 -1px 0 rgba(40, 22, 8, 0.55),
    inset 0 0 18px rgba(120, 80, 30, 0.12);
  overflow: hidden;
}

.relic-card__desc {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(0.78rem, 1.85vmin, 0.92rem);
  line-height: 1.42;
  color: var(--ink-card);
  font-style: italic;
  letter-spacing: 0.005em;
  /* Subtle ink-bleed so letters feel inked onto vellum */
  text-shadow: 0 0 0.3px rgba(31, 20, 8, 0.85);
  /* Cap to 4-5 lines as per the brief */
  display: -webkit-box;
  -webkit-line-clamp: 5;
          line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.relic-card__tags {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.relic-card__tag {
  padding: 0.22rem 0.5rem;
  font-family: var(--font-mono);
  font-size: clamp(0.52rem, 1.35vmin, 0.62rem);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #2A1D0E;
  background:
    linear-gradient(180deg, rgba(255, 235, 180, 0.95) 0%, rgba(200, 170, 110, 0.95) 100%);
  border: 1px solid var(--gold-frame-deep);
  border-radius: 999px;
  box-shadow:
    inset 0 1px 0 rgba(255, 245, 200, 0.6),
    inset 0 -1px 0 rgba(60, 35, 10, 0.35);
  opacity: 0;
  animation: relic-tag-appear 0.55s var(--ease-out) forwards;
  animation-delay: calc(0.6s + var(--i, 0) * 0.07s);
  white-space: nowrap;
}

@keyframes relic-tag-appear {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ------------------------------------------------------------------ *
 *  FOOTER · wax-seal "Open Artifact" CTA
 * ------------------------------------------------------------------ */
.relic-card__footer {
  display: grid;
  place-items: center;
  padding: 0.15rem 0 0.05rem;
}

.relic-card__seal {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1.4rem;
  font-family: var(--font-display);
  font-size: clamp(0.72rem, 1.7vmin, 0.85rem);
  letter-spacing: 0.32em;
  text-transform: uppercase;
  font-weight: 600;
  color: #FFE6A8;
  text-decoration: none;
  background:
    radial-gradient(circle at 30% 28%,
      color-mix(in srgb, var(--c-light) 55%, #6B1818) 0%,
      var(--c-dark) 55%,
      #2A0A04 100%);
  border: 1.5px solid var(--gold-frame);
  border-radius: 999px;
  box-shadow:
    inset 0 1px 0 var(--gold-emboss-hi),
    inset 0 -2px 4px rgba(0, 0, 0, 0.55),
    inset 0 0 16px color-mix(in srgb, var(--c-glow) 25%, transparent),
    0 4px 14px rgba(0, 0, 0, 0.6),
    0 0 18px color-mix(in srgb, var(--c-glow) 45%, transparent);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8);
  transition:
    transform var(--duration-fast) var(--ease-out),
    background var(--duration-med),
    box-shadow var(--duration-med),
    color var(--duration-fast);
}

.relic-card__seal::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: inherit;
  background:
    conic-gradient(from 0deg,
      transparent 0deg,
      var(--gold-frame-bright) 60deg,
      transparent 120deg,
      transparent 240deg,
      var(--gold-frame-bright) 300deg,
      transparent 360deg);
  filter: blur(8px);
  opacity: 0;
  z-index: -1;
  transition: opacity 0.4s;
}

.relic-card__seal:hover,
.relic-card__seal:focus-visible {
  transform: translateY(-1px) scale(1.02);
  background:
    radial-gradient(circle at 30% 28%,
      color-mix(in srgb, var(--c-light) 70%, #8A2020) 0%,
      var(--c-dark) 55%,
      #3A0E08 100%);
  border-color: var(--gold-frame-bright);
  color: #FFF1C9;
  box-shadow:
    inset 0 1px 0 var(--gold-emboss-hi),
    inset 0 -2px 4px rgba(0, 0, 0, 0.55),
    inset 0 0 22px color-mix(in srgb, var(--c-glow) 45%, transparent),
    0 6px 18px rgba(0, 0, 0, 0.7),
    0 0 28px color-mix(in srgb, var(--c-glow) 70%, transparent);
  outline: none;
}

.relic-card__seal:hover::before,
.relic-card__seal:focus-visible::before {
  opacity: 0.75;
  animation: relic-seal-spin 6s linear infinite;
}

@keyframes relic-seal-spin {
  to { transform: rotate(360deg); }
}

.relic-card__seal-glyph {
  display: grid;
  place-items: center;
  color: var(--gold-frame-bright);
  filter: drop-shadow(0 0 6px var(--gold-frame-bright));
}

/* ------------------------------------------------------------------ *
 *  CORNER ORNAMENTS · L-shaped gold filigree on every corner
 * ------------------------------------------------------------------ */
.relic-card__corner {
  position: absolute;
  width: 24px;
  height: 24px;
  pointer-events: none;
  z-index: 4;
  background:
    linear-gradient(135deg,
      var(--gold-frame-bright) 0%,
      var(--gold-frame) 50%,
      var(--gold-frame-deep) 100%);
  -webkit-mask:
    linear-gradient(#000, #000) padding-box,
    linear-gradient(#000, #000);
          mask:
    linear-gradient(#000, #000) padding-box,
    linear-gradient(#000, #000);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  border: 2px solid transparent;
}
.relic-card__corner--tl { top: 4px;    left: 4px;    border-right: 0; border-bottom: 0; }
.relic-card__corner--tr { top: 4px;    right: 4px;   border-left:  0; border-bottom: 0; }
.relic-card__corner--bl { bottom: 4px; left: 4px;    border-right: 0; border-top:    0; }
.relic-card__corner--br { bottom: 4px; right: 4px;   border-left:  0; border-top:    0; }

/* ------------------------------------------------------------------ *
 *  RARITY VARIANTS · subtle frame tweaks per tier
 * ------------------------------------------------------------------ */
.crystal-vault__stage[data-rarity="legendary"] .relic-card__frame {
  /* Maxed-out gold frame with extra magenta-gold bloom */
  background:
    linear-gradient(180deg, #1F1408 0%, #100702 100%) padding-box,
    linear-gradient(135deg,
      #5C3E16 0%,
      #C99E55 18%,
      #FFE294 38%,
      #C99E55 58%,
      #6E4C1E 78%,
      #FFE294 100%) border-box;
  box-shadow:
    inset 0 0 0 1px var(--gold-emboss-hi),
    inset 0 0 0 2px var(--gold-emboss-lo),
    0 0 48px color-mix(in srgb, var(--c-glow) 55%, transparent),
    0 28px 70px rgba(0, 0, 0, 0.65);
}
.crystal-vault__stage[data-rarity="legendary"] .relic-card__typeline-rarity {
  color: #FFE294;
  text-shadow: 0 0 8px #FFE294;
}

.crystal-vault__stage[data-rarity="epic"] .relic-card__frame {
  background:
    linear-gradient(180deg, #1A0E1A 0%, #0C0410 100%) padding-box,
    linear-gradient(135deg,
      #4A1F58 0%,
      #B07EE8 30%,
      #E2B6FF 50%,
      #8A4FB5 70%,
      #4A1F58 100%) border-box;
  box-shadow:
    inset 0 0 0 1px rgba(230, 200, 255, 0.55),
    inset 0 0 0 2px rgba(50, 18, 70, 0.85),
    0 0 36px color-mix(in srgb, var(--c-glow) 50%, transparent),
    0 28px 60px rgba(0, 0, 0, 0.6);
}

.crystal-vault__stage[data-rarity="rare"] .relic-card__frame {
  background:
    linear-gradient(180deg, #0A101A 0%, #03060E 100%) padding-box,
    linear-gradient(135deg,
      #1E3858 0%,
      #6B9FD4 30%,
      #B6D5F0 50%,
      #4F7AAE 70%,
      #1E3858 100%) border-box;
  box-shadow:
    inset 0 0 0 1px rgba(200, 224, 255, 0.55),
    inset 0 0 0 2px rgba(20, 38, 70, 0.85),
    0 0 32px color-mix(in srgb, var(--c-glow) 45%, transparent),
    0 28px 56px rgba(0, 0, 0, 0.6);
}

/* ------------------------------------------------------------------ *
 *  REDUCED MOTION
 * ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .relic-card,
  .relic-card__frame,
  .relic-card__aura,
  .relic-card__art-sigil,
  .crystal-vault__particle,
  .crystal-vault__halo,
  .crystal-vault__gem,
  .relic-card__tag,
  .relic-card__seal::before {
    animation: none !important;
  }
  .relic-card,
  .relic-card__frame { transform: none; }
  .relic-card { opacity: 1; }
  .relic-card__tag { opacity: 1; }
}

/* ============================================================
   PORTAL
   ============================================================ */

.portal {
  position: relative;
  z-index: var(--z-content);
  padding: var(--space-xl) var(--margin-safe) var(--space-lg);
  max-width: var(--container-max);
  margin: 0 auto;
}

.portal .section-head {
  padding: 1rem 1.25rem;
  background: transparent;
  border: none;
  border-radius: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
.portal .section-head__title,
.portal .section-head__lede,
.portal .section-head__eyebrow {
  text-shadow:
    0 0 28px rgba(9, 22, 9, 0.85),
    0 1px 2px rgba(0, 0, 0, 0.75);
}

.portal__stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 480px;
}

/* DEPTH BACKDROP · a deep-space radial seat behind the galaxy
   canvas. Warm amber heart fading through violet into the void —
   gives the portal somewhere to "open from" and reinforces the
   tunnel depth without adding a visible box. Sits at the very
   back (below the canvas) and never blocks pointer events. */
.portal__stage::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(680px, 104vw);
  height: min(680px, 104vw);
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(circle at 50% 50%,
      rgba(255, 228, 170, 0.1) 0%,
      rgba(120, 80, 170, 0.12) 30%,
      rgba(70, 44, 120, 0.1) 55%,
      rgba(20, 12, 30, 0.0) 78%);
  mix-blend-mode: screen;
}

#portal-canvas {
  position: absolute;
  z-index: 1;                       /* the galaxy itself */
  width: min(560px, 92vw);
  height: min(560px, 92vw);
  border-radius: 50%;
  /* A soft outer aura so the canvas edge melts into the section
     instead of ending on a hard circular cut. */
  filter: drop-shadow(0 0 26px rgba(120, 80, 170, 0.22));
}

/* ─────────────────────────────────────────────────────────────
   PORTAL · two regional columns (June 2026 restructure)
   ─────────────────────────────────────────────────────────────
   Each column is a persona + region: the Atlantic column groups
   Carlos's channels for Portugal · Brasil · Irlanda, and the
   Iberian column groups Raquel's channels for Galicia · España.
   Each column carries its own small flag row, ceremonial title
   and accent colour (driven by data-region on .portal__column).
   The cards themselves stay minimalist — just the channel name
   centred on a narrow plate. */
.portal__columns {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(2, minmax(190px, 220px));
  gap: 2.2rem;
  width: min(560px, 92vw);
  margin: 0 auto;
  justify-content: center;
  align-items: start;
}

.portal__column {
  display: flex;
  flex-direction: column;
  gap: 0.95rem;
  /* Region-tinted glow channel — consumed by .portal__link::before
     so the mystical aura on hover takes the column's hue. */
  --col-glow: rgba(229, 190, 174, 0.6);
  --col-accent: var(--gold);
}

/* COLUMN HEAD · stacked flags + ceremonial title + hairline rule */
.portal__column-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
}
.portal__column-flags {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55));
}
.portal__flag {
  width: 26px;
  height: auto;
  border-radius: 2px;
  outline: 1px solid rgba(255, 245, 200, 0.25);
  outline-offset: -1px;
  background: rgba(0, 0, 0, 0.15);
  transition: transform 0.4s cubic-bezier(.16, 1, .3, 1), filter 0.4s ease;
}
.portal__column:hover .portal__flag {
  transform: translateY(-1px);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.55))
          drop-shadow(0 0 6px color-mix(in srgb, var(--col-accent) 60%, transparent));
}
.portal__column-title {
  font-family: var(--font-display);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--col-accent);
  margin: 0;
  line-height: 1.35;
  max-width: 200px;
  /* Reserve the height of THREE lines so both regional titles
     (the longer Atlantic one wraps to 3 lines, the shorter Iberian
     to 2) occupy the same vertical box. The shorter title centres
     inside the reserved space so the hairline rule below — and
     consequently the cards below the rule — line up perfectly
     across columns. (Pre-fix the Iberian cards sat 16px higher.) */
  min-height: calc(1.35em * 3);
  display: flex;
  align-items: center;
  justify-content: center;
  text-shadow:
    0 0 12px color-mix(in srgb, var(--col-accent) 35%, transparent),
    0 0 24px rgba(9, 22, 9, 0.9),
    0 1px 2px rgba(0, 0, 0, 0.75);
}
.portal__column-rule {
  display: block;
  width: 60%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--col-accent) 80%, transparent) 50%,
    transparent 100%);
  opacity: 0.7;
}

/* REGION TINTS · scoped colour identity per persona/region.
   The values are intentionally muted so the codex/arcane mood
   stays dominant; they read as accents, not brand colours. */
.portal__column[data-region="atlantic"] {
  --col-accent: #6DC58B;                       /* PT/BR/IE green */
  --col-glow: rgba(110, 200, 140, 0.65);
}
.portal__column[data-region="iberian"] {
  --col-accent: #E9B042;                       /* GL/ES warm amber-gold */
  --col-glow: rgba(233, 176, 66, 0.66);
}

.portal__links {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
}
.portal__links > li {
  list-style: none;
  display: block;
}

.portal__link {
  position: relative;
  display: flex;
  align-items: center;
  /* Center the icon + label horizontally now that the destination
     handle was removed (June 2026 — minimalist labels). The card
     is now narrow (≤220px) so the name reads at the optical
     centre rather than drifting left against empty space. */
  justify-content: center;
  gap: 0.65rem;
  padding: 0.6rem 0.95rem;
  width: 100%;
  background: var(--glass-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  isolation: isolate;
  transform-origin: center;
  will-change: transform, box-shadow;
  /* Channel-level tint is overridden by the column-level --col-glow
     when present (each column paints its own halo). Default falls
     back to the warm cream tone. */
  --channel-glow: var(--col-glow, rgba(229, 190, 174, 0.62));
  /* Resting glow — each of the contact cards now carries a soft,
     always-on halo in its region's hue so the six boxes read as lit
     runes at rest, not flat plates. Static (no animation); hover
     intensifies it below. */
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--channel-glow) 22%, transparent),
    0 0 18px color-mix(in srgb, var(--channel-glow) 26%, transparent),
    0 6px 16px rgba(0, 0, 0, 0.30);
  transition:
    transform 0.5s cubic-bezier(.16, 1, .3, 1),
    border-color 0.35s ease,
    box-shadow 0.5s ease,
    background-color 0.45s ease;
}

/* MYSTICAL AURA · the growing halo that blooms behind each
   card on hover. It sits on a z-index BELOW the card content
   (z-index: -1 inside the isolating context) so the text is
   never obscured. Idle = invisible & shrunken; on hover it
   expands, brightens and starts breathing. */
.portal__link::before {
  content: "";
  position: absolute;
  inset: -16px;
  border-radius: calc(var(--radius-md) + 14px);
  background: radial-gradient(circle at 50% 50%,
    var(--channel-glow) 0%,
    color-mix(in srgb, var(--channel-glow) 35%, transparent) 38%,
    transparent 72%);
  opacity: 0;
  transform: scale(0.78);
  filter: blur(10px);
  pointer-events: none;
  z-index: -1;
  transition:
    opacity 0.55s ease,
    transform 0.7s cubic-bezier(.16, 1, .3, 1),
    filter 0.55s ease;
}

/* INNER SHEEN · a second pseudo paints a hairline gold halo
   tight to the border (no blur) so the card edge crisply
   ignites on hover, complementing the soft aura below. */
.portal__link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--channel-glow) 0%, transparent),
    inset 0 0 0 0 transparent;
  transition: box-shadow 0.45s ease;
  z-index: 0;
}

.portal__link:hover,
.portal__link:focus-visible {
  border-color: color-mix(in srgb, var(--channel-glow) 90%, var(--gold) 10%);
  transform: scale(1.06);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--channel-glow) 55%, transparent),
    0 14px 38px color-mix(in srgb, var(--channel-glow) 38%, transparent),
    0 4px 14px rgba(0, 0, 0, 0.35);
  outline: none;
}
.portal__link:hover::before,
.portal__link:focus-visible::before {
  opacity: 0.95;
  transform: scale(1.18);
  filter: blur(14px);
  animation: portal-glow-breathe 2.6s ease-in-out infinite;
}
.portal__link:hover::after,
.portal__link:focus-visible::after {
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--channel-glow) 70%, transparent),
    inset 0 0 18px color-mix(in srgb, var(--channel-glow) 22%, transparent);
}

/* Breathing keyframe — the aura inhales/exhales while the
   pointer rests on a card, giving the "alive portal" feel. */
@keyframes portal-glow-breathe {
  0%, 100% {
    opacity: 0.80;
    transform: scale(1.14);
    filter: blur(12px);
  }
  50% {
    opacity: 1;
    transform: scale(1.26);
    filter: blur(18px);
  }
}

/* Per-channel chromatic identity REMOVED (June 2026 restructure).
   Card glow is now driven by the column's --col-glow so the
   Atlantic column reads green and the Iberian column reads gold,
   regardless of which channel the card represents. The selectors
   are kept here as no-ops in case a future redesign reintroduces
   per-channel hues. */

.portal__link svg {
  color: var(--gold);
  flex-shrink: 0;
  transition: color 0.4s ease, transform 0.5s cubic-bezier(.16, 1, .3, 1);
}
.portal__link:hover svg,
.portal__link:focus-visible svg {
  color: color-mix(in srgb, var(--channel-glow) 75%, var(--gold) 25%);
  transform: scale(1.08);
}

.portal__link-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--primary);
  /* flex: 1 removed — there is no longer a second column (handle)
     to push the label against; centring is handled by the parent
     .portal__link's justify-content. */
  position: relative;
  z-index: 1;
}

/* Handle rule kept for backwards compatibility — if a future edit
   reintroduces the span it will render correctly. The element is
   not present in markup at the moment. */
.portal__link-handle {
  font-size: 0.75rem;
  color: var(--on-surface-muted);
  position: relative;
  z-index: 1;
}

/* Honour reduced-motion — keep the static glow halo (it never
   moves) but freeze the breathing animation and shorten the
   transform so the card simply brightens on hover. */
@media (prefers-reduced-motion: reduce) {
  .portal__link,
  .portal__link::before,
  .portal__link::after,
  .portal__link svg {
    transition-duration: 0.2s;
  }
  .portal__link:hover,
  .portal__link:focus-visible {
    transform: none;
  }
  .portal__link:hover::before,
  .portal__link:focus-visible::before {
    animation: none;
    transform: scale(1.1);
  }
}

/* ── TOUCH DEVICES · hover never fires ────────────────────────
   On phones/tablets there is no pointer hover, so the portal
   cards would otherwise sit completely inert — the mystical aura,
   border ignition and icon tint (all hover-only above) never show.
   Here we light each card with a gentle RESTING glow so it reads
   as a living portal at a glance, and intensify it on :active
   (the moment of a tap) to mirror the desktop hover feedback. */
@media (hover: none) {
  .portal__link {
    border-color: color-mix(in srgb, var(--channel-glow) 60%, var(--glass-border) 40%);
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--channel-glow) 30%, transparent),
      0 8px 22px color-mix(in srgb, var(--channel-glow) 20%, transparent),
      0 3px 10px rgba(0, 0, 0, 0.3);
  }
  /* Soft aura always present, breathing slowly so the card feels alive. */
  .portal__link::before {
    opacity: 0.6;
    transform: scale(1.08);
    filter: blur(12px);
    animation: portal-glow-breathe 3.4s ease-in-out infinite;
  }
  /* Hairline inner sheen lit at rest. */
  .portal__link::after {
    box-shadow:
      inset 0 0 0 1px color-mix(in srgb, var(--channel-glow) 45%, transparent),
      inset 0 0 14px color-mix(in srgb, var(--channel-glow) 14%, transparent);
  }
  .portal__link svg {
    color: color-mix(in srgb, var(--channel-glow) 55%, var(--gold) 45%);
  }
  /* Tap feedback — flare brighter, like the desktop hover peak. */
  .portal__link:active {
    border-color: color-mix(in srgb, var(--channel-glow) 90%, var(--gold) 10%);
    transform: scale(1.04);
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--channel-glow) 60%, transparent),
      0 14px 36px color-mix(in srgb, var(--channel-glow) 42%, transparent),
      0 4px 14px rgba(0, 0, 0, 0.35);
  }
  .portal__link:active::before {
    opacity: 1;
    transform: scale(1.22);
    filter: blur(16px);
  }
  .portal__link:active::after {
    box-shadow:
      inset 0 0 0 1px color-mix(in srgb, var(--channel-glow) 75%, transparent),
      inset 0 0 20px color-mix(in srgb, var(--channel-glow) 26%, transparent);
  }
  .portal__link:active svg {
    color: color-mix(in srgb, var(--channel-glow) 80%, var(--gold) 20%);
    transform: scale(1.06);
  }
  /* Touch + reduced-motion: keep the resting glow but stop breathing. */
  @media (prefers-reduced-motion: reduce) {
    .portal__link::before { animation: none; }
  }
}

/* ============================================================
   DOMÍNIOS EM EXPANSÃO · ambient right-rail artefact
   ----------------------------------------------------------------
   A discreet inscription pinned to the right edge, vertically
   centred. Reads as a fragment of the Arquivo Arcano: dark
   parchment-glass, bronze double-frame, gold Cinzel title.
   Knowledge bars breathe slowly between two widths (continuous
   growth — never a fixed level, never empty) and are crossed by a
   2000s-style luminous load sweep. Active skills carry slow
   pulsing gold embers. No percentages, no numeric levels.
   Controller: src/js/domains.js
   ============================================================ */
.domains {
  position: fixed;
  bottom: 18px;
  right: 18px;
  top: auto;
  transform: none;
  z-index: var(--z-domains);
  display: flex;
  align-items: flex-end;
  gap: 0;
  pointer-events: none;            /* only the panel/handle are live */
  /* Quiet entrance — drift in from the right once, then hold. */
  animation: domains-enter 1.1s cubic-bezier(.16, 1, .3, 1) 0.9s both;
  transition: opacity 0.4s var(--ease-out), filter 0.4s var(--ease-out);
}
@keyframes domains-enter {
  from { opacity: 0; transform: translateX(26px); }
  to   { opacity: 1; transform: translateX(0);    }
}

/* ── PANEL ─────────────────────────────────────────────────── */
.domains__panel {
  position: relative;
  width: 212px;
  padding: 0.78rem 0.85rem 0.82rem;
  border-radius: 11px;
  pointer-events: auto;
  /* Dark parchment-glass — warm, low, never glossy. */
  background:
    linear-gradient(158deg,
      rgba(28, 40, 28, 0.82) 0%,
      rgba(12, 20, 12, 0.78) 60%,
      rgba(9, 16, 9, 0.8) 100%);
  backdrop-filter: blur(9px) saturate(1.04);
  -webkit-backdrop-filter: blur(9px) saturate(1.04);
  /* Aged-gold artefact edge so the panel belongs to the same arcane
     manuscript family as the rest of the page (was a flat widget). */
  border: 1px solid rgba(201, 161, 95, 0.42);
  box-shadow:
    0 20px 44px rgba(0, 0, 0, 0.42),
    inset 0 0 0 1px rgba(242, 200, 121, 0.08),
    inset 0 1px 0 rgba(242, 200, 121, 0.12),
    inset 0 0 24px rgba(201, 161, 95, 0.06);
  /* Discreet at rest, full presence on hover/focus. */
  opacity: 0.62;
  transition:
    opacity 0.5s var(--ease-out),
    transform 0.55s cubic-bezier(.5, 0, .25, 1);
}
.domains:hover .domains__panel,
.domains:focus-within .domains__panel {
  opacity: 1;
}

/* Inner bronze double-frame — the "ancient artefact" edge. */
.domains__frame {
  position: absolute;
  inset: 6px;
  border: 1px solid rgba(201, 161, 95, 0.28);
  border-radius: 7px;
  pointer-events: none;
}
.domains__frame::before,
.domains__frame::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 1.5px solid rgba(242, 200, 121, 0.6);
}
.domains__frame::before { top: -1px;  left: -1px;  border-right: 0; border-bottom: 0; }
.domains__frame::after  { bottom: -1px; right: -1px; border-left: 0;  border-top: 0;  }

/* ── HEADER ────────────────────────────────────────────────── */
.domains__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.3rem;
  margin-bottom: 0.6rem;
}
.domains__head--sub {
  margin-top: 0.7rem;
  margin-bottom: 0.5rem;
}
.domains__sigil {
  color: var(--gold);
  line-height: 0;
  filter: drop-shadow(0 0 6px rgba(242, 200, 121, 0.18));
  animation: domains-sigil-turn 48s linear infinite;
}
@keyframes domains-sigil-turn {
  from { transform: rotate(0deg);   }
  to   { transform: rotate(360deg); }
}
.domains__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.25;
  color: var(--gold-burning);
  text-shadow:
    0 0 14px rgba(242, 200, 121, 0.22),
    0 1px 2px rgba(0, 0, 0, 0.7);
}
/* Runic flourish flanking the title — ties the panel to the rune
   language used across the codex and contracts. */
.domains__title::before,
.domains__title::after {
  content: "ᛟ";
  margin: 0 0.45em;
  font-size: 0.62em;
  color: var(--gold-aged);
  opacity: 0.7;
  vertical-align: middle;
}
.domains__subtitle {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-aged);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}
.domains__rule {
  display: block;
  width: 64%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(242, 200, 121, 0.55) 50%,
    transparent 100%);
  opacity: 0.7;
}

/* ── TECH KNOWLEDGE BARS ───────────────────────────────────── */
.domains__techs,
.domains__skills {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.domains__techs {
  gap: 0.5rem;
  /* Constellation spine — a faint energy line threading the domains
     so the panel reads as a branch of the same central map, not a
     detached widget. */
  position: relative;
  padding-left: 1rem;
}
.domains__techs::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0.5rem;
  bottom: 0.5rem;
  width: 1px;
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(242, 200, 121, 0.45) 18%,
    rgba(168, 85, 247, 0.38) 82%,
    transparent 100%);
  pointer-events: none;
}

.domains__tech {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.26rem;
}
/* luminous node where each domain connects to the spine */
.domains__tech::before {
  content: "";
  position: absolute;
  left: -1rem;
  top: 0.32rem;
  width: 6px;
  height: 6px;
  margin-left: 0.5px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--gold-burning) 0%, var(--gold-aged) 60%, transparent 75%);
  box-shadow: 0 0 6px rgba(242, 200, 121, 0.6);
  transition: box-shadow 0.4s ease, transform 0.4s ease;
}
.domains__tech:hover::before {
  transform: scale(1.4);
  box-shadow:
    0 0 9px rgba(242, 200, 121, 0.9),
    0 0 16px rgba(168, 85, 247, 0.6);
}
.domains__tech-name {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  color: var(--on-surface);
  opacity: 0.9;
}
.domains__bar {
  position: relative;
  display: block;
  height: 6px;
  border-radius: 5px;
  overflow: hidden;
  /* Recessed dark channel — like a groove cut into old bronze. */
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.28));
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.6),
    inset 0 0 0 1px rgba(194, 164, 107, 0.14);
}
.domains__bar-fill {
  position: relative;
  display: block;
  height: 100%;
  width: var(--reach-min, 60%);
  border-radius: 5px;
  /* Bronze → aged gold → volcanic amber molten metal. */
  background: linear-gradient(90deg,
    var(--bronze-old) 0%,
    var(--gold-aged) 55%,
    var(--ember-amber) 100%);
  box-shadow:
    0 0 8px rgba(224, 138, 46, 0.28),
    inset 0 1px 0 rgba(242, 200, 121, 0.35);
  /* Slow continuous "expansion" — breathes between two widths so it
     never reads as a fixed score and never empties. */
  animation: domains-grow var(--grow-dur, 17s) ease-in-out infinite;
}
@keyframes domains-grow {
  0%, 100% { width: var(--reach-min, 60%); }
  50%      { width: var(--reach-max, 90%); }
}
/* 2000s-style luminous load sweep travelling across the fill. */
.domains__bar-sweep {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(100deg,
    transparent 0%,
    rgba(242, 200, 121, 0) 36%,
    rgba(242, 200, 121, 0.6) 50%,
    rgba(242, 200, 121, 0) 64%,
    transparent 100%);
  transform: translateX(-120%);
  animation: domains-sweep var(--sweep-dur, 4.2s) linear infinite;
  animation-delay: var(--sweep-delay, 0s);
}
@keyframes domains-sweep {
  0%        { transform: translateX(-120%); }
  62%, 100% { transform: translateX(220%);  }
}

/* ── ACTIVE SKILLS ─────────────────────────────────────────── */
.domains__skills { gap: 0.32rem; position: relative; }
/* Matching constellation spine running through the skill pulses, so
   both lists in the panel share the central map's connective tissue. */
.domains__skills::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0.5rem;
  bottom: 0.5rem;
  width: 1px;
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(242, 200, 121, 0.4) 18%,
    rgba(168, 85, 247, 0.34) 82%,
    transparent 100%);
  pointer-events: none;
}
.domains__skill {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.domains__pulse {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
    var(--gold-burning) 0%,
    var(--gold-aged) 58%,
    rgba(201, 161, 95, 0) 74%);
  animation: domains-pulse 3.8s ease-in-out infinite;
  animation-delay: var(--pulse-delay, 0s);
}
@keyframes domains-pulse {
  0%, 100% {
    opacity: 0.4;
    transform: scale(0.8);
    box-shadow: 0 0 3px rgba(242, 200, 121, 0.25);
  }
  50% {
    opacity: 1;
    transform: scale(1.05);
    box-shadow: 0 0 9px rgba(242, 200, 121, 0.55);
  }
}
.domains__skill-name {
  font-family: var(--font-body);
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  color: var(--on-surface-variant);
}

/* ── COLLAPSE HANDLE (slim rune tab) ───────────────────────── */
.domains__handle {
  pointer-events: auto;
  display: none;                   /* desktop: hidden, panel always open */
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin-right: 6px;
  padding: 0.7rem 0.35rem;
  border: 1px solid rgba(194, 164, 107, 0.3);
  border-radius: 8px;
  background: linear-gradient(158deg,
    rgba(28, 40, 28, 0.85), rgba(9, 16, 9, 0.82));
  color: var(--gold-aged);
  cursor: pointer;
  transition: color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
}
.domains__handle:hover {
  color: var(--gold-burning);
  border-color: rgba(242, 200, 121, 0.5);
  box-shadow: 0 0 14px rgba(242, 200, 121, 0.18);
}
.domains__handle-rune {
  font-size: 0.85rem;
  line-height: 1;
}
.domains__handle-label {
  font-family: var(--font-display);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  text-orientation: mixed;
}

/* While the Codex or Memory Vault is open, fade the rail entirely
   so it never competes with the focused experience (mirrors the
   Merlin behaviour). */
body.vault-open .domains,
body.is-codex-summoning .domains {
  opacity: 0;
  pointer-events: none;
}

/* ── LIGHT THEME · aged manuscript instead of dark glass ───── */
html[data-theme="light"] .domains__panel {
  background:
    linear-gradient(158deg,
      rgba(244, 232, 205, 0.9) 0%,
      rgba(232, 216, 182, 0.86) 100%);
  border-color: rgba(120, 84, 40, 0.4);
  box-shadow:
    0 18px 40px rgba(74, 45, 20, 0.18),
    inset 0 0 0 1px rgba(120, 84, 40, 0.06);
}
html[data-theme="light"] .domains__frame {
  border-color: rgba(120, 84, 40, 0.22);
}
html[data-theme="light"] .domains__frame::before,
html[data-theme="light"] .domains__frame::after {
  border-color: rgba(120, 84, 40, 0.5);
}
html[data-theme="light"] .domains__title {
  color: #6B3F18;
  text-shadow: 0 1px 0 rgba(255, 248, 215, 0.6);
}
html[data-theme="light"] .domains__subtitle { color: #7A4B1E; }
html[data-theme="light"] .domains__sigil { color: #8B5A1F; }
html[data-theme="light"] .domains__tech-name { color: #3A2410; opacity: 1; }
html[data-theme="light"] .domains__skill-name { color: #4A2E16; }
html[data-theme="light"] .domains__bar {
  background: linear-gradient(180deg, rgba(120, 84, 40, 0.22), rgba(120, 84, 40, 0.12));
  box-shadow:
    inset 0 1px 2px rgba(74, 45, 20, 0.3),
    inset 0 0 0 1px rgba(120, 84, 40, 0.18);
}
html[data-theme="light"] .domains__handle {
  background: linear-gradient(158deg,
    rgba(244, 232, 205, 0.92), rgba(232, 216, 182, 0.88));
  color: #7A4B1E;
  border-color: rgba(120, 84, 40, 0.4);
}

/* ── RESPONSIVE · auto-collapse below 1100px ───────────────── */
@media (max-width: 1100px) {
  /* Anchor the rail to the BOTTOM-LEFT on mobile. Previously it was
     anchored right, but the collapsed panel still reserves its layout
     width (scaleX is visual-only), which pushed the rune tab ~244px
     left of the right edge — landing it near screen centre. Anchoring
     left pins the tab to the lower-left corner; the panel opens to its
     right (drawer-style) and furls back toward the handle.            */
  .domains {
    left: 0;
    right: auto;
    flex-direction: row;
  }
  /* Handle sits at the very left edge; gap now opens toward the panel
     on its right (was margin-right for the old right-anchored layout). */
  .domains__handle { display: flex; margin-right: 6px; }
  /* Collapsed: panel furls toward the handle (left), only the tab shows.
     scaleX(0) collapses it in place — it never crosses a viewport edge,
     so there is no sideways-scroll overflow on mobile. */
  .domains[data-collapsed="true"] .domains__panel {
    transform: scaleX(0);
    transform-origin: left center;
    opacity: 0;
    pointer-events: none;
  }
  /* Expanded by the visitor: full presence (no hover on touch). */
  .domains[data-collapsed="false"] .domains__panel {
    opacity: 1;
  }
  .domains[data-collapsed="false"] .domains__handle {
    border-color: rgba(242, 200, 121, 0.5);
    color: var(--gold-burning);
  }
}
@media (max-width: 480px) {
  .domains__panel { width: min(72vw, 244px); }
}

/* ── REDUCED MOTION · freeze into a calm, readable state ───── */
@media (prefers-reduced-motion: reduce) {
  .domains { animation: none; opacity: 1; transform: none; }
  .domains__sigil { animation: none; }
  .domains__bar-fill {
    animation: none;
    /* Hold at a mid expansion so the bar still reads as "advanced
       and growing", never empty, never a fixed full stop. */
    width: calc((var(--reach-min, 60%) + var(--reach-max, 90%)) / 2);
  }
  .domains__bar-sweep { animation: none; opacity: 0.25; transform: translateX(40%); }
  .domains__pulse { animation: none; opacity: 0.85; }
}

/* ============================================================
   MERLIN · The Living Companion
   ----------------------------------------------------------------
   A small wizard sprite + a parchment speech scroll + a quill
   input. Everything is anchored at one of six teleport spots
   (data-pos on .merlin) and animated as an illuminated medieval
   manuscript come to life. Controller: src/js/merlin.js
   ============================================================ */
.merlin {
  position: fixed;
  z-index: var(--z-merlin);
  /* Default spot — JS may switch data-pos to one of 6 anchors */
  bottom: 1.25rem;
  right: 1.25rem;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.55rem;
  pointer-events: none;
  /* Anchor properties transition for smooth teleports */
  transition:
    bottom 0.55s cubic-bezier(.5, 0, .25, 1),
    top    0.55s cubic-bezier(.5, 0, .25, 1),
    left   0.55s cubic-bezier(.5, 0, .25, 1),
    right  0.55s cubic-bezier(.5, 0, .25, 1),
    opacity 0.35s ease;
  opacity: 0;
  /* Quill cursor everywhere inside Merlin (sprite, scroll, input)
     — a small inline SVG so we don't ship an extra asset. The
     hotspot (3 24) sits at the ink tip of the feather. */
  cursor:
    url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Cdefs%3E%3ClinearGradient id='qg' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0%25' stop-color='%23F4E8C6'/%3E%3Cstop offset='100%25' stop-color='%23D6B97A'/%3E%3C/linearGradient%3E%3C/defs%3E%3Ccircle cx='4' cy='24' r='1.6' fill='%235D4423'/%3E%3Cpath d='M5 23 L22 7 Q24 5 23.5 3 Q22 2 20 4 L6 22 Z' fill='url(%23qg)' stroke='%235D4423' stroke-width='0.5'/%3E%3Cpath d='M9 19 L18 9' stroke='%235D4423' stroke-width='0.4' opacity='0.55'/%3E%3Cpath d='M11 17 L19 7' stroke='%235D4423' stroke-width='0.3' opacity='0.35'/%3E%3Cpath d='M21 5 L24 3' stroke='%23C2A46B' stroke-width='1' stroke-linecap='round'/%3E%3C/svg%3E") 3 24,
    pointer;
}

.merlin.is-visible { opacity: 1; }

/* Teleport anchors — JS toggles data-pos to switch spots
   without ever covering the upper-left Hero panel.            */
.merlin[data-pos="bottom-right"]  { top: auto; bottom: 1.25rem; right: 1.25rem; left: auto;  align-items: flex-end; }
.merlin[data-pos="bottom-left"]   { top: auto; bottom: 1.25rem; right: auto;    left: 1.25rem; align-items: flex-start; }
/* Resting spot — nestled on the right between the "Dominado" HUD
   (top-right) and the "Domínios em Expansão" panel (bottom-right).
   Bottom-anchored so the speech scroll expands UPWARD into the open
   gap instead of pushing the wizard down onto the domains panel. */
.merlin[data-pos="middle-right"]  { top: auto;  bottom: calc(50% + 26px); right: 1.25rem; left: auto;  align-items: flex-end; }
.merlin[data-pos="middle-left"]   { top: 55%;  bottom: auto;    right: auto;    left: 1.25rem; align-items: flex-start; }
/* Top-right is tucked further down so it doesn't collide with
   the relocated tree-hud panel that now lives at top-right.   */
.merlin[data-pos="top-right"]     { top: 13rem;  bottom: auto;  right: 1.25rem; left: auto;  align-items: flex-end; }
.merlin[data-pos="top-left"]      { top: 5.5rem; bottom: auto;  right: auto;    left: 1.25rem; align-items: flex-start; }

/* When anchored on the left half, mirror the scroll seal so
   the parchment looks like it's being held with the right hand. */
.merlin[data-pos$="-left"] .merlin__scroll { transform-origin: bottom left; }
.merlin[data-pos$="-left"] .merlin__scroll-seal { left: 0.6rem; right: auto; }

/* While the Codex is open or the Memory Vault is open, fade
   Merlin entirely so he doesn't compete with the focused UI. */
body.vault-open .merlin,
body.is-codex-summoning .merlin {
  opacity: 0;
  pointer-events: none;
}

/* ─────────────────────────────────────────────────────────────
   1. WIZARD SPRITE
   ───────────────────────────────────────────────────────────── */
.merlin__avatar {
  position: relative;
  width: 60px;
  height: 71px;
  background: transparent;
  border: 0;
  padding: 0;
  display: inline-flex;
  align-items: flex-end;
  justify-content: center;
  pointer-events: all;
  filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.55));
  outline: none;
}

.merlin__sprite {
  width: 100%;
  height: 100%;
  display: block;
  /* Floating + breathing combined. Subtle 4s loop. */
  animation: merlin-float 4s ease-in-out infinite;
  transform-origin: 50% 90%;
}

@keyframes merlin-float {
  0%, 100% { transform: translateY(0)   scale(1)    rotate(-0.6deg); }
  25%      { transform: translateY(-3px) scale(1.012) rotate(0.4deg); }
  50%      { transform: translateY(-5px) scale(1.02)  rotate(-0.2deg); }
  75%      { transform: translateY(-2px) scale(1.008) rotate(0.6deg); }
}

/* Hat stars twinkle independently */
.merlin__hat-stars circle {
  animation: merlin-twinkle 2.6s ease-in-out infinite;
  transform-origin: center;
  transform-box: fill-box;
}
.merlin__hat-stars circle:nth-child(2) { animation-delay: 0.6s; }
.merlin__hat-stars circle:nth-child(3) { animation-delay: 1.2s; }

@keyframes merlin-twinkle {
  0%, 100% { opacity: 0.4; transform: scale(0.85); }
  50%      { opacity: 1;   transform: scale(1.3); }
}

/* Staff orb pulses */
.merlin__staff-glow {
  transform-origin: 51px 22px;
  animation: merlin-orb 3.2s ease-in-out infinite;
}
@keyframes merlin-orb {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.18); }
}

/* Outer aura — soft golden glow that breathes around the sprite */
.merlin__aura {
  position: absolute;
  inset: -14% -10% 0 -10%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 55%,
    rgba(255, 215, 160, 0.32) 0%,
    rgba(194, 164, 107, 0.18) 35%,
    transparent 70%);
  filter: blur(8px);
  animation: merlin-aura 4s ease-in-out infinite;
  pointer-events: none;
  z-index: -1;
}
@keyframes merlin-aura {
  0%, 100% { opacity: 0.65; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.08); }
}

/* Halo — thin gold ring that swells when reacting (.is-casting) */
.merlin__halo {
  position: absolute;
  inset: 8% 14% 8% 14%;
  border-radius: 50%;
  border: 1px solid rgba(255, 215, 160, 0);
  pointer-events: none;
  transition: border-color 0.4s ease, transform 0.4s ease;
  z-index: -1;
}
.merlin.is-casting .merlin__halo {
  border-color: rgba(255, 215, 160, 0.75);
  transform: scale(1.18);
  animation: merlin-halo-pulse 0.9s ease-out;
}
@keyframes merlin-halo-pulse {
  0%   { transform: scale(0.85); border-width: 2px; border-color: rgba(255, 240, 200, 0.95); }
  60%  { transform: scale(1.22); border-width: 1px; }
  100% { transform: scale(1.45); border-width: 0.5px; border-color: rgba(255, 215, 160, 0); }
}

/* Hover / focus on the wizard */
.merlin__avatar:hover .merlin__sprite,
.merlin__avatar:focus-visible .merlin__sprite {
  animation-play-state: paused;
  transform: translateY(-5px) scale(1.04);
  transition: transform 0.4s var(--ease-out);
}
.merlin__avatar:hover .merlin__aura,
.merlin__avatar:focus-visible .merlin__aura {
  opacity: 1;
  transform: scale(1.15);
}

/* Summon: final-ritual entrance bump (existing behaviour) */
.merlin.is-summoned .merlin__avatar {
  animation: merlin-summon 1.4s var(--ease-out);
}
@keyframes merlin-summon {
  0%   { transform: scale(0.4) translateY(20px); opacity: 0; }
  60%  { transform: scale(1.18) translateY(-4px); }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}

/* Teleport: brief fade-out → spell handled by JS */
.merlin.is-teleporting {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}

/* ─────────────────────────────────────────────────────────────
   1c. RICH MOVEMENT  (glide, spin, staff-wave, fairy trail)
   ─────────────────────────────────────────────────────────────
   Beyond the simple fade-teleport, Merlin can now traverse the
   page with three richer actions:
     · .is-gliding   → smooth point-to-point flight (1.6 s)
     · .is-spinning  → playful 360° rotation in place
     · .is-waving    → tilts the staff arc, releasing sparks
   Each of these is triggered by JS and auto-clears after the
   animation ends. They are layered over the idle floating loop
   via animation-composition (same transform-origin).            */

/* GLIDE — fluid point-to-point flight along an irregular curve.
   JS computes a cubic-Bézier path: the origin offset (--gx, --gy),
   two perpendicular-offset control points (--cx1/--cy1, --cx2/--cy2)
   and a length-aware duration (--gdur). The keyframes below stop
   at those exact control points so the rendered trajectory follows
   the same curve the trail draws. The cubic-bezier easing carries
   gentle acceleration in / deceleration out, which (combined with
   the randomised perpendicular offsets) makes every flight feel
   slightly different and never linear. */
.merlin.is-gliding .merlin__sprite {
  animation: merlin-glide var(--gdur, 2.2s) cubic-bezier(.42, .04, .42, 1) both;
}
@keyframes merlin-glide {
  0%   {
    transform: translate(var(--gx, 0), var(--gy, 0)) scale(0.94) rotate(-2deg);
    opacity: 0.92;
  }
  28%  {
    transform: translate(var(--cx1, 0), var(--cy1, 0)) scale(1.05) rotate(2.5deg);
    opacity: 1;
  }
  62%  {
    transform: translate(var(--cx2, 0), var(--cy2, 0)) scale(1.07) rotate(-2deg);
    opacity: 1;
  }
  86%  {
    transform:
      translate(
        calc(var(--cx2, 0) * 0.32),
        calc(var(--cy2, 0) * 0.32 - 4px)
      )
      scale(1.03) rotate(0.6deg);
  }
  100% { transform: translate(0, 0) scale(1) rotate(0); }
}

/* SPIN — playful 360° (with a tiny upward hop). */
.merlin.is-spinning .merlin__sprite {
  animation: merlin-spin 1.4s cubic-bezier(.5, 0, .25, 1) both;
}
@keyframes merlin-spin {
  0%   { transform: rotate(0)     scale(1)    translateY(0); }
  35%  { transform: rotate(180deg) scale(1.06) translateY(-6px); }
  70%  { transform: rotate(330deg) scale(1.02) translateY(-2px); }
  100% { transform: rotate(360deg) scale(1)    translateY(0); }
}

/* STAFF-WAVE — tilt the whole sprite right while the staff orb
   pulses brighter. Particles are spawned by JS during this time. */
.merlin.is-waving .merlin__sprite {
  animation: merlin-wave 1.3s cubic-bezier(.36, 0, .15, 1) both;
}
@keyframes merlin-wave {
  0%   { transform: rotate(0)    translateY(0); }
  20%  { transform: rotate(8deg) translateY(-3px); }
  40%  { transform: rotate(-6deg) translateY(-1px); }
  60%  { transform: rotate(10deg) translateY(-4px); }
  80%  { transform: rotate(-3deg) translateY(-1px); }
  100% { transform: rotate(0)    translateY(0); }
}
.merlin.is-waving .merlin__staff-glow {
  animation: merlin-staff-flare 1.3s ease-in-out both;
}
@keyframes merlin-staff-flare {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  35%      { opacity: 1;    transform: scale(1.6); filter: brightness(1.5); }
  70%      { opacity: 1;    transform: scale(1.35); filter: brightness(1.3); }
}

/* FAIRY TRAIL — golden motes left along the glide path.
   Each mote is a span with --x / --y coordinates set inline by
   JS at spawn time. The trail container is a fixed-position
   overlay so motes can land anywhere on the viewport. */
.merlin-trail {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 199;             /* below merlin, above content */
}
.merlin-trail__mote {
  position: absolute;
  left: var(--x, 0);
  top:  var(--y, 0);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: radial-gradient(circle,
    #FFF7D8 0%,
    #FFD089 50%,
    rgba(255, 180, 100, 0) 80%);
  box-shadow:
    0 0 8px rgba(255, 230, 170, 0.95),
    0 0 18px rgba(255, 180, 100, 0.65),
    0 0 32px rgba(229, 160, 80, 0.35);
  transform: translate(-50%, -50%) scale(0.4);
  opacity: 0;
  animation: merlin-trail-mote var(--life, 1.2s) ease-out both;
  will-change: transform, opacity;
}
@keyframes merlin-trail-mote {
  0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0.4); }
  20%  { opacity: 0.95; transform: translate(-50%, -50%) scale(1); }
  60%  { opacity: 0.65; transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) scale(0.85); }
  100% { opacity: 0;    transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) scale(0.2); }
}

/* ─────────────────────────────────────────────────────────────
   1d. CURSOR ESCORT  ·  chase + stun
   ─────────────────────────────────────────────────────────────
   While chasing, JS drives the avatar's translate (--cx, --cy) and
   a banking rotation (--crot) every frame so the wizard flies along
   with the live cursor. The float loop keeps running on the inner
   sprite, so he still bobs while in flight. On release (endChase),
   .is-chasing-return transitions the offset smoothly back to the
   resting anchor. A hard mouse-shake adds .is-stunned: a dizzy
   wobble plus three little stars orbiting his hat.               */
.merlin.is-chasing {
  /* Don't let the anchor's position transition fight the per-frame
     transform, and never block clicks while flying over content. */
  transition: opacity 0.35s ease;
  z-index: calc(var(--z-merlin) + 1);
}
.merlin.is-chasing .merlin__avatar {
  transform: translate(var(--cx, 0px), var(--cy, 0px)) rotate(var(--crot, 0deg));
  pointer-events: none;          /* ghostly escort — clicks pass through */
  will-change: transform;
}
.merlin.is-chasing-return .merlin__avatar {
  transition: transform 0.9s cubic-bezier(.34, .02, .2, 1);
}

/* STUN — knocked dizzy: a woozy wobble of the whole sprite. */
.merlin.is-stunned .merlin__sprite {
  animation: merlin-dizzy 0.62s ease-in-out infinite;
}
@keyframes merlin-dizzy {
  0%   { transform: rotate(-9deg) translateY(0); }
  25%  { transform: rotate(6deg)  translateY(1px); }
  50%  { transform: rotate(-7deg) translateY(-1px); }
  75%  { transform: rotate(8deg)  translateY(1px); }
  100% { transform: rotate(-9deg) translateY(0); }
}

/* ── Classic RPG / MMO stun ───────────────────────────────────────
   A flattened halo of little gold stars circling the wizard's hat.
   The orbit is an ELLIPSE (wide, short) so it reads as a ring seen
   in perspective: each star dips to the BACK (small, dim, behind)
   then sweeps to the FRONT (large, bright), twinkling as it spins —
   the cartoon "seeing stars" dizziness everyone recognises. */
.merlin__stun {
  position: absolute;
  left: 50%;
  top: 8px;                 /* orbit centre, just over the hat */
  width: 0;
  height: 0;
  pointer-events: none;
  opacity: 0;
  z-index: 3;
  transition: opacity 0.22s ease;
}
.merlin__stun.is-active { opacity: 1; animation: merlin-stun-bob 1.4s ease-in-out infinite; }
.merlin__stun i {
  position: absolute;
  left: 0;
  top: 0;
  width: 11px;
  height: 11px;
  margin: -5.5px;
  /* Solid 5-point gold star (crisp glyph, not a soft dot). */
  background: radial-gradient(circle at 50% 36%, #FFFBE8 0%, #FFE193 40%, #F4B543 76%, #DE8420 100%);
  clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
  filter:
    drop-shadow(0 0 4px rgba(255, 214, 130, 0.95))
    drop-shadow(0 0 9px rgba(242, 200, 121, 0.55));
  transform-origin: center;
  animation: merlin-stun-orbit 1.4s linear infinite;
  will-change: transform, opacity;
}
.merlin__stun i:nth-child(1) { animation-delay: 0s;     }
.merlin__stun i:nth-child(2) { animation-delay: -0.28s; }
.merlin__stun i:nth-child(3) { animation-delay: -0.56s; }
.merlin__stun i:nth-child(4) { animation-delay: -0.84s; }
.merlin__stun i:nth-child(5) { animation-delay: -1.12s; }

/* Elliptical orbit baked into 8 steps. θ=0 at the BACK (top of the
   ellipse): small + dim; θ=180 at the FRONT (bottom): big + bright.
   A full self-rotation per lap makes each star twinkle as it flies. */
@keyframes merlin-stun-orbit {
  0%    { transform: translate(0px, -8px)      scale(0.55) rotate(0deg);   opacity: 0.4; }
  12.5% { transform: translate(15.6px, -5.7px) scale(0.7)  rotate(45deg);  opacity: 0.6; }
  25%   { transform: translate(22px, 0px)      scale(0.9)  rotate(90deg);  opacity: 0.9; }
  37.5% { transform: translate(15.6px, 5.7px)  scale(1.12) rotate(135deg); opacity: 1;   }
  50%   { transform: translate(0px, 8px)       scale(1.3)  rotate(180deg); opacity: 1;   }
  62.5% { transform: translate(-15.6px, 5.7px) scale(1.12) rotate(225deg); opacity: 1;   }
  75%   { transform: translate(-22px, 0px)     scale(0.9)  rotate(270deg); opacity: 0.9; }
  87.5% { transform: translate(-15.6px, -5.7px) scale(0.7) rotate(315deg); opacity: 0.6; }
  100%  { transform: translate(0px, -8px)      scale(0.55) rotate(360deg); opacity: 0.4; }
}
/* The whole halo bobs a touch, echoing the dizzy sprite wobble. */
@keyframes merlin-stun-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2px); }
}

/* FX HOST — sparks (summon) + embers (fire) spawned at the cursor /
   wizard in viewport coords. Fixed plane below the wizard. */
.merlin-fx {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 10050;
}
.merlin-fx__spark,
.merlin-fx__ember {
  position: absolute;
  left: var(--x, 0);
  top:  var(--y, 0);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  will-change: transform, opacity;
}
.merlin-fx__spark {
  width: 5px;
  height: 5px;
  background: radial-gradient(circle, #FFF7D8 0%, #FFD089 50%, rgba(255, 180, 100, 0) 80%);
  box-shadow: 0 0 7px rgba(255, 230, 170, 0.95), 0 0 16px rgba(255, 180, 100, 0.6);
  animation: merlin-fx-spark var(--life, 0.8s) ease-out both;
}
.merlin-fx__ember {
  width: 7px;
  height: 9px;
  border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
  background: radial-gradient(circle at 50% 65%, #FFF0B0 0%, #FFB347 38%, #E8541E 74%, rgba(180, 40, 10, 0) 100%);
  box-shadow: 0 0 8px rgba(255, 150, 60, 0.85), 0 0 18px rgba(230, 90, 30, 0.5);
  animation: merlin-fx-ember var(--life, 0.7s) ease-out both;
}
@keyframes merlin-fx-spark {
  0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0.4); }
  25%  { opacity: 0.95; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;    transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) scale(0.2); }
}
@keyframes merlin-fx-ember {
  0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0.5) rotate(0deg); }
  30%  { opacity: 1;    transform: translate(calc(-50% + var(--dx, 0) * 0.4), calc(-50% + var(--dy, 0) * 0.4)) scale(1.05) rotate(6deg); }
  100% { opacity: 0;    transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) scale(0.25) rotate(-8deg); }
}

/* ═══════════════════════════════════════════════════════════════
   FIRE-CAST RITUAL · charge glow → arcane bolt → CURSOR ABLAZE
   Merlin's deliberate spell: he gathers fire (charge), hurls a bolt
   (.merlin-bolt) at the pointer, and the cursor itself burns
   (.merlin-cursor-flame) for a few seconds. Charge/cast effects use
   ONLY `filter` on .merlin__avatar (its transform is owned by the
   chase positioning) and `transform` on the inner .merlin__sprite.
   ═══════════════════════════════════════════════════════════════ */
.merlin.is-charging .merlin__avatar {
  animation: merlin-charge-glow 0.95s ease-in forwards;
}
.merlin.is-charging .merlin__sprite {
  animation: merlin-charge-pulse 0.30s ease-in-out infinite alternate;
}
@keyframes merlin-charge-glow {
  0%   { filter: drop-shadow(0 0 2px rgba(255, 170, 80, 0)); }
  60%  { filter: drop-shadow(0 0 12px rgba(255, 175, 85, 0.85)) drop-shadow(0 0 22px rgba(255, 120, 40, 0.5)); }
  100% { filter: drop-shadow(0 0 18px rgba(255, 198, 108, 1)) drop-shadow(0 0 32px rgba(255, 130, 50, 0.65)); }
}
@keyframes merlin-charge-pulse {
  0%   { transform: scale(1); }
  100% { transform: scale(1.07); }
}
.merlin.is-casting .merlin__avatar {
  animation: merlin-cast-flash 0.42s ease-out;
}
.merlin.is-casting .merlin__sprite {
  animation: merlin-cast-recoil 0.42s ease-out;
}
@keyframes merlin-cast-flash {
  0%   { filter: drop-shadow(0 0 22px rgba(255, 212, 122, 1)) drop-shadow(0 0 38px rgba(255, 140, 60, 0.8)); }
  100% { filter: drop-shadow(0 0 0 rgba(255, 140, 60, 0)); }
}
@keyframes merlin-cast-recoil {
  0%   { transform: scale(1.13); }
  40%  { transform: scale(0.95); }
  100% { transform: scale(1); }
}

/* The arcane bolt — a short luminous streak flung at the pointer.
   Lives inside the .merlin-fx host (z 198). */
.merlin-bolt {
  position: absolute;
  left: var(--x, 0);
  top:  var(--y, 0);
  width: 24px;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg,
    rgba(255, 200, 110, 0) 0%, #FFCE84 38%, #FFF3C8 72%, #FFFFFF 100%);
  box-shadow: 0 0 8px rgba(255, 200, 120, 0.95), 0 0 18px rgba(255, 140, 60, 0.7);
  opacity: 0;
  transform: translate(-50%, -50%) rotate(var(--ang, 0deg)) scaleX(0.4);
  animation: merlin-bolt-fly 0.3s ease-in both;
  will-change: transform, opacity;
}
@keyframes merlin-bolt-fly {
  0%   { opacity: 0;   transform: translate(-50%, -50%) rotate(var(--ang, 0deg)) scaleX(0.4); }
  25%  { opacity: 1; }
  100% { opacity: 0.9; transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) rotate(var(--ang, 0deg)) scaleX(1.1); }
}

/* The cursor flame — a small living fire that rides the pointer.
   Positioned by JS via transform: translate(cursorX, cursorY); the
   inner layers rise from that point. */
.merlin-cursor-flame {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  z-index: 10051;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.22s ease;
  will-change: transform;
}
.merlin-cursor-flame.is-lit { opacity: 1; }
.merlin-cursor-flame.is-out { opacity: 0; transition: opacity 0.5s ease; }
/* Warm ground glow that pools around the burning pointer. */
.merlin-cursor-flame .mcf__glow {
  position: absolute;
  left: 0; top: 0;
  width: 68px; height: 68px;
  margin-left: -34px; margin-top: -50px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255, 196, 104, 0.55) 0%, rgba(255, 126, 44, 0.32) 44%, rgba(255, 90, 30, 0) 74%);
  filter: blur(2.5px);
  animation: mcf-glow-pulse 0.6s ease-in-out infinite alternate;
}
/* White-hot ember bed sitting right on the pointer tip. */
.merlin-cursor-flame .mcf__bed {
  position: absolute;
  left: 0; top: 0;
  width: 26px; height: 13px;
  margin-left: -13px; margin-top: -11px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
    #FFF3C8 0%, #FFC15A 44%, rgba(232, 84, 30, 0.6) 80%, rgba(180, 40, 10, 0) 100%);
  filter: blur(0.6px);
  animation: mcf-bed-pulse 0.34s ease-in-out infinite alternate;
}
.merlin-cursor-flame .mcf__f {
  position: absolute;
  left: 0; top: 0;
  transform-origin: 50% 100%;
  /* Symmetric flame silhouette — tip up, base at the pointer. */
  clip-path: polygon(50% 0%, 72% 26%, 64% 50%, 84% 78%, 50% 100%, 16% 78%, 36% 50%, 28% 26%);
  filter: blur(0.4px);
  will-change: transform;
}
.merlin-cursor-flame .mcf__f--1 {   /* outer red body */
  width: 26px; height: 44px; margin-left: -13px; margin-top: -44px;
  background: linear-gradient(to top, #C8390F 0%, #FF7A1E 42%, #FFB347 78%, #FFE9A8 100%);
  opacity: 0.9;
  animation: mcf-flicker-a 0.46s ease-in-out infinite alternate;
}
.merlin-cursor-flame .mcf__f--2 {   /* mid orange */
  width: 17px; height: 32px; margin-left: -8.5px; margin-top: -33px;
  background: linear-gradient(to top, #FF6A14 0%, #FFB347 56%, #FFE9A8 100%);
  opacity: 0.95;
  animation: mcf-flicker-b 0.4s ease-in-out infinite alternate;
}
.merlin-cursor-flame .mcf__f--3 {   /* white-hot core */
  width: 10px; height: 20px; margin-left: -5px; margin-top: -22px;
  background: linear-gradient(to top, #FFC15A 0%, #FFF3C8 58%, #FFFFFF 100%);
  opacity: 0.98;
  animation: mcf-flicker-c 0.34s ease-in-out infinite alternate;
}
/* Two side tongues so the fire reads fuller, not a single candle. */
.merlin-cursor-flame .mcf__f--sl,
.merlin-cursor-flame .mcf__f--sr {
  width: 13px; height: 24px;
  background: linear-gradient(to top, #C8390F 0%, #FF8A2A 55%, #FFD08A 100%);
  opacity: 0.82;
}
.merlin-cursor-flame .mcf__f--sl {
  margin-left: -16px; margin-top: -28px;
  animation: mcf-flicker-sl 0.42s ease-in-out infinite alternate;
}
.merlin-cursor-flame .mcf__f--sr {
  margin-left: 3px; margin-top: -27px;
  animation: mcf-flicker-sr 0.44s ease-in-out infinite alternate;
}

/* Rising smoke as the pointer chars — spawned into the fixed FX host. */
.merlin-smoke {
  position: absolute;
  left: var(--x, 0); top: var(--y, 0);
  width: 12px; height: 12px;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(58, 52, 46, 0.5) 0%, rgba(40, 36, 32, 0.32) 55%, rgba(28, 24, 20, 0) 80%);
  filter: blur(2px);
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.5);
  animation: merlin-smoke-rise var(--life, 1.2s) ease-out both;
  will-change: transform, opacity;
}
@keyframes merlin-smoke-rise {
  0%   { opacity: 0;   transform: translate(-50%, -50%) scale(0.5); }
  25%  { opacity: 0.5; }
  100% { opacity: 0;   transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) scale(var(--scale, 2)); }
}

@keyframes mcf-glow-pulse {
  0%   { opacity: 0.6; transform: scale(0.9); }
  100% { opacity: 1;   transform: scale(1.12); }
}
@keyframes mcf-bed-pulse {
  0%   { opacity: 0.75; transform: scale(0.9); }
  100% { opacity: 1;    transform: scale(1.16); }
}
@keyframes mcf-flicker-a {
  0%   { transform: scale(1, 1)       skewX(0deg)  translateY(0); }
  50%  { transform: scale(0.95, 1.08) skewX(2deg)  translateY(-1px); }
  100% { transform: scale(0.9, 1.16)  skewX(-3deg) translateY(-2px); }
}
@keyframes mcf-flicker-b {
  0%   { transform: scale(1, 1)       skewX(0deg); }
  100% { transform: scale(1.08, 0.9)  skewX(-4deg); }
}
@keyframes mcf-flicker-c {
  0%   { transform: scale(0.94, 1.06) skewX(2deg); }
  100% { transform: scale(1.08, 0.88) skewX(-2deg); }
}
@keyframes mcf-flicker-sl {
  0%   { transform: rotate(-12deg) scale(0.9, 1); }
  100% { transform: rotate(-18deg) scale(0.82, 1.16); }
}
@keyframes mcf-flicker-sr {
  0%   { transform: rotate(12deg)  scale(0.9, 1); }
  100% { transform: rotate(18deg)  scale(0.82, 1.16); }
}

/* While the spell burns, force the (progressively charred) pointer
   onto every element so links/buttons don't reset it to a clean arrow. */
html.merlin-burning,
html.merlin-burning * { cursor: none !important; }

/* Visible pointer ghost — replaces the unreliable CSS custom-cursor
   approach. Sits just under the flame, above all page content. */
.merlin-cursor-ghost {
  position: fixed;
  left: 0;
  top: 0;
  width: 26px;
  height: 30px;
  margin: -2px 0 0 -3px;          /* hotspot at the arrow tip */
  z-index: 10049;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s ease;
  will-change: transform;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
}
.merlin-cursor-ghost.is-active { opacity: 1; }
.merlin-cursor-ghost__arrow {
  fill: #EFE7D6;
  stroke: #2A2118;
  stroke-width: 1.3;
  stroke-linejoin: round;
  transition: fill 0.55s ease, stroke 0.55s ease, filter 0.55s ease;
}
.merlin-cursor-ghost[data-step="0"] .merlin-cursor-ghost__arrow { fill: #EFE7D6; stroke: #2A2118; }
.merlin-cursor-ghost[data-step="1"] .merlin-cursor-ghost__arrow { fill: #D6C19B; stroke: #241A12; }
.merlin-cursor-ghost[data-step="2"] .merlin-cursor-ghost__arrow { fill: #A6875A; stroke: #1A120A; }
.merlin-cursor-ghost[data-step="3"] .merlin-cursor-ghost__arrow { fill: #6B5334; stroke: #120C06; }
.merlin-cursor-ghost[data-step="4"] .merlin-cursor-ghost__arrow { fill: #3A2C1D; stroke: #0A0705; filter: brightness(0.72); }
.merlin-cursor-ghost[data-step="5"] .merlin-cursor-ghost__arrow {
  fill: #1A130D;
  stroke: #000000;
  filter: brightness(0.45) drop-shadow(0 0 4px rgba(255, 120, 40, 0.35));
}

@media (prefers-reduced-motion: reduce) {
  .merlin.is-charging .merlin__avatar,
  .merlin.is-charging .merlin__sprite,
  .merlin.is-casting .merlin__avatar,
  .merlin.is-casting .merlin__sprite,
  .merlin-bolt,
  .merlin-cursor-flame .mcf__glow,
  .merlin-cursor-flame .mcf__bed,
  .merlin-cursor-flame .mcf__f,
  .merlin-smoke,
  .merlin-cursor-ghost__arrow { animation: none !important; transition: none !important; }
}

/* ─────────────────────────────────────────────────────────────
   1b. IDLE PHOTONS  (firefly motes orbiting the wizard)
   ─────────────────────────────────────────────────────────────
   Mirrors the photon dust around the Memory Crystals. Each
   .merlin__photon carries:
     --ox / --oy  → anchor offset around the sprite center
     --dur        → cycle duration
     --delay      → animation offset
   The path is a tight ellipse: the photon drifts ±18px around
   its anchor while fading in/out and pulsing in size.        */
.merlin__photons {
  position: absolute;
  inset: 8% 8% 8% 8%;
  pointer-events: none;
  z-index: 0;          /* above aura, below sprite */
}

.merlin__photon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: radial-gradient(circle,
    #FFF7D8 0%,
    #FFD89A 45%,
    rgba(255, 200, 130, 0) 80%);
  box-shadow:
    0 0 6px rgba(255, 230, 170, 0.85),
    0 0 14px rgba(255, 190, 120, 0.55),
    0 0 28px rgba(229, 160, 80, 0.30);
  opacity: 0;
  transform: translate(-50%, -50%) translate(var(--ox, 0px), var(--oy, 0px)) scale(0.4);
  animation: merlin-photon var(--dur, 4s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform, opacity;
}

@keyframes merlin-photon {
  0%, 100% {
    opacity: 0;
    transform: translate(-50%, -50%)
               translate(var(--ox), var(--oy))
               scale(0.4);
  }
  18% {
    opacity: 0.95;
    transform: translate(-50%, -50%)
               translate(calc(var(--ox) * 0.85),  calc(var(--oy) * 1.05 - 4px))
               scale(1.1);
  }
  45% {
    opacity: 0.6;
    transform: translate(-50%, -50%)
               translate(calc(var(--ox) * 1.15), calc(var(--oy) * 0.9 - 8px))
               scale(0.9);
  }
  72% {
    opacity: 0.85;
    transform: translate(-50%, -50%)
               translate(calc(var(--ox) * 0.95), calc(var(--oy) * 1.1 - 2px))
               scale(1.0);
  }
}

/* When the wizard is casting (clicked / spell event), photons
   flare brighter and tighten their orbit briefly. */
.merlin.is-casting .merlin__photon {
  animation-duration: 1.6s;
  filter: brightness(1.4);
}

/* ─────────────────────────────────────────────────────────────
   2. SPEECH SCROLL  (parchment bubble)
   ───────────────────────────────────────────────────────────── */
.merlin__scroll {
  position: relative;
  max-width: 196px;             /* compacted dialog window */
  min-width: 150px;
  padding: 0.6rem 0.75rem 0.58rem;
  background:
    radial-gradient(ellipse 80% 60% at 30% 25%, rgba(245, 230, 196, 0.16), transparent 70%),
    radial-gradient(ellipse 60% 70% at 70% 75%, rgba(120, 90, 55, 0.10), transparent 70%),
    linear-gradient(180deg, #F2E2BD 0%, #E8D4A8 55%, #D8BF85 100%);
  border-radius: 14px 18px 8px 16px;
  box-shadow:
    inset 0 0 0 1px rgba(120, 90, 55, 0.18),
    inset 0 0 0 2px rgba(245, 230, 196, 0.7),
    inset 0 0 18px rgba(120, 80, 40, 0.18),
    0 8px 22px rgba(0, 0, 0, 0.55),
    0 0 24px rgba(255, 215, 160, 0.18);
  color: #3D2E1A;
  font-family: "Cormorant Garamond", "Libre Caslon Text", Georgia, serif;
  /* Heavier ink so the smaller chat stays easy to read on the
     parchment background (semibold). */
  font-weight: 600;
  font-size: 0.78rem;
  line-height: 1.4;
  letter-spacing: 0.005em;
  /* Cinematic fade-in: opacity + blur + soft lift.
     Blur clears as the parchment "settles" into focus. */
  opacity: 0;
  filter: blur(6px);
  transform: translateY(12px) scale(0.94);
  transition:
    opacity 0.55s ease,
    filter  0.55s ease,
    transform 0.55s cubic-bezier(.2, .8, .2, 1);
  pointer-events: none;
  transform-origin: bottom right;
}
.merlin__scroll.is-visible {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0) scale(1);
  pointer-events: all;
}

/* Curled top/bottom edges — fake the rolled parchment look */
.merlin__scroll-curl {
  position: absolute;
  left: -3px;
  right: -3px;
  height: 7px;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(120, 80, 40, 0.22) 0%,
    rgba(180, 140, 90, 0.10) 60%,
    transparent 100%);
  border-radius: 50%;
  filter: blur(0.5px);
}
.merlin__scroll-curl--top    { top: -4px; }
.merlin__scroll-curl--bottom {
  bottom: -4px;
  background: linear-gradient(0deg,
    rgba(120, 80, 40, 0.22) 0%,
    rgba(180, 140, 90, 0.10) 60%,
    transparent 100%);
}

/* Tiny wax seal in the upper-right corner */
.merlin__scroll-seal {
  position: absolute;
  top: 0.45rem;
  right: 0.55rem;
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));
  opacity: 0.85;
}

.merlin__text {
  margin: 0;
  font-style: italic;
  font-weight: 600;
  color: #36280F;
  /* Slight ink-bleed: faint dark shadow makes letters feel inked */
  text-shadow: 0 0.5px 0 rgba(255, 245, 220, 0.4);
}

/* Topic title (CHARACTER / TECH / SPELL) — rendered by JS as a
   dedicated <strong class="merlin__title"> on its own line, so it
   never visually fuses with the italic body paragraph. */
.merlin__title {
  display: block;
  margin-bottom: 0.35rem;
  font-family: "Libre Caslon Text", "Cormorant Garamond", Georgia, serif;
  font-style: normal;
  font-weight: 700;
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #5D2410;
  /* Faint underline rule to mark the chapter heading */
  padding-bottom: 0.2rem;
  border-bottom: 1px solid rgba(120, 80, 40, 0.25);
}

.merlin__body {
  display: block;
  font-style: italic;
}

/* ─────────────────────────────────────────────────────────────
   2b. THINKING STATE  (Merlin querying the Brain / LLM)
   ─────────────────────────────────────────────────────────────
   While the parchment is in `.is-thinking` we show three dots
   that pulse in cascade beneath the title — like ink slowly
   forming on the page. The input is also dimmed/disabled.    */
.merlin__dots {
  display: inline-flex;
  align-items: center;
  gap: 0.32rem;
  height: 1em;
  font-style: normal;
}
.merlin__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: radial-gradient(circle,
    #6B3416 0%,
    rgba(107, 52, 22, 0.55) 70%,
    transparent 100%);
  box-shadow: 0 0 4px rgba(120, 80, 40, 0.4);
  opacity: 0.25;
  animation: merlin-dot 1.3s ease-in-out infinite;
}
.merlin__dot:nth-child(2) { animation-delay: 0.18s; }
.merlin__dot:nth-child(3) { animation-delay: 0.36s; }
@keyframes merlin-dot {
  0%, 80%, 100% { opacity: 0.18; transform: translateY(0)    scale(0.85); }
  40%           { opacity: 1;    transform: translateY(-2px) scale(1.05); }
}

/* When thinking, the parchment glows a touch warmer to signal
   the wizard is reaching across the aether. */
.merlin__scroll.is-thinking {
  box-shadow:
    inset 0 0 0 1px rgba(120, 90, 55, 0.22),
    inset 0 0 0 2px rgba(245, 230, 196, 0.7),
    inset 0 0 22px rgba(180, 120, 60, 0.22),
    0 8px 22px rgba(0, 0, 0, 0.55),
    0 0 30px rgba(255, 200, 130, 0.30);
}

/* Quill input dimmed while waiting */
.merlin__quill.is-thinking {
  opacity: 0.55;
  cursor: progress;
}
.merlin__quill.is-thinking .merlin__quill-input,
.merlin__quill-input:disabled {
  cursor: progress;
}

/* ─────────────────────────────────────────────────────────────
   3. QUILL INPUT  (mini parchment for asking)
   ───────────────────────────────────────────────────────────── */
.merlin__quill {
  position: relative;
  /* Hidden until the visitor taps/clicks Merlin (is-asking). Kept out
     of flow when closed so the avatar never carries an empty gap.
     Quotes (.merlin__scroll) are independent of this and still play. */
  display: none;
  align-items: center;
  gap: 0.3rem;
  padding: 0.26rem 0.34rem 0.26rem 0.42rem;
  max-width: 196px;
  min-width: 150px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s ease 0.25s, transform 0.5s ease 0.25s, box-shadow 0.3s ease;
  background:
    radial-gradient(ellipse 70% 60% at 30% 30%, rgba(245, 230, 196, 0.18), transparent 70%),
    linear-gradient(180deg, #EFDCB0 0%, #E0C896 100%);
  border-radius: 18px;
  box-shadow:
    inset 0 0 0 1px rgba(120, 90, 55, 0.20),
    inset 0 0 0 2px rgba(245, 230, 196, 0.55),
    inset 0 0 12px rgba(120, 80, 40, 0.15),
    0 4px 14px rgba(0, 0, 0, 0.45);
  pointer-events: all;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* The quill is summoned only when the visitor taps/clicks Merlin.
   It then fades up into place; closing simply removes the class. */
.merlin.is-asking .merlin__quill {
  display: inline-flex;
  opacity: 1;
  transform: translateY(0);
  animation: merlin-quill-in 0.32s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes merlin-quill-in {
  from { opacity: 0; transform: translateY(10px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.merlin__quill:hover,
.merlin__quill:focus-within {
  transform: translateY(-1px);
  box-shadow:
    inset 0 0 0 1px rgba(120, 90, 55, 0.25),
    inset 0 0 0 2px rgba(245, 230, 196, 0.65),
    inset 0 0 12px rgba(120, 80, 40, 0.18),
    0 6px 18px rgba(0, 0, 0, 0.5),
    0 0 20px rgba(255, 215, 160, 0.2);
}

.merlin__quill-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0.85;
  transform: rotate(-12deg);
  transition: transform 0.3s ease, opacity 0.3s ease;
}
.merlin__quill:hover .merlin__quill-icon,
.merlin__quill:focus-within .merlin__quill-icon {
  transform: rotate(-6deg) translateY(-1px);
  opacity: 1;
}

.merlin__quill-input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  outline: none;
  font-family: "Cormorant Garamond", "Libre Caslon Text", Georgia, serif;
  /* Matches the scroll body — semibold so the user's question
     reads with the same inked confidence as Merlin's reply. */
  font-weight: 600;
  font-size: 0.74rem;
  font-style: italic;
  color: #36280F;
  padding: 0;
  letter-spacing: 0.01em;
}
.merlin__quill-input::placeholder {
  /* Keep the placeholder lighter (400) so it visibly recedes
     compared to actually typed text. */
  color: rgba(61, 46, 26, 0.55);
  font-style: italic;
  font-weight: 400;
}
.merlin__quill-input:focus { color: #2A1F12; }

.merlin__quill-send {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid rgba(120, 90, 55, 0.4);
  background: rgba(245, 230, 196, 0.6);
  color: #5D2410;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.25s ease, color 0.25s ease, transform 0.2s ease;
}
.merlin__quill-send:hover,
.merlin__quill-send:focus-visible {
  background: #A13E1E;
  color: #FFE6A8;
  transform: scale(1.1);
  outline: none;
}

/* ─────────────────────────────────────────────────────────────
   4. SPELL PARTICLES
   ───────────────────────────────────────────────────────────── */
.merlin__spell {
  position: absolute;
  /* Anchored around the sprite at the bottom-end of the column.
     The container has 0 size; particles are absolutely placed and
     fly outward from the centre. */
  width: 0;
  height: 0;
  bottom: 50px;
  right: 39px;
  pointer-events: none;
  z-index: 1;
}
.merlin[data-pos$="-left"] .merlin__spell { right: auto; left: 39px; }

.merlin__particle {
  position: absolute;
  left: 0;
  top: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: radial-gradient(circle, #FFF1C9 0%, #FFD089 55%, transparent 85%);
  box-shadow:
    0 0 8px rgba(255, 215, 160, 0.85),
    0 0 18px rgba(255, 170, 100, 0.55);
  transform: translate(-50%, -50%) scale(0.4);
  opacity: 0;
  animation: merlin-particle var(--dur, 0.9s) cubic-bezier(.25, .65, .35, 1) forwards;
  will-change: transform, opacity;
}
@keyframes merlin-particle {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.3);
  }
  20% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(calc(-50% + var(--tx, 0px)), calc(-50% + var(--ty, 0px))) scale(0.2);
  }
}

/* ─────────────────────────────────────────────────────────────
   5. RESPONSIVE
   ───────────────────────────────────────────────────────────── */
@media (max-width: 767px) {
  .merlin {
    bottom: 1rem;            /* tree-hud now lives at top-right */
    right: 0.65rem;
    gap: 0.35rem;
  }
  .merlin[data-pos="bottom-right"]  { bottom: 1rem; right: 0.65rem; }
  .merlin[data-pos="middle-right"]  { top: 38%; right: 0.65rem; }
  .merlin[data-pos="bottom-left"]   { bottom: 1rem; left: 0.65rem; }
  .merlin[data-pos="middle-left"]   { top: 52%; left: 0.65rem; }
  /* Top spots are pushed slightly lower to clear the tree-hud
     badge that now occupies the upper-right area on mobile.  */
  .merlin[data-pos="top-right"]     { top: 8.5rem; }
  .merlin[data-pos="top-left"]      { top: 4.5rem; }

  /* Mobile: a smaller, more discreet wizard so the floating chat
     never crowds the content the visitor is reading. */
  .merlin__avatar { width: 52px; height: 62px; }
  .merlin__scroll {
    max-width: min(178px, calc(100vw - 2rem));
    min-width: 0;
    font-size: 0.72rem;
    line-height: 1.34;
    padding: 0.5rem 0.62rem 0.48rem;
    border-radius: 12px 14px 7px 13px;
  }
  .merlin__title { font-size: 0.56rem; letter-spacing: 0.14em; margin-bottom: 0.28rem; }
  .merlin__scroll-seal { width: 12px; height: 12px; top: 0.36rem; right: 0.42rem; }
  .merlin__quill {
    max-width: min(200px, calc(100vw - 2rem));
    min-width: 0;
    padding: 0.26rem 0.32rem 0.26rem 0.42rem;
  }
  .merlin__quill-input { font-size: 0.72rem; }
  .merlin__photon { width: 3px; height: 3px; }
}

/* Even tighter on very small phones. */
@media (max-width: 480px) {
  .merlin__avatar { width: 46px; height: 56px; }
  .merlin__scroll {
    max-width: min(164px, calc(100vw - 2.2rem));
    font-size: 0.7rem;
    padding: 0.46rem 0.56rem 0.44rem;
  }
}

/* ─────────────────────────────────────────────────────────────
   6. REDUCED MOTION
   ───────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .merlin__sprite,
  .merlin__hat-stars circle,
  .merlin__staff-glow,
  .merlin__aura,
  .merlin__photon {
    animation: none !important;
  }
  .merlin.is-gliding .merlin__sprite,
  .merlin.is-spinning .merlin__sprite,
  .merlin.is-waving .merlin__sprite,
  .merlin.is-waving .merlin__staff-glow,
  .merlin.is-stunned .merlin__sprite,
  .merlin__stun i {
    animation: none !important;
    transform: none !important;
  }
  /* Cursor escort is disabled in JS under reduced motion, but guard
     the transform here too in case the class ever lingers. */
  .merlin.is-chasing .merlin__avatar { transform: none !important; }
  .merlin-trail__mote { animation-duration: 0.4s !important; }
  .merlin__photon { opacity: 0.7 !important; }
  .merlin__particle { animation-duration: 0.4s !important; }
  .merlin { transition: opacity 0.2s ease !important; }
  .merlin__scroll {
    transition: opacity 0.2s ease !important;
    transform: none !important;
    filter: none !important;
  }
  .merlin__quill { transition: opacity 0.2s ease !important; transform: none !important; }
}

/* ============================================================
   FOOTER
   ============================================================ */

.footer {
  position: relative;
  z-index: var(--z-content);
  padding: var(--space-md) var(--margin-safe);
  border-top: 1px solid var(--glass-border);
  text-align: center;
}

.footer__line {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-surface-muted);
}

/* Discreet copyright + legal notice — sits below the wax-seal line.
   Calibrated so the © line + disclaimer collapse to two readable
   lines on desktop, and re-flow gracefully on narrower viewports. */
.footer__legal {
  max-width: 1040px;
  margin: 0.7rem auto 0;
  padding: 0 1rem;
  text-align: center;
  font-family: "Cormorant Garamond", "EB Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.66rem;
  line-height: 1.55;
  letter-spacing: 0.015em;
  color: var(--on-surface-muted);
  opacity: 0.55;
  transition: opacity 0.45s ease;
}
.footer__legal:hover { opacity: 0.78; }
.footer__legal-copy {
  display: block;
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 0.2rem;
}
.footer__legal-notice { display: block; }

/* Light theme — sit on burgundy ink so legal text stays readable
   without breaking the parchment palette */
html[data-theme="light"] .footer__legal {
  color: var(--burgundy, #5C2B1F);
  opacity: 0.62;
}
html[data-theme="light"] .footer__legal:hover { opacity: 0.82; }

@media (max-width: 720px) {
  .footer__legal { font-size: 0.62rem; padding: 0 0.85rem; }
  .footer__legal-copy { font-size: 0.6rem; letter-spacing: 0.14em; }
}

/* ============================================================
   SCROLL REVEAL (applied via JS)
   ============================================================ */

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}

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

/* ============================================================
   RESPONSIVE
   ============================================================ */

@media (min-width: 768px) {
  .nav__links { display: flex; }
  .nav__burger { display: none !important; }
  :root { --margin-safe: 48px; }
}

/* MOBILE NAVIGATION (<768px) — the inline links collapse into a
   drop-down panel revealed by the .nav__burger trigger. The panel
   drops from the bottom edge of the fixed nav, inherits the same dark
   arcane glass, and stacks the four destinations as full-width rows. */
@media (max-width: 767px) {
  .nav__burger { display: inline-flex; }

  .nav__links {
    display: flex;
    flex-direction: column;
    gap: 0;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    padding: 0.35rem var(--margin-safe) 0.75rem;
    background: rgba(15, 42, 34, 0.96);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    border-bottom: 1px solid var(--glass-border);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.4);
    /* collapsed by default — animated open via .is-open */
    transform: translateY(-10px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.25s var(--ease-out),
                transform 0.25s var(--ease-out),
                visibility 0s linear 0.25s;
    max-height: calc(100vh - 72px);
    overflow-y: auto;
  }
  .nav__links.is-open {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.25s var(--ease-out),
                transform 0.25s var(--ease-out),
                visibility 0s;
  }
  .nav__links a {
    display: block;
    padding: 0.9rem 0;
    font-size: 0.8rem;
    border-bottom: 1px solid var(--glass-border);
  }
  .nav__links a:last-child { border-bottom: none; }
  /* The sliding underline reads as clutter in a stacked list. */
  .nav__links a::after { display: none; }

  /* The panel is dark arcane glass in BOTH themes, so links stay a
     light parchment tone (the extra `.nav` lifts specificity above the
     light-theme `.nav a` ink rule). */
  .nav__links a,
  html[data-theme="light"] .nav .nav__links a {
    color: rgba(231, 222, 202, 0.82);
  }
  .nav__links a:hover,
  .nav__links a:focus-visible,
  html[data-theme="light"] .nav .nav__links a:hover,
  html[data-theme="light"] .nav .nav__links a:focus-visible {
    color: var(--gold);
  }
}

/* Reclaim width on the smallest screens so the brand + 4 chips never
   overflow once the burger is added. */
@media (max-width: 420px) {
  .nav__wordmark-meta { display: none; }
}

/* (The Hero now uses a single compact upper-left panel on ALL
   viewports. The previous side-by-side desktop layout — Portrait +
   Copy in a row — was removed during the layout refactor; no
   breakpoint-specific Hero rules are needed above 768px.) */

@media (max-width: 980px) {
  /* Stack the cinematic crystal on top of the relic card on smaller
     screens, with the stage scrolling vertically if needed. */
  .crystal-vault__stage {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    justify-items: center;
    gap: 1.4rem;
    padding: 3rem 1.6rem 1.8rem;
    width: min(620px, 96vw);
    max-height: 94vh;
    overflow-y: auto;
  }
  .crystal-vault__core {
    height: clamp(240px, 38vh, 340px);
  }
  .relic-card {
    width: min(360px, 100%);
    max-height: none;
  }
  .crystal-vault__brand { top: 0.8rem; left: 1rem; font-size: 0.55rem; }
}

@media (max-width: 480px) {
  .crystal-vault__stage {
    padding: 2.6rem 0.9rem 1.4rem;
  }
  .crystal-vault__core { height: clamp(200px, 30vh, 280px); }
  .relic-card { width: min(320px, 100%); }
}

@media (max-width: 767px) {
  /* Tablet/Mobile reflow: the upper-left panel becomes a full-width
     block but stays at the top of the viewport. Content alignment
     and stack order are preserved. */
  .hero {
    grid-template-columns: 1fr;
    padding-top: clamp(5rem, 9vh, 6.5rem);
  }
  .hero__inner {
    max-width: 100%;
  }

  .crystal-caption__name { max-width: 120px; font-size: 0.85rem; }
  /* Stack the two regional columns vertically; flags + title
     stay at the top of each block. Cards shrink to fit. */
  .portal__columns {
    grid-template-columns: minmax(200px, 280px);
    width: min(360px, 92vw);
    gap: 1.6rem;
  }
  .portal__link { min-width: unset; width: 100%; max-width: 280px; }
  /* Each column has its own header on mobile (no horizontal pair
     to align with), so the 3-line title reservation from the
     desktop rule would leave dead space inside the shorter header.
     Release it and let each title size to its actual content. */
  .portal__column-title {
    font-size: 0.7rem;
    max-width: 260px;
    min-height: 0;
  }
  /* Slightly softer zoom on small screens so the card never
     clips against the viewport edge. */
  .portal__link:hover,
  .portal__link:focus-visible { transform: scale(1.04); }
  /* Mobile Merlin spot is handled inside the dedicated .merlin
     media query (above 4.5rem to clear the tree-hud badge). */
}

@media (max-width: 480px) {
  .hero__name { font-size: 2.2rem; }
  .tree__stage { aspect-ratio: 1 / 1.1; }
}

/* ============================================================
   MILESTONE · 3 SKILLS UNLOCKED
   Brief page quake + colour intensification + giant cursor
   that orbits Carlos' portrait while a banner instructs the
   visitor to click the photo.
============================================================ */

/* Brief vibration: short, decaying shake on the body */
.is-milestone-quaking {
  animation: ms-quake 0.7s cubic-bezier(.36,.07,.19,.97) both;
}
@keyframes ms-quake {
  0%, 100% { transform: translate(0, 0); }
  10% { transform: translate(-4px, 2px); }
  20% { transform: translate(5px, -3px); }
  30% { transform: translate(-6px, -2px); }
  40% { transform: translate(4px, 3px); }
  50% { transform: translate(-3px, -3px); }
  60% { transform: translate(3px, 2px); }
  70% { transform: translate(-2px, -1px); }
  80% { transform: translate(2px, 1px); }
  90% { transform: translate(-1px, 0); }
}

/* Colour intensification: a brief saturate / glow boost layered on top */
.is-milestone-celebrate::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 998;
  background:
    radial-gradient(circle at 50% 35%, rgba(255, 230, 180, 0.18), transparent 55%),
    radial-gradient(circle at 50% 50%, rgba(229, 190, 174, 0.12), transparent 70%);
  animation: ms-celebrate-flash 1.6s ease-out both;
  mix-blend-mode: screen;
}
@keyframes ms-celebrate-flash {
  0%   { opacity: 0; }
  18%  { opacity: 1; }
  60%  { opacity: 0.45; }
  100% { opacity: 0; }
}

/* Giant cursor flying / orbiting */
.milestone-cursor {
  position: fixed;
  z-index: 9999;
  width: 90px;
  height: 90px;
  pointer-events: none;
  --ms-x: 0px;
  --ms-y: 0px;
  --ms-scale: 0.4;
  --ms-opacity: 0;
  --ms-orbit-radius: 200px;
  transform: translate(-50%, -50%) translate(var(--ms-x), var(--ms-y)) scale(var(--ms-scale));
  opacity: var(--ms-opacity);
  filter: drop-shadow(0 0 14px rgba(255, 215, 160, 0.85))
          drop-shadow(0 0 32px rgba(229, 190, 174, 0.55));
  will-change: transform, opacity;
}
.milestone-cursor.is-traveling {
  transition:
    transform 1.4s cubic-bezier(.22,.7,.22,1),
    opacity 0.7s ease-out;
}
.milestone-cursor.is-orbiting {
  animation: ms-cursor-orbit 3.2s linear infinite;
  transition: opacity 0.4s ease-out;
}
@keyframes ms-cursor-orbit {
  from { transform: translate(-50%, -50%) rotate(0deg) translateX(var(--ms-orbit-radius)) scale(1); }
  to   { transform: translate(-50%, -50%) rotate(360deg) translateX(var(--ms-orbit-radius)) scale(1); }
}
.milestone-cursor.is-fading {
  opacity: 0 !important;
  transition: opacity 0.7s ease-in;
}

/* Tap-tap-tap pulse layered onto the orbiting cursor for extra emphasis */
.milestone-cursor.is-orbiting::after {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 215, 160, 0.8);
  animation: ms-cursor-ping 1.4s ease-out infinite;
  pointer-events: none;
}
@keyframes ms-cursor-ping {
  0%   { transform: scale(0.85); opacity: 0.95; }
  80%  { transform: scale(1.6);  opacity: 0; }
  100% { transform: scale(1.6);  opacity: 0; }
}

/* Floating instruction banner */
.milestone-banner {
  position: fixed;
  z-index: 9998;
  transform: translate(-50%, -50%) translateY(8px);
  background:
    linear-gradient(180deg, rgba(15, 9, 7, 0.94), rgba(27, 11, 5, 0.92));
  border: 1px solid rgba(229, 190, 174, 0.45);
  padding: 0.75rem 1.5rem;
  border-radius: 999px;
  color: #FFF6DC;
  font-family: "JetBrains Mono", "Hanken Grotesk", monospace;
  font-size: 0.85rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow:
    0 0 28px rgba(229, 190, 174, 0.35),
    0 0 60px rgba(255, 215, 160, 0.18),
    inset 0 0 18px rgba(255, 215, 160, 0.18);
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  opacity: 0;
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
  pointer-events: none;
}
.milestone-banner.is-shown {
  opacity: 1;
  transform: translate(-50%, -50%) translateY(0);
  animation: ms-banner-bob 3.2s ease-in-out infinite;
}
.milestone-banner.is-fading {
  opacity: 0 !important;
  transition: opacity 0.7s ease-in;
}
.milestone-banner__sigil {
  color: #E5BEAE;
  font-size: 0.9rem;
  text-shadow: 0 0 8px rgba(229, 190, 174, 0.85);
}
.milestone-banner__text { color: #FFF6DC; }

@keyframes ms-banner-bob {
  0%, 100% { transform: translate(-50%, -50%) translateY(0); }
  50%      { transform: translate(-50%, -50%) translateY(-6px); }
}

/* Portrait highlight: pulsing halo + brighter glow + clickable look */
.hero__portrait.is-milestone-target {
  cursor: pointer;
  z-index: 5;
}
.hero__portrait.is-milestone-target::after {
  content: "";
  position: absolute;
  inset: -22px;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(circle, rgba(255, 215, 160, 0.32) 0%, rgba(229, 190, 174, 0.16) 45%, transparent 75%);
  animation: ms-portrait-halo 2.2s ease-in-out infinite;
  z-index: 0;
}
@keyframes ms-portrait-halo {
  0%, 100% {
    transform: scale(1);
    opacity: 0.7;
    box-shadow:
      0 0 40px rgba(255, 215, 160, 0.55),
      0 0 90px rgba(229, 190, 174, 0.35);
  }
  50% {
    transform: scale(1.06);
    opacity: 1;
    box-shadow:
      0 0 60px rgba(255, 215, 160, 0.85),
      0 0 140px rgba(229, 190, 174, 0.55);
  }
}
.hero__portrait.is-milestone-target .hero__portrait-frame {
  animation: ms-portrait-pulse 2.2s ease-in-out infinite;
}
@keyframes ms-portrait-pulse {
  0%, 100% { filter: brightness(1) saturate(1); transform: scale(1); }
  50%      { filter: brightness(1.18) saturate(1.18); transform: scale(1.025); }
}

/* Mobile tweaks */
@media (max-width: 640px) {
  .milestone-cursor { width: 68px; height: 68px; }
  .milestone-banner {
    font-size: 0.72rem;
    padding: 0.6rem 1.1rem;
    letter-spacing: 0.14em;
    max-width: 84vw;
    white-space: normal;
    text-align: center;
    line-height: 1.3;
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-milestone-quaking { animation: none; }
  .is-milestone-celebrate::before { animation: none; opacity: 0.6; }
  .milestone-cursor.is-orbiting { animation: none; }
  .milestone-banner.is-shown { animation: none; }
  .hero__portrait.is-milestone-target::after,
  .hero__portrait.is-milestone-target .hero__portrait-frame { animation: none; }
}

/* ============================================================
   CODEX DO ARQUITETO
   Click on the Núcleo Arcano portrait → 3s summoning ritual →
   the codex unfurls as a luxurious medieval/arcane spread.
============================================================ */

/* PORTRAIT CALL-TO-ACTION
   Subtle persistent hint that the photo is interactive (without
   replacing the milestone halo when that one is active). */
.hero__portrait {
  --codex-portrait-glow: rgba(255, 215, 160, 0);
  cursor: pointer;
  transition: transform 0.6s cubic-bezier(.2,.7,.2,1);
}
.hero__portrait:not(.is-milestone-target):hover {
  transform: scale(1.015);
}
.hero__portrait:not(.is-milestone-target):hover .hero__portrait-frame {
  filter: brightness(1.08) saturate(1.05);
}

/* RITUAL STATE — when the Codex is being summoned, the ring
   accelerates, the photo brightens and the surrounding tree dims */
.hero__portrait.is-codex-active .hero__rune-ring {
  animation: codex-ring-spin 6s linear infinite, codex-ring-glow 1.6s ease-in-out infinite;
}
.hero__portrait.is-codex-active .hero__rune-text {
  fill: #FFE7A0;
  filter: drop-shadow(0 0 6px rgba(255, 215, 160, 0.85));
}
.hero__portrait.is-codex-active .hero__portrait-frame {
  animation: codex-portrait-breathe 1.4s ease-in-out infinite;
}
.hero__portrait.is-codex-active::before {
  content: "";
  position: absolute;
  inset: -34px;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(circle, rgba(255, 235, 190, 0.4) 0%, rgba(229, 190, 174, 0.18) 45%, transparent 75%);
  animation: codex-portrait-aura 1.4s ease-in-out infinite;
  z-index: -1;
}
@keyframes codex-ring-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@keyframes codex-ring-glow {
  0%, 100% { filter: drop-shadow(0 0 8px rgba(229, 190, 174, 0.45)); }
  50%      { filter: drop-shadow(0 0 24px rgba(255, 215, 160, 0.95)); }
}
@keyframes codex-portrait-breathe {
  0%, 100% { transform: scale(1); filter: brightness(1.05) saturate(1.05); }
  50%      { transform: scale(1.04); filter: brightness(1.25) saturate(1.18); }
}
@keyframes codex-portrait-aura {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 1; transform: scale(1.1); }
}

/* TREE DIMMING during the ritual + codex open.
   We dim tree canvases & ambient layers, but never hide them.
   The crystals share the same wallpaper plane, so they dim too. */
.is-codex-summoning .tree-canvas,
.is-codex-summoning .tree-fullscreen,
.is-codex-summoning #tree-canvas-bg,
.is-codex-summoning #tree-canvas-fg,
.is-codex-summoning #crystal-canvas,
.is-codex-summoning #crystal-overlay {
  transition: filter 1.6s ease, opacity 1.6s ease;
  filter: brightness(0.45) saturate(0.6);
  opacity: 0.55;
}
.is-codex-summoning .nav,
.is-codex-summoning .hero__inner > *:not(.hero__portrait),
.is-codex-summoning .tree-vault,
.is-codex-summoning .memories,
.is-codex-summoning .portal,
.is-codex-summoning .merlin {
  transition: filter 1.4s ease, opacity 1.4s ease;
  filter: blur(2.5px) brightness(0.55);
  opacity: 0.45;
  pointer-events: none;
}

/* ============================================================
   CONSELHO DE MERLIN · microevento narrativo
============================================================ */
.council {
  position: fixed;
  inset: 0;
  z-index: 8800;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.65s ease, visibility 0.65s ease;
}
.council.is-active {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  cursor: pointer;
}
.council.is-fading-out {
  opacity: 0;
  pointer-events: none;
}

.council__canvas {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 1;
}

.council__stage {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
  max-width: min(680px, 88vw);
  padding: 2rem 1.5rem;
  text-align: center;
  pointer-events: none;
}

.council__title {
  margin: 0;
  font-family: "Cinzel", "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.05rem, 2.4vw, 1.45rem);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 235, 200, 0.92);
  text-shadow:
    0 0 18px rgba(255, 220, 160, 0.35),
    0 2px 8px rgba(0, 0, 0, 0.55);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.council.is-show-title .council__title {
  opacity: 1;
  transform: translateY(0);
}

.council__intro {
  margin: 0.35rem 0 0;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.05rem, 2.1vw, 1.25rem);
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: rgba(229, 200, 160, 0.78);
  min-height: 1.5em;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.55s ease, transform 0.55s ease;
}
.council.is-show-intro .council__intro {
  opacity: 1;
  transform: translateY(0);
}
.council__intro.is-typing::after {
  content: "▌";
  display: inline-block;
  margin-left: 2px;
  color: rgba(255, 220, 160, 0.65);
  animation: council-cursor 0.85s step-end infinite;
}
@keyframes council-cursor {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0; }
}

.council__phrase {
  margin: 0.6rem 0 0;
  padding: 0;
  border: none;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.25rem, 2.8vw, 1.65rem);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0.02em;
  color: rgba(255, 240, 215, 0.94);
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
  opacity: 0;
  transform: translateY(14px) scale(0.98);
  transition:
    opacity 0.85s ease,
    transform 0.85s ease,
    filter 0.9s ease;
}
.council__line {
  display: block;
}
.council.is-show-phrase .council__phrase {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.council.is-phrase-glow .council__phrase {
  filter: drop-shadow(0 0 14px rgba(255, 220, 160, 0.45));
}

.council__seal {
  margin: 0.5rem 0 0;
  font-family: "Cinzel", "Cormorant Garamond", Georgia, serif;
  font-size: clamp(0.95rem, 2vw, 1.15rem);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(194, 164, 107, 0.95);
  text-shadow: 0 0 12px rgba(194, 164, 107, 0.35);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.75s ease, transform 0.75s ease;
}
.council.is-show-seal .council__seal {
  opacity: 1;
  transform: translateY(0);
}

body.is-merlin-council .hero__portrait.is-codex-active::before {
  animation-duration: 2.4s;
}

@media (prefers-reduced-motion: reduce) {
  .council,
  .council__title,
  .council__intro,
  .council__phrase,
  .council__seal {
    transition-duration: 0.25s;
  }
  .council__intro.is-typing::after {
    animation: none;
    opacity: 0;
  }
}

/* ============================================================
   CODEX OVERLAY
============================================================ */
.codex {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  visibility: hidden;
  --codex-origin-x: 50vw;
  --codex-origin-y: 50vh;
  --gold:  #C2A46B;
  --gold-bright: #E5BEAE;
  --gold-deep: #8C5A2F;
  --ember: #A13E1E;
  --ink: #271812;
  --ink-soft: #5C3F2A;
  --parchment-1: #F4E2C2;
  --parchment-2: #E6CFA0;
  --parchment-3: #D9B47B;
}
.codex[aria-hidden="false"],
.codex.is-open,
.codex.is-closing {
  visibility: visible;
}

/* Convergence canvas: full viewport, behind the book */
.codex__energy {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 9001;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.codex[aria-hidden="false"] .codex__energy,
.codex.is-closing .codex__energy {
  opacity: 1;
}

/* Veil: dark velvet that fades in during summon */
.codex__veil {
  position: fixed;
  inset: 0;
  background:
    radial-gradient(ellipse at center, rgba(20, 11, 7, 0.55) 0%, rgba(9, 5, 4, 0.92) 70%),
    linear-gradient(160deg, rgba(60, 30, 15, 0.35), rgba(0, 0, 0, 0.85));
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.2s ease;
  z-index: 9002;
  cursor: pointer;
}
.codex.is-open .codex__veil,
.codex.is-closing .codex__veil {
  opacity: 1;
  pointer-events: auto;
}

/* THE BOOK — the actual codex spread.
   It unfurls from the portrait centre. */
.codex__book {
  position: relative;
  z-index: 9003;
  width: min(1180px, 94vw);
  max-width: 94vw;
  max-height: 92vh;
  background:
    radial-gradient(ellipse at top, rgba(255, 235, 200, 0.18), transparent 55%),
    radial-gradient(ellipse at bottom, rgba(140, 90, 47, 0.18), transparent 60%),
    linear-gradient(180deg, var(--parchment-1) 0%, var(--parchment-2) 60%, var(--parchment-3) 100%);
  color: var(--ink);
  border-radius: 6px;
  padding: 3.4rem 2.6rem 2.6rem;
  box-shadow:
    0 0 0 1px rgba(140, 90, 47, 0.35),
    0 0 0 6px rgba(20, 12, 8, 0.85),
    0 0 0 7px rgba(194, 164, 107, 0.6),
    0 30px 90px rgba(0, 0, 0, 0.7),
    0 0 200px rgba(229, 190, 174, 0.25);
  font-family: "Libre Caslon Text", "Cormorant Garamond", Georgia, serif;
  pointer-events: auto;
  transform:
    translate(calc(var(--codex-origin-x) - 50vw), calc(var(--codex-origin-y) - 50vh))
    scale(0.04)
    rotate(-6deg);
  opacity: 0;
  transition:
    transform 1.2s cubic-bezier(.18,.7,.16,1.05),
    opacity 0.9s ease;
  overflow: hidden;
}
.codex.is-open .codex__book {
  transform: translate(0, 0) scale(1) rotate(0);
  opacity: 1;
}
.codex.is-closing .codex__book {
  transform:
    translate(calc(var(--codex-origin-x) - 50vw), calc(var(--codex-origin-y) - 50vh))
    scale(0.06)
    rotate(8deg);
  opacity: 0;
  filter: blur(4px) brightness(0.7);
  transition:
    transform 1.4s cubic-bezier(.6,0,.7,.2),
    opacity 1.4s ease,
    filter 1.4s ease;
}

/* Subtle parchment texture */
.codex__book::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(rgba(140, 90, 47, 0.08) 1px, transparent 1.5px),
    radial-gradient(rgba(60, 35, 15, 0.05) 1px, transparent 1.5px);
  background-size: 4px 4px, 6px 6px;
  background-position: 0 0, 2px 3px;
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: 0.85;
}
/* Burnt vignette */
.codex__book::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at top left, rgba(80, 30, 10, 0.32), transparent 35%),
    radial-gradient(ellipse at bottom right, rgba(80, 30, 10, 0.34), transparent 40%),
    radial-gradient(ellipse at center, transparent 55%, rgba(60, 25, 10, 0.4) 100%);
  mix-blend-mode: multiply;
}

/* CORNERS — decorative gold ornaments */
.codex__corner {
  position: absolute;
  width: 56px;
  height: 56px;
  pointer-events: none;
  background:
    linear-gradient(135deg, transparent 35%, var(--gold) 35%, var(--gold-bright) 50%, var(--gold) 65%, transparent 65%);
  opacity: 0.85;
  z-index: 2;
}
.codex__corner--tl { top: 14px; left: 14px; transform: rotate(0); }
.codex__corner--tr { top: 14px; right: 14px; transform: rotate(90deg); }
.codex__corner--bl { bottom: 14px; left: 14px; transform: rotate(-90deg); }
.codex__corner--br { bottom: 14px; right: 14px; transform: rotate(180deg); }
.codex__corner::before,
.codex__corner::after {
  content: "";
  position: absolute;
  background: var(--gold-deep);
}
.codex__corner::before {
  top: 0; left: 0;
  width: 38px; height: 1px;
}
.codex__corner::after {
  top: 0; left: 0;
  width: 1px; height: 38px;
}

/* CLOSE BUTTON — small gold seal in the upper-right */
.codex__close {
  position: absolute;
  top: 18px;
  right: 78px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--gold-deep);
  background:
    radial-gradient(circle, rgba(255, 235, 190, 0.6), rgba(140, 90, 47, 0.15) 70%),
    var(--parchment-1);
  color: var(--ink);
  display: grid;
  place-items: center;
  cursor: pointer;
  z-index: 3;
  transition: transform 0.3s ease, box-shadow 0.3s ease, color 0.3s ease;
  box-shadow:
    0 0 0 2px var(--parchment-1),
    0 0 0 3px var(--gold-deep),
    0 4px 18px rgba(0, 0, 0, 0.4);
}
.codex__close:hover {
  transform: scale(1.08) rotate(90deg);
  color: var(--ember);
  box-shadow:
    0 0 0 2px var(--parchment-1),
    0 0 0 3px var(--ember),
    0 0 22px rgba(229, 190, 174, 0.7);
}

/* CROWN ornament in the header area */
.codex__crown {
  display: flex;
  justify-content: center;
  margin-bottom: 0.4rem;
  color: var(--gold-deep);
  z-index: 2;
  position: relative;
}
.codex__crown-svg {
  width: min(420px, 70%);
  height: 28px;
  opacity: 0.85;
}

/* HEADER */
.codex__head {
  text-align: center;
  z-index: 2;
  position: relative;
  padding-bottom: 0.4rem;
}
.codex__eyebrow {
  font-family: "JetBrains Mono", monospace;
  letter-spacing: 0.4em;
  font-size: 0.7rem;
  color: var(--gold-deep);
  margin: 0 0 0.4rem;
}
.codex__title {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: clamp(1.5rem, 3vw, 2.2rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
  margin: 0;
  text-shadow: 0 1px 0 rgba(255, 235, 190, 0.5);
  background: linear-gradient(180deg, var(--ink) 30%, var(--gold-deep) 90%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.codex__subtitle {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.95rem;
  color: var(--ink-soft);
  margin: 0.4rem 0 0;
  letter-spacing: 0.06em;
}

/* SPREAD: two facing pages with a central spine */
.codex__spread {
  display: grid;
  grid-template-columns: 1fr 2px 1fr;
  gap: 1.6rem;
  margin-top: 1.6rem;
  position: relative;
  z-index: 2;
  max-height: calc(92vh - 220px);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--gold-deep) transparent;
}
.codex__spread::-webkit-scrollbar { width: 6px; }
.codex__spread::-webkit-scrollbar-thumb {
  background: var(--gold-deep);
  border-radius: 3px;
}
/* The CV grant (Outorga Selada) + the seal footer now live INSIDE the
   scrollable spread so the book's max-height/overflow can never clip
   them. Both span the full two-page width as their own rows. The
   grid-column is scoped to direct children so the certificate
   `.codex__seal` links (nested in the left page) are untouched. */
.codex__spread > .codex__download,
.codex__spread > .codex__seal { grid-column: 1 / -1; }
.codex__spread { padding-bottom: 0.5rem; }
.codex__page {
  position: relative;
  padding: 0.4rem 0.8rem;
}
.codex__spine {
  position: relative;
  background:
    linear-gradient(180deg,
      transparent 0,
      rgba(60, 30, 15, 0.45) 8%,
      rgba(60, 30, 15, 0.65) 50%,
      rgba(60, 30, 15, 0.45) 92%,
      transparent 100%);
  box-shadow:
    -2px 0 6px rgba(60, 30, 15, 0.3),
     2px 0 6px rgba(60, 30, 15, 0.3);
}

/* Watermarks: subtle background symbols */
.codex__watermark {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200' fill='%238c5a2f' opacity='0.18'><circle cx='100' cy='100' r='70' fill='none' stroke='%238c5a2f' stroke-width='1'/><circle cx='100' cy='100' r='38' fill='none' stroke='%238c5a2f' stroke-width='0.6'/><path d='M100 30 L108 64 L142 60 L116 84 L130 118 L100 102 L70 118 L84 84 L58 60 L92 64 Z' stroke='%238c5a2f' stroke-width='0.6' fill='none'/><line x1='30' y1='100' x2='170' y2='100' stroke='%238c5a2f' stroke-width='0.5'/><line x1='100' y1='30' x2='100' y2='170' stroke='%238c5a2f' stroke-width='0.5'/></svg>");
  background-repeat: no-repeat;
  background-position: center 30%;
  background-size: 65% auto;
  opacity: 0.13;
}
.codex__watermark--alt {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200' fill='%238c5a2f'><g fill='none' stroke='%238c5a2f' stroke-width='0.7'><rect x='40' y='40' width='120' height='120' rx='6'/><circle cx='100' cy='100' r='42'/><path d='M100 58 V142 M58 100 H142 M71 71 L129 129 M129 71 L71 129'/><circle cx='100' cy='100' r='10'/></g></svg>");
  opacity: 0.1;
}

/* PORTRAIT inside the codex */
.codex__portrait {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0 0 1rem;
}
.codex__portrait-frame {
  position: relative;
  width: 200px;
  height: 240px;
  border: 2px solid var(--gold-deep);
  outline: 1px solid var(--gold);
  outline-offset: 4px;
  background: linear-gradient(180deg, rgba(60, 30, 15, 0.1), transparent);
  box-shadow:
    0 0 0 6px var(--parchment-1),
    0 0 0 7px var(--gold-deep),
    0 14px 40px rgba(0, 0, 0, 0.4);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.codex__portrait-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: sepia(0.18) contrast(1.05) saturate(1.05);
}
.codex__portrait-corner {
  position: absolute;
  width: 16px;
  height: 16px;
  border-color: var(--gold-bright);
  border-style: solid;
  z-index: 1;
}
.codex__portrait-corner--tl { top: 4px; left: 4px; border-width: 1.4px 0 0 1.4px; }
.codex__portrait-corner--tr { top: 4px; right: 4px; border-width: 1.4px 1.4px 0 0; }
.codex__portrait-corner--bl { bottom: 4px; left: 4px; border-width: 0 0 1.4px 1.4px; }
.codex__portrait-corner--br { bottom: 4px; right: 4px; border-width: 0 1.4px 1.4px 0; }

.codex__portrait-cap {
  margin-top: 0.7rem;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.36em;
  color: var(--gold-deep);
}

/* Name & class */
.codex__name {
  text-align: center;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  margin: 0.2rem 0 0.2rem;
  letter-spacing: 0.04em;
  font-weight: 700;
  color: var(--ink);
  text-shadow: 0 1px 0 rgba(255, 235, 190, 0.5);
}
.codex__class-main {
  text-align: center;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 1.05rem;
  color: var(--ember);
  margin: 0;
  letter-spacing: 0.08em;
}

/* Divider with central glyph */
.codex__divider {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1.1rem 0 0.9rem;
  color: var(--gold-deep);
}
.codex__divider::before,
.codex__divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background:
    linear-gradient(90deg, transparent, var(--gold-deep) 30%, var(--gold-bright) 50%, var(--gold-deep) 70%, transparent);
  opacity: 0.7;
}
.codex__divider-mark {
  font-size: 0.95rem;
  text-shadow: 0 0 6px rgba(229, 190, 174, 0.6);
}

/* Identity dl */
.codex__identity {
  margin: 0;
  padding: 0;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
}
.codex__identity > div {
  margin-bottom: 0.55rem;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.1rem;
}
.codex__identity dt {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.32em;
  color: var(--gold-deep);
  text-transform: uppercase;
}
.codex__identity dd {
  margin: 0;
  font-size: 1rem;
  color: var(--ink);
  line-height: 1.45;
}
.codex__identity dd .sep {
  color: var(--gold-deep);
  margin: 0 0.4rem;
}

/* Languages */
.codex__langs h4,
.codex__attrs h4,
.codex__chronicles h4,
.codex__relics h4,
.codex__sobre h4,
.codex__contact h4,
.codex__seals h4,
.codex__cartography h4,
.codex__formacao h4,
.codex__experience h4,
.codex__research h4,
.codex__voluntariado h4,
.codex__softskills h4,
.codex__honors h4 {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.75rem;
  letter-spacing: 0.36em;
  color: var(--gold-deep);
  text-transform: uppercase;
  margin: 0 0 0.7rem;
  text-align: center;
  position: relative;
}
.codex__langs h4::before,
.codex__langs h4::after,
.codex__attrs h4::before,
.codex__attrs h4::after,
.codex__chronicles h4::before,
.codex__chronicles h4::after,
.codex__relics h4::before,
.codex__relics h4::after,
.codex__sobre h4::before,
.codex__sobre h4::after,
.codex__contact h4::before,
.codex__contact h4::after,
.codex__seals h4::before,
.codex__seals h4::after,
.codex__cartography h4::before,
.codex__cartography h4::after,
.codex__formacao h4::before,
.codex__formacao h4::after,
.codex__experience h4::before,
.codex__experience h4::after,
.codex__research h4::before,
.codex__research h4::after,
.codex__voluntariado h4::before,
.codex__voluntariado h4::after,
.codex__softskills h4::before,
.codex__softskills h4::after,
.codex__honors h4::before,
.codex__honors h4::after {
  content: "✦";
  font-size: 0.65rem;
  margin: 0 0.5rem;
  color: var(--gold);
  vertical-align: middle;
}
.codex__langs ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.6rem;
}
.codex__langs li {
  display: grid;
  grid-template-columns: 6.5em 1fr 5em;
  align-items: center;
  gap: 0.7rem;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
}
.codex__lang-name {
  font-size: 1rem;
  color: var(--ink);
}
.codex__bar {
  position: relative;
  height: 8px;
  background:
    repeating-linear-gradient(90deg,
      rgba(140, 90, 47, 0.3) 0,
      rgba(140, 90, 47, 0.3) 1px,
      transparent 1px,
      transparent 6px),
    rgba(60, 30, 15, 0.18);
  border: 1px solid var(--gold-deep);
  border-radius: 1px;
  overflow: hidden;
}
.codex__bar-fill {
  display: block;
  height: 100%;
  width: var(--w);
  background:
    linear-gradient(90deg, var(--gold-deep), var(--gold-bright) 60%, var(--ember));
  box-shadow: 0 0 8px rgba(229, 190, 174, 0.7);
  transform-origin: left;
  animation: codex-bar-fill 1.4s cubic-bezier(.2,.7,.2,1) both;
}
.codex__lang-tag {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.6rem;
  letter-spacing: 0.2em;
  color: var(--gold-deep);
  text-align: right;
}
@keyframes codex-bar-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* ATTRIBUTES (right page) */
.codex__attrs ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.55rem;
}
.codex__attrs li {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto;
  column-gap: 0.6rem;
  align-items: center;
}
.codex__attr-name {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 1rem;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.codex__attr-val {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--ember);
  text-shadow: 0 0 6px rgba(229, 190, 174, 0.4);
}
.codex__attr-bar {
  grid-column: 1 / -1;
  position: relative;
  height: 11px;
  background:
    repeating-linear-gradient(90deg,
      rgba(140, 90, 47, 0.4) 0,
      rgba(140, 90, 47, 0.4) 1px,
      transparent 1px,
      transparent 10%),
    rgba(60, 30, 15, 0.15);
  border: 1px solid var(--gold-deep);
  border-radius: 1px;
  overflow: hidden;
}
.codex__attr-fill {
  display: block;
  height: 100%;
  width: var(--w);
  background:
    linear-gradient(90deg, var(--gold-deep), var(--gold) 50%, var(--ember));
  box-shadow:
    0 0 10px rgba(229, 190, 174, 0.7),
    inset 0 0 4px rgba(255, 235, 190, 0.5);
  transform-origin: left;
  animation: codex-bar-fill 1.6s cubic-bezier(.2,.7,.2,1) both;
}

/* CHRONICLES (timeline) — shared by Crônicas, Pergaminhos
   Acadêmicos, Crônicas de Serviço, Pesquisas Arcanas
   and Pactos Voluntários. */
.codex__chronicles ol,
.codex__formacao ol,
.codex__experience ol,
.codex__research ol,
.codex__voluntariado ol {
  list-style: none;
  padding: 0 0 0 1.4rem;
  margin: 0;
  border-left: 1px dashed var(--gold-deep);
  position: relative;
}
.codex__chronicles li,
.codex__formacao li,
.codex__experience li,
.codex__research li,
.codex__voluntariado li {
  position: relative;
  padding: 0.35rem 0 0.35rem 0.4rem;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
}
.codex__chronicles li::before,
.codex__formacao li::before,
.codex__experience li::before,
.codex__research li::before,
.codex__voluntariado li::before {
  content: "";
  position: absolute;
  left: -1.78rem;
  top: 0.7rem;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background:
    radial-gradient(circle, var(--gold-bright), var(--gold) 40%, var(--gold-deep) 70%);
  box-shadow:
    0 0 0 2px var(--parchment-1),
    0 0 0 3px var(--gold-deep),
    0 0 10px rgba(229, 190, 174, 0.6);
}
.codex__chronicles li.is-now::before,
.codex__formacao li.is-now::before,
.codex__experience li.is-now::before,
.codex__research li.is-now::before,
.codex__voluntariado li.is-now::before {
  background:
    radial-gradient(circle, #FFE7A0, var(--ember) 60%, var(--gold-deep) 100%);
  box-shadow:
    0 0 0 2px var(--parchment-1),
    0 0 0 3px var(--ember),
    0 0 18px rgba(255, 215, 160, 0.95);
  animation: codex-now-pulse 2s ease-in-out infinite;
}
@keyframes codex-now-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.18); }
}
.codex__chronicles time,
.codex__formacao time,
.codex__experience time,
.codex__research time,
.codex__voluntariado time {
  display: inline-block;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  color: var(--ember);
  font-weight: 700;
  margin-right: 0.5rem;
}
.codex__chronicles p,
.codex__formacao p,
.codex__experience p,
.codex__research p,
.codex__voluntariado p {
  display: inline;
  margin: 0;
  font-size: 0.98rem;
  color: var(--ink);
}
.codex__formacao p strong,
.codex__experience p strong,
.codex__research p strong,
.codex__voluntariado p strong {
  color: var(--ink);
  font-weight: 700;
  letter-spacing: 0.01em;
}

/* SUB-LIST · indented detail bullets for Pesquisas Arcanas and
   Pactos Voluntários activity breakdowns. Lives inside an <li> so
   the timeline dot styling above is preserved. */
.codex__research .codex__sub-list,
.codex__voluntariado .codex__sub-list {
  list-style: none;
  display: block;
  padding: 0.45rem 0 0.35rem 0.2rem;
  margin: 0;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.9rem;
  color: var(--ink);
  opacity: 0.92;
}
.codex__research .codex__sub-list li,
.codex__voluntariado .codex__sub-list li {
  display: block;
  position: relative;
  padding: 0.08rem 0 0.08rem 1rem;
  font-family: inherit;
}
.codex__research .codex__sub-list li::before,
.codex__voluntariado .codex__sub-list li::before {
  content: "❖";
  position: static;
  display: inline-block;
  width: 0.85rem;
  margin-left: -1rem;
  color: var(--gold-deep);
  font-size: 0.72rem;
  background: none;
  border-radius: 0;
  box-shadow: none;
  animation: none;
  vertical-align: 0.05em;
}

/* RELICS — runic chips · shared by Relíquias, Pactos de Honra
   and Distintivos Concedidos. */
.codex__relics ul,
.codex__softskills ul,
.codex__honors ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}
/* The honors line tends to be long — keep it on a single row when it
   fits and let it wrap softly otherwise. */
.codex__honors ul li { width: 100%; max-width: 100%; }
.codex__honors ul {
  flex-direction: column;
  align-items: stretch;
  gap: 0.45rem;
}
.codex__relics li,
.codex__softskills li,
.codex__honors li {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.7rem 0.35rem 0.45rem;
  border: 1px solid var(--gold-deep);
  border-radius: 999px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.5), rgba(140, 90, 47, 0.1));
  font-family: "JetBrains Mono", monospace;
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  color: var(--ink);
  text-transform: uppercase;
  transition: transform 0.3s ease, box-shadow 0.3s ease, color 0.3s ease;
  cursor: default;
}
.codex__relics li:hover,
.codex__softskills li:hover,
.codex__honors li:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 6px 18px rgba(229, 190, 174, 0.5);
  color: var(--ember);
}
.codex__relic-rune {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background:
    radial-gradient(circle, #FFE7A0, var(--gold) 60%, var(--gold-deep));
  color: var(--ink);
  font-size: 0.95rem;
  text-shadow: 0 0 6px rgba(255, 235, 190, 0.7);
  box-shadow: inset 0 0 4px rgba(60, 30, 15, 0.4);
}

/* MANIFESTO · the architect's purpose, quoted from the CV */
.codex__sobre {
  text-align: center;
}
.codex__sobre-body {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink);
  margin: 0 auto;
  padding: 0 0.3rem;
  max-width: 38ch;
  position: relative;
  text-shadow: 0 1px 0 rgba(255, 235, 190, 0.4);
}
.codex__sobre-body::before,
.codex__sobre-body::after {
  display: inline-block;
  color: var(--gold-deep);
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 1.4rem;
  line-height: 0;
  vertical-align: -0.35em;
  opacity: 0.7;
}
.codex__sobre-body::before { content: "“"; margin-right: 0.25rem; }
.codex__sobre-body::after  { content: "”"; margin-left: 0.25rem; }

/* SINAIS DE CONVOCAÇÃO · contact runes */
.codex__contact ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.45rem;
}
.codex__contact li { margin: 0; }
.codex__contact a {
  display: grid;
  grid-template-columns: 28px 1fr;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--gold-deep);
  border-radius: 4px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.5), rgba(140, 90, 47, 0.08));
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.92rem;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: 0.02em;
  transition: transform 0.3s ease, color 0.3s ease, box-shadow 0.3s ease, background 0.3s ease;
}
.codex__contact a:hover,
.codex__contact a:focus-visible {
  transform: translateY(-1px);
  color: var(--ember);
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.7), rgba(229, 190, 174, 0.15));
  box-shadow: 0 6px 16px rgba(229, 190, 174, 0.5);
  outline: none;
}
.codex__contact-rune {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background:
    radial-gradient(circle, #FFE7A0, var(--gold) 60%, var(--gold-deep));
  color: var(--ink);
  font-size: 0.92rem;
  text-shadow: 0 0 6px rgba(255, 235, 190, 0.7);
  box-shadow: inset 0 0 4px rgba(60, 30, 15, 0.4);
}
.codex__contact-text {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  color: var(--ink);
  word-break: break-all;
}
.codex__contact a:hover .codex__contact-text,
.codex__contact a:focus-visible .codex__contact-text {
  color: var(--ember);
}

/* ============================================================
   SELOS ARCANOS · public certificates (LinkedIn-sourced)
   ------------------------------------------------------------
   Each tile is a wax-stamped certificate. The sigil column on
   the left identifies the issuing "house" via [data-house]:
     · ifrs  = Instituto Federal do RS  (forest green wax)
     · ipb   = Instituto Politécnico de Bragança (deep amber)
     · ufrgs = Universidade Federal do RS (burgundy)
   The whole tile is the link, so clicking anywhere on it opens
   the LinkedIn certifications page in a new tab.
   ============================================================ */

.codex__seals {
  position: relative;
}

.codex__seals-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
}

.codex__seals-grid > li { margin: 0; }

.codex__seal {
  display: grid;
  grid-template-columns: 36px 1fr;
  align-items: center;
  gap: 0.55rem;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--gold-deep);
  border-radius: 4px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.50), rgba(140, 90, 47, 0.08));
  color: var(--ink);
  text-decoration: none;
  position: relative;
  isolation: isolate;
  transition: transform 0.3s ease, color 0.3s ease, box-shadow 0.3s ease,
              background 0.3s ease, border-color 0.3s ease;
  min-height: 56px;
}

/* Subtle paper-texture noise on each seal, faintly visible. */
.codex__seal::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    radial-gradient(circle at 22% 28%, rgba(255, 235, 190, 0.18), transparent 55%),
    radial-gradient(circle at 78% 72%, rgba(140, 90, 47, 0.12), transparent 60%);
  z-index: -1;
  opacity: 0.85;
  pointer-events: none;
}

.codex__seal:hover,
.codex__seal:focus-visible {
  transform: translateY(-1px);
  color: var(--ember);
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.72), rgba(229, 190, 174, 0.18));
  border-color: var(--gold);
  box-shadow: 0 6px 16px rgba(229, 190, 174, 0.45);
  outline: none;
}

/* The sigil is a small wax stamp with the issuing house's letter. */
.codex__seal-sigil {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  font-family: "Cinzel", "Cormorant Garamond", serif;
  font-size: 1rem;
  font-weight: 700;
  color: #FFE7A0;
  background:
    radial-gradient(circle at 30% 30%, #C58A3E 0%, #7E4818 65%, #3A1F08 100%);
  border: 1.5px solid var(--gold);
  box-shadow:
    inset 0 0 0 1px rgba(255, 235, 190, 0.35),
    inset 0 -2px 3px rgba(0, 0, 0, 0.45),
    0 2px 4px rgba(60, 30, 15, 0.45);
  text-shadow:
    0 0 4px rgba(255, 235, 190, 0.55),
    0 1px 0 rgba(0, 0, 0, 0.55);
  flex-shrink: 0;
}

/* House-specific wax colour. The sigil glyph stays gold-ivory in all
   houses for legibility against the warm vellum background. */
.codex__seal[data-house="ifrs"] .codex__seal-sigil {
  background:
    radial-gradient(circle at 30% 30%, #5BA56C 0%, #1F4F2C 65%, #0E2A18 100%);
  border-color: #C1E5B5;
}
.codex__seal[data-house="ipb"] .codex__seal-sigil {
  background:
    radial-gradient(circle at 30% 30%, #E0A55B 0%, #8A5118 65%, #3A1F08 100%);
  border-color: #F3D58A;
}
.codex__seal[data-house="ufrgs"] .codex__seal-sigil {
  background:
    radial-gradient(circle at 30% 30%, #C45A4C 0%, #6E1F18 65%, #2E0A08 100%);
  border-color: #F0BCAE;
}

.codex__seal-body {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0; /* allows ellipsis on title */
}

.codex__seal-title {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.82rem;
  line-height: 1.18;
  color: var(--ink);
  font-weight: 600;
  letter-spacing: 0.01em;
  /* Two-line clamp for very long titles. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
          line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.codex__seal:hover .codex__seal-title,
.codex__seal:focus-visible .codex__seal-title {
  color: var(--ember);
}

.codex__seal-meta {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.58rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-deep);
  opacity: 0.85;
}

/* Footer CTA → opens the full certificates page on LinkedIn. */
.codex__seals-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0.7rem auto 0;
  padding: 0.45rem 0.85rem;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--gold-deep);
  text-decoration: none;
  border: 1px solid var(--gold-deep);
  border-radius: 999px;
  background: rgba(255, 235, 190, 0.18);
  transition: transform 0.3s ease, color 0.3s ease, background 0.3s ease,
              box-shadow 0.3s ease, border-color 0.3s ease;
  /* Centered under the grid */
  justify-content: center;
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
}

.codex__seals-cta:hover,
.codex__seals-cta:focus-visible {
  transform: translateY(-1px);
  color: var(--ember);
  background: rgba(255, 235, 190, 0.38);
  border-color: var(--gold);
  box-shadow: 0 4px 12px rgba(229, 190, 174, 0.35);
  outline: none;
}

/* On very tight columns (mobile reflow), collapse the seal grid to
   a single column so titles stay readable. */
@media (max-width: 720px) {
  .codex__seals-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   CARTOGRAFIA AMBIENTAL · public Google My Maps authored by
   Carlos during his environmental management work.
   ------------------------------------------------------------
   The thumb is a small thematic SVG (terrain grid + symbols)
   in antique-gold ink. Each tile reads like a grimoire map
   fragment: a single column of cards, each card with a
   parchment background, gold rule, and a flavour description.
   The whole card is the link, so clicking anywhere opens the
   corresponding My Maps URL in a new tab.
   ============================================================ */

.codex__cartography {
  position: relative;
}

.codex__cartography-sub {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.78rem;
  text-align: center;
  color: var(--gold-deep);
  opacity: 0.78;
  letter-spacing: 0.04em;
  margin: -0.4rem 0 0.85rem;
}

.codex__cartography-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.5rem;
}

.codex__cartography-list > li { margin: 0; }

.codex__map {
  display: grid;
  grid-template-columns: 56px 1fr;
  align-items: stretch;
  gap: 0.7rem;
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--gold-deep);
  border-radius: 4px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.50), rgba(140, 90, 47, 0.08));
  color: var(--ink);
  text-decoration: none;
  position: relative;
  isolation: isolate;
  transition: transform 0.3s ease, color 0.3s ease, box-shadow 0.3s ease,
              background 0.3s ease, border-color 0.3s ease;
  min-height: 70px;
}

/* Subtle topographic noise to make the card feel like a hand-drawn
   map fragment glued onto vellum. */
.codex__map::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  z-index: -1;
  background:
    radial-gradient(circle at 18% 25%, rgba(255, 235, 190, 0.16), transparent 55%),
    radial-gradient(circle at 82% 75%, rgba(140, 90, 47, 0.10), transparent 60%);
  opacity: 0.85;
  pointer-events: none;
}

.codex__map:hover,
.codex__map:focus-visible {
  transform: translateY(-1px);
  color: var(--ember);
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.72), rgba(229, 190, 174, 0.18));
  border-color: var(--gold);
  box-shadow: 0 6px 16px rgba(229, 190, 174, 0.45);
  outline: none;
}

/* Cartographic thumbnail — beveled vellum square with inset gold rule. */
.codex__map-thumb {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 3px;
  background:
    radial-gradient(circle at 30% 25%, rgba(255, 235, 190, 0.55), transparent 60%),
    linear-gradient(180deg, rgba(255, 235, 190, 0.45), rgba(140, 90, 47, 0.10));
  border: 1px solid var(--gold-deep);
  box-shadow:
    inset 0 0 0 1px rgba(255, 235, 190, 0.45),
    inset 0 -1px 3px rgba(60, 30, 15, 0.20);
  color: var(--gold-deep);
  align-self: center;
  flex-shrink: 0;
  overflow: hidden;
}

.codex__map-svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Per-theme ink colour for the SVG sigil so the eye spots the map's
   subject at a glance. All themes stay within the codex's gold/sepia
   palette — no neon blues or modern accents. */
.codex__map[data-theme="trail"]    .codex__map-thumb { color: #6B4A1E; }
.codex__map[data-theme="mining"]   .codex__map-thumb { color: #5A3A14; }
.codex__map[data-theme="hydro"]    .codex__map-thumb {
  color: #305A6E; /* aged ink-blue for water-themed maps */
  background:
    radial-gradient(circle at 30% 25%, rgba(220, 235, 240, 0.55), transparent 60%),
    linear-gradient(180deg, rgba(220, 235, 240, 0.45), rgba(70, 95, 120, 0.10));
}
.codex__map[data-theme="build"]    .codex__map-thumb { color: #4A2E0E; }
.codex__map[data-theme="wildlife"] .codex__map-thumb {
  color: #3F5A1E; /* aged moss-green for fauna/flora */
  background:
    radial-gradient(circle at 30% 25%, rgba(235, 240, 200, 0.55), transparent 60%),
    linear-gradient(180deg, rgba(235, 240, 200, 0.45), rgba(95, 110, 60, 0.10));
}
.codex__map[data-theme="compass"]  .codex__map-thumb { color: #7E4818; }

.codex__map-body {
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  min-width: 0;
  justify-content: center;
}

.codex__map-title {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.92rem;
  line-height: 1.18;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.01em;
}

.codex__map:hover .codex__map-title,
.codex__map:focus-visible .codex__map-title {
  color: var(--ember);
}

.codex__map-desc {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.78rem;
  line-height: 1.32;
  color: var(--ink);
  opacity: 0.82;
  /* Clamp to keep cards compact. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
          line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.codex__map-meta {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.56rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-deep);
  opacity: 0.85;
  margin-top: 0.1rem;
}

/* On extremely narrow screens the description starts to overflow the
   single card — clamp to two lines and let the title breathe. */
@media (max-width: 480px) {
  .codex__map {
    grid-template-columns: 48px 1fr;
    gap: 0.55rem;
    padding: 0.5rem 0.55rem;
  }
  .codex__map-thumb { width: 48px; height: 48px; }
  .codex__map-desc { -webkit-line-clamp: 2; line-clamp: 2; }
}

/* Page numbers */
.codex__page-num {
  text-align: center;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.65rem;
  letter-spacing: 0.4em;
  color: var(--gold-deep);
  margin: 1.4rem 0 0;
  opacity: 0.7;
}

/* OUTORGA SELADA · CV download card. Lives inside the spread grid so
   it appears at the very end of the codex scroll. Spans both pages of
   the spread via grid-column: 1 / -1, with auto-margins centering the
   capped width inside that wide cell. */
.codex__download {
  grid-column: 1 / -1;
  position: relative;
  z-index: 2;
  margin: 1.6rem auto 0.4rem;
  padding: 1.1rem 1.2rem 1.2rem;
  max-width: 520px;
  text-align: center;
  border: 1px solid var(--gold-deep);
  border-radius: 4px;
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(255, 235, 190, 0.55), transparent 70%),
    linear-gradient(180deg, rgba(255, 235, 190, 0.18), rgba(140, 90, 47, 0.08));
  box-shadow:
    inset 0 0 0 1px rgba(255, 235, 190, 0.35),
    0 10px 30px rgba(70, 40, 20, 0.35);
}
.codex__download::before,
.codex__download::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 1px solid var(--gold-deep);
  opacity: 0.85;
}
.codex__download::before {
  top: -1px;
  left: -1px;
  border-right: none;
  border-bottom: none;
}
.codex__download::after {
  bottom: -1px;
  right: -1px;
  border-left: none;
  border-top: none;
}
.codex__download-title {
  margin: 0 0 0.3rem;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.72rem;
  letter-spacing: 0.36em;
  color: var(--gold-deep);
  text-transform: uppercase;
}
.codex__download-title::before,
.codex__download-title::after {
  content: "✦";
  font-size: 0.62rem;
  margin: 0 0.5rem;
  color: var(--gold);
  vertical-align: middle;
}
.codex__download-sub {
  margin: 0 0 0.85rem;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.95rem;
  color: var(--ink);
  opacity: 0.9;
}
.codex__download-btn {
  display: inline-grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.85rem;
  padding: 0.65rem 1rem 0.65rem 0.8rem;
  border: 1px solid var(--gold-deep);
  border-radius: 4px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.65), rgba(140, 90, 47, 0.18));
  color: var(--ink);
  text-decoration: none;
  position: relative;
  overflow: hidden;
  transition:
    transform 0.35s cubic-bezier(.2,.7,.2,1),
    box-shadow 0.35s ease,
    color 0.3s ease,
    background 0.35s ease;
  box-shadow:
    inset 0 0 0 1px rgba(255, 235, 190, 0.35),
    0 4px 12px rgba(70, 40, 20, 0.25);
}
.codex__download-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(120deg, transparent 30%, rgba(255, 235, 190, 0.45) 50%, transparent 70%);
  transform: translateX(-110%);
  transition: transform 0.7s ease;
  pointer-events: none;
}
.codex__download-btn:hover,
.codex__download-btn:focus-visible {
  transform: translateY(-2px);
  color: var(--ember);
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.85), rgba(229, 190, 174, 0.25));
  box-shadow:
    inset 0 0 0 1px rgba(255, 235, 190, 0.55),
    0 10px 24px rgba(229, 190, 174, 0.55);
  outline: none;
}
.codex__download-btn:hover::before,
.codex__download-btn:focus-visible::before {
  transform: translateX(110%);
}
.codex__download-icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background:
    radial-gradient(circle, #FFE7A0, var(--gold) 60%, var(--gold-deep));
  color: var(--ink);
  text-shadow: 0 0 6px rgba(255, 235, 190, 0.7);
  box-shadow: inset 0 0 4px rgba(60, 30, 15, 0.4);
}
.codex__download-text {
  display: grid;
  text-align: left;
  line-height: 1.25;
}
.codex__download-text strong {
  font-family: "Libre Caslon Text", "Cormorant Garamond", serif;
  font-size: 1rem;
  letter-spacing: 0.04em;
  color: inherit;
  font-weight: 700;
}
.codex__download-text em {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  font-style: normal;
  text-transform: uppercase;
  color: var(--gold-deep);
  margin-top: 0.15rem;
}
.codex__download-btn:hover .codex__download-text em,
.codex__download-btn:focus-visible .codex__download-text em {
  color: var(--ember);
}
.codex__download-seal {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  font-size: 0.95rem;
  color: var(--gold-deep);
  filter: drop-shadow(0 0 4px rgba(229, 190, 174, 0.5));
  transition: transform 0.6s ease;
}
.codex__download-btn:hover .codex__download-seal,
.codex__download-btn:focus-visible .codex__download-seal {
  transform: rotate(45deg);
  color: var(--ember);
}
@media (max-width: 520px) {
  .codex__download { padding: 0.95rem 0.8rem 1rem; }
  .codex__download-btn {
    grid-template-columns: auto 1fr;
    gap: 0.7rem;
    padding: 0.6rem 0.8rem;
  }
  .codex__download-seal { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .codex__download-btn,
  .codex__download-btn::before,
  .codex__download-seal {
    transition: none;
  }
  .codex__download-btn:hover,
  .codex__download-btn:focus-visible { transform: none; }
}

/* SEAL footer */
.codex__seal {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.8rem;
  margin-top: 1.4rem;
  position: relative;
  z-index: 2;
  text-align: center;
}
.codex__seal-line {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-deep), transparent);
}
.codex__seal-mark {
  color: var(--gold-deep);
  filter: drop-shadow(0 0 8px rgba(229, 190, 174, 0.6));
}
.codex__seal-text {
  grid-column: 1 / -1;
  margin: 0.3rem 0 0;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.36em;
  color: var(--gold-deep);
  text-transform: uppercase;
}

/* Scroll-in for sections inside the codex */
.codex.is-open .codex__page > *,
.codex.is-open .codex__head > *,
.codex.is-open .codex__seal > * {
  animation: codex-fade-up 0.9s cubic-bezier(.2,.7,.2,1) both;
}
.codex.is-open .codex__head > *:nth-child(1) { animation-delay: 0.1s; }
.codex.is-open .codex__head > *:nth-child(2) { animation-delay: 0.18s; }
.codex.is-open .codex__head > *:nth-child(3) { animation-delay: 0.28s; }
.codex.is-open .codex__page--left > *:nth-child(1) { animation-delay: 0.36s; }
.codex.is-open .codex__page--left > *:nth-child(2) { animation-delay: 0.46s; }
.codex.is-open .codex__page--left > *:nth-child(3) { animation-delay: 0.54s; }
.codex.is-open .codex__page--left > *:nth-child(4) { animation-delay: 0.62s; }
.codex.is-open .codex__page--left > *:nth-child(5) { animation-delay: 0.7s; }
.codex.is-open .codex__page--right > *:nth-child(1) { animation-delay: 0.46s; }
.codex.is-open .codex__page--right > *:nth-child(2) { animation-delay: 0.56s; }
.codex.is-open .codex__page--right > *:nth-child(3) { animation-delay: 0.66s; }
.codex.is-open .codex__page--right > *:nth-child(4) { animation-delay: 0.74s; }
.codex.is-open .codex__page--right > *:nth-child(5) { animation-delay: 0.82s; }
@keyframes codex-fade-up {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* RESPONSIVE */
@media (max-width: 980px) {
  .codex__book {
    padding: 2.6rem 1.2rem 1.6rem;
    width: 96vw;
    max-height: 94vh;
  }
  .codex__close { right: 18px; top: 14px; }
  .codex__corner { width: 36px; height: 36px; }
  .codex__corner--tl { top: 8px; left: 8px; }
  .codex__corner--tr { top: 8px; right: 8px; }
  .codex__corner--bl { bottom: 8px; left: 8px; }
  .codex__corner--br { bottom: 8px; right: 8px; }
  .codex__spread {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    max-height: calc(94vh - 200px);
    padding: 0 0.4rem;
  }
  .codex__spine {
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--gold-deep), transparent);
    margin: 0.6rem 0;
  }
  .codex__portrait-frame { width: 160px; height: 192px; }
  .codex__langs li { grid-template-columns: 5em 1fr 4.5em; }
}
@media (max-width: 480px) {
  .codex__book { padding: 2rem 0.8rem 1.2rem; }
  .codex__title { font-size: 1.5rem; }
  .codex__subtitle { font-size: 0.85rem; }
  .codex__lang-tag { display: none; }
  .codex__langs li { grid-template-columns: 5em 1fr; }
  .codex__relic-rune { width: 20px; height: 20px; font-size: 0.8rem; }
  .codex__relics li { font-size: 0.66rem; padding: 0.3rem 0.55rem 0.3rem 0.4rem; }
}

@media (prefers-reduced-motion: reduce) {
  .codex__book,
  .codex.is-open .codex__page > *,
  .codex.is-open .codex__head > *,
  .codex.is-open .codex__seal > * { animation: none !important; transition: opacity 0.4s ease; }
  .hero__portrait.is-codex-active::before,
  .hero__portrait.is-codex-active .hero__portrait-frame,
  .hero__portrait.is-codex-active .hero__rune-ring,
  .codex__chronicles li.is-now::before { animation: none; }
  .codex__bar-fill,
  .codex__attr-fill { animation: none; transform: scaleX(1); }
}

/* ============================================================
   CODEX DOS CONTRATOS ARCANOS · Capítulo IV
   The same parchment-bound book language as the Codex do
   Arquiteto, but rendered as inline page-flow chapters. Each
   service is its own open spread (left page = description,
   right page = pricing & specifications). Rarity tints the
   gem, dividers, perk runes and CTA — never the parchment.
============================================================ */
.contracts {
  position: relative;
  z-index: 5;
  padding: 3.4rem 1.5rem 3.8rem;
  /* Inherit codex tokens so this section IS another chapter
     of the same book. */
  --gold:        #C2A46B;
  --gold-bright: #E5BEAE;
  --gold-deep:   #8C5A2F;
  --ember:       #A13E1E;
  --ink:         #271812;
  --ink-soft:    #5C3F2A;
  --parchment-1: #F4E2C2;
  --parchment-2: #E6CFA0;
  --parchment-3: #D9B47B;
}

/* Wallpaper window — DISABLED (June 2026 phantom-border fix).
   The previous radial-gradient(ellipse at top, ..., transparent 55%)
   covered the entire section rectangle. Even at 0.06 alpha, the
   gradient was clipped at the section's edges and read as a
   semi-transparent rectangle around the Codex header — exactly the
   "inspector outline" look the user reported. The Skill Tree
   wallpaper now shines through unobstructed; every contract book
   already carries its own contrast via .contract__book gradients. */
.contracts::before {
  content: none;
  background: none;
  display: none;
}

.contracts__head {
  text-align: center;
  margin: 0 auto 2rem;
  max-width: 720px;
  position: relative;
}
.contracts__eyebrow {
  font-family: "JetBrains Mono", monospace;
  letter-spacing: 0.4em;
  font-size: 0.66rem;
  color: var(--gold);
  margin: 0 0 0.55rem;
}
.contracts__title {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: clamp(1.5rem, 2.8vw, 2.15rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  margin: 0;
  background: linear-gradient(180deg, var(--gold-bright) 30%, var(--gold-deep) 90%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.35);
}
.contracts__subtitle {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: clamp(0.85rem, 1.3vw, 1rem);
  color: rgba(229, 190, 174, 0.78);
  margin: 0.55rem auto 0;
  letter-spacing: 0.05em;
  max-width: 580px;
}
.contracts__crown {
  display: flex;
  justify-content: center;
  margin-top: 1rem;
  color: var(--gold-deep);
  opacity: 0.85;
}
.contracts__crown svg {
  width: min(340px, 60%);
  height: 22px;
}

/* List of contract books — narrower so wallpaper breathes
   on either side. */
.contracts__list {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2.2rem;
  max-width: 880px;
}
.contract { position: relative; }

/* THE BOOK — parchment spread, mirroring .codex__book.
   Phantom-border fix (June 2026): the previous box-shadow stack
   layered THREE solid "ring" shadows (0 0 0 1px / 4px / 5px)
   which projected a hard rectangular frame around every card —
   the user reported it as a "borda fantasma" in the Codex.
   The frame has been replaced by a single hairline gold inner
   highlight + outer halo + drop shadow, so the parchment now
   floats over the wallpaper without a perceptible rectangle. */
.contract__book {
  position: relative;
  background:
    radial-gradient(ellipse at top, rgba(255, 235, 200, 0.18), transparent 55%),
    radial-gradient(ellipse at bottom, rgba(140, 90, 47, 0.18), transparent 60%),
    linear-gradient(180deg, var(--parchment-1) 0%, var(--parchment-2) 60%, var(--parchment-3) 100%);
  color: var(--ink);
  border-radius: 14px;
  padding: 1.8rem 1.4rem 1.4rem;
  box-shadow:
    inset 0 0 0 1px rgba(194, 164, 107, 0.18),
    0 18px 44px rgba(0, 0, 0, 0.45),
    0 0 80px var(--rarity-glow, rgba(229, 190, 174, 0.10));
  font-family: "Libre Caslon Text", "Cormorant Garamond", Georgia, serif;
  overflow: hidden;
  transition:
    transform 0.5s cubic-bezier(.18, .7, .16, 1.05),
    box-shadow 0.6s ease;
  outline: none;
}
.contract__book::before {
  /* Dotted parchment texture (matches codex) */
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(rgba(140, 90, 47, 0.08) 1px, transparent 1.5px),
    radial-gradient(rgba(60, 35, 15, 0.05) 1px, transparent 1.5px);
  background-size: 4px 4px, 6px 6px;
  background-position: 0 0, 2px 3px;
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: 0.85;
  z-index: 1;
}
.contract__book::after {
  /* Burnt vignette (matches codex) */
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at top left, rgba(80, 30, 10, 0.32), transparent 35%),
    radial-gradient(ellipse at bottom right, rgba(80, 30, 10, 0.34), transparent 40%),
    radial-gradient(ellipse at center, transparent 55%, rgba(60, 25, 10, 0.4) 100%);
  mix-blend-mode: multiply;
  transition: opacity 0.6s ease;
  z-index: 1;
}

/* Decorative gold corners (matches codex) */
.contract__corner {
  position: absolute;
  width: 38px;
  height: 38px;
  pointer-events: none;
  background:
    linear-gradient(135deg, transparent 35%, var(--gold) 35%, var(--gold-bright) 50%, var(--gold) 65%, transparent 65%);
  opacity: 0.85;
  z-index: 3;
}
.contract__corner--tl { top: 10px; left: 10px; transform: rotate(0); }
.contract__corner--tr { top: 10px; right: 10px; transform: rotate(90deg); }
.contract__corner--bl { bottom: 10px; left: 10px; transform: rotate(-90deg); }
.contract__corner--br { bottom: 10px; right: 10px; transform: rotate(180deg); }
.contract__corner::before,
.contract__corner::after {
  content: "";
  position: absolute;
  background: var(--gold-deep);
}
.contract__corner::before { top: 0; left: 0; width: 26px; height: 1px; }
.contract__corner::after  { top: 0; left: 0; width: 1px; height: 26px; }

/* Spread: two pages + spine, with ink-wash overlay */
.contract__spread {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 2px 1fr;
  gap: 1.2rem;
  z-index: 2;
}
/* Ink-wash that fades in on hover — feels like an arcane stain
   spreading across the parchment as the contract is scrutinised. */
.contract__spread::before {
  content: "";
  position: absolute;
  inset: -1.8rem -1.4rem -1.4rem;
  background:
    radial-gradient(ellipse at center, var(--rarity-glow, rgba(229, 190, 174, 0.18)) 0%, transparent 60%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.8s ease;
  mix-blend-mode: screen;
  z-index: 0;
}
.contract__page {
  position: relative;
  padding: 0.3rem 0.6rem 0.45rem;
  z-index: 2;
}
.contract__spine {
  position: relative;
  background:
    linear-gradient(180deg,
      transparent 0,
      rgba(60, 30, 15, 0.45) 8%,
      rgba(60, 30, 15, 0.65) 50%,
      rgba(60, 30, 15, 0.45) 92%,
      transparent 100%);
  box-shadow:
    -2px 0 6px rgba(60, 30, 15, 0.3),
     2px 0 6px rgba(60, 30, 15, 0.3);
  z-index: 2;
}

/* Watermarks — subtle alchemy glyphs (same SVGs as codex) */
.contract__watermark {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><g fill='none' stroke='%238c5a2f' stroke-width='0.7'><circle cx='100' cy='100' r='70'/><circle cx='100' cy='100' r='38'/><path d='M100 30 L108 64 L142 60 L116 84 L130 118 L100 102 L70 118 L84 84 L58 60 L92 64 Z'/><line x1='30' y1='100' x2='170' y2='100' stroke-width='0.5'/><line x1='100' y1='30' x2='100' y2='170' stroke-width='0.5'/></g></svg>");
  background-repeat: no-repeat;
  background-position: center 38%;
  background-size: 60% auto;
  opacity: 0.13;
}
.contract__watermark--alt {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><g fill='none' stroke='%238c5a2f' stroke-width='0.7'><rect x='40' y='40' width='120' height='120' rx='6'/><circle cx='100' cy='100' r='42'/><path d='M100 58 V142 M58 100 H142 M71 71 L129 129 M129 71 L71 129'/><circle cx='100' cy='100' r='10'/></g></svg>");
  opacity: 0.1;
}

/* Rarity tag at the top of left page */
.contract__rarity {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.28rem 0.75rem 0.28rem 0.45rem;
  border: 1px solid var(--rarity-accent-deep, var(--gold-deep));
  border-radius: 999px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.5), rgba(140, 90, 47, 0.1));
  font-family: "JetBrains Mono", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.3em;
  color: var(--ink);
  text-transform: uppercase;
  margin: 0 0 0.8rem;
}
.contract__gem {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  color: var(--rarity-accent, var(--gold));
  background:
    radial-gradient(circle, rgba(255, 235, 190, 0.85), rgba(140, 90, 47, 0.15) 70%);
  box-shadow:
    inset 0 0 4px rgba(60, 30, 15, 0.4),
    0 0 6px var(--rarity-glow, transparent);
  transition: box-shadow 0.45s ease, transform 0.45s ease;
}
.contract__gem svg {
  display: block;
  filter: drop-shadow(0 0 2px var(--rarity-glow, transparent));
}

/* Service name & subtitle */
.contract__name {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: clamp(1.2rem, 1.9vw, 1.55rem);
  font-weight: 700;
  letter-spacing: 0.03em;
  margin: 0 0 0.25rem;
  text-shadow: 0 1px 0 rgba(255, 235, 190, 0.5);
  background: linear-gradient(180deg, var(--ink) 30%, var(--rarity-accent-deep, var(--gold-deep)) 90%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.contract__class {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.9rem;
  color: var(--ember);
  margin: 0;
  letter-spacing: 0.06em;
}

/* Divider with central glyph (matches codex) */
.contract__divider {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0.85rem 0 0.7rem;
  color: var(--rarity-accent-deep, var(--gold-deep));
}
.contract__divider::before,
.contract__divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background:
    linear-gradient(90deg,
      transparent,
      var(--rarity-accent-deep, var(--gold-deep)) 30%,
      var(--rarity-accent-bright, var(--gold-bright)) 50%,
      var(--rarity-accent-deep, var(--gold-deep)) 70%,
      transparent);
  opacity: 0.7;
}
.contract__divider-mark {
  font-size: 0.95rem;
  color: var(--rarity-accent, var(--gold));
  text-shadow: 0 0 6px var(--rarity-glow, rgba(229, 190, 174, 0.6));
}

/* Description meta list (Propósito · Tecnologias · Prazo) */
.contract__meta {
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
}
.contract__meta > div {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.12rem;
}
.contract__meta dt {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.6rem;
  letter-spacing: 0.3em;
  color: var(--rarity-accent-deep, var(--gold-deep));
  text-transform: uppercase;
}
.contract__meta dd {
  margin: 0;
  font-size: 0.92rem;
  color: var(--ink);
  line-height: 1.45;
}

/* Right page · Section headings (mirrors codex h4 style) */
.contract__specs h4,
.contract__perks h4 {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.66rem;
  letter-spacing: 0.32em;
  color: var(--rarity-accent-deep, var(--gold-deep));
  text-transform: uppercase;
  margin: 0 0 0.55rem;
  text-align: center;
}
.contract__specs h4::before,
.contract__specs h4::after,
.contract__perks h4::before,
.contract__perks h4::after {
  content: "✦";
  font-size: 0.55rem;
  margin: 0 0.35rem;
  color: var(--rarity-accent, var(--gold));
  vertical-align: middle;
}

/* Specs list (Raridade · Investimento · Dificuldade · Poder) */
.contract__specs ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.4rem;
}
.contract__specs li {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.6rem;
  padding: 0.26rem 0;
  border-bottom: 1px dashed rgba(140, 90, 47, 0.35);
}
.contract__specs li:last-child { border-bottom: 0; }
.contract__spec-name {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.88rem;
  color: var(--ink-soft);
  letter-spacing: 0.04em;
}
.contract__spec-val {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.78rem;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-align: right;
}

/* Investment cell — bigger price stack */
.contract__price {
  display: grid;
  text-align: right;
  font-family: "Libre Caslon Text", Georgia, serif;
}
.contract__price strong {
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  color: var(--ember);
  text-shadow: 0 0 8px var(--rarity-glow, rgba(229, 190, 174, 0.4));
}
.contract__price em {
  font-style: normal;
  font-size: 0.72rem;
  font-family: "Cormorant Garamond", serif;
  color: var(--ink-soft);
  letter-spacing: 0.06em;
  margin-top: 1px;
}

/* ════════════════════════════════════════════════════════════════
   ✦ CONVERGÊNCIAS ARCANAS ✦  · a living cosmic event
   A single contract is "blessed" each 10-day cycle. Aged-gold seal,
   struck original price, blessed value, and a live countdown — all
   built to read as a rare artefact, never a Black-Friday banner.
   DOM is injected by convergence.js; everything here is scoped to
   .contract--convergent / .convergence so untouched cards are inert.
   ════════════════════════════════════════════════════════════════ */
@property --conv-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

/* The favoured book lifts subtly and gains a warmer aura. */
.contract--convergent .contract__book {
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.38),
    0 22px 52px rgba(0, 0, 0, 0.5),
    0 0 70px rgba(242, 200, 121, 0.18);
}

/* ── The seal ribbon (top of the blessed book) ─────────────────── */
.convergence-seal {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  width: fit-content;
  max-width: 92%;
  margin: 0 auto 1.25rem;
  padding: 0.4rem 1.15rem;
  border-radius: 999px;
  overflow: hidden;
  font-family: "Cinzel", "Libre Caslon Text", Georgia, serif;
  font-size: 0.62rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #3a230c;
  background:
    linear-gradient(180deg, rgba(255, 244, 214, 0.92), rgba(228, 197, 130, 0.92) 48%, rgba(192, 150, 80, 0.94));
  box-shadow:
    inset 0 1px 0 rgba(255, 248, 224, 0.85),
    inset 0 -1px 2px rgba(110, 76, 30, 0.5),
    0 0 0 1px rgba(110, 76, 30, 0.35),
    0 0 22px rgba(242, 200, 121, 0.4);
  animation: conv-seal-pulse 3.8s ease-in-out infinite;
}
.convergence-seal__rune {
  font-size: 0.72rem;
  color: #6e4c1e;
  text-shadow: 0 0 6px rgba(242, 200, 121, 0.7);
}
.convergence-seal__text { position: relative; z-index: 2; font-weight: 600; }
.convergence-seal__edge {
  position: absolute;
  inset: 2px;
  border-radius: 999px;
  border: 1px solid rgba(110, 76, 30, 0.35);
  pointer-events: none;
}
.convergence-seal__sheen {
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    transparent 35%, rgba(255, 248, 222, 0.6) 50%, transparent 65%);
  transform: translateX(-130%);
  animation: conv-seal-sheen 6.5s ease-in-out infinite;
}

@keyframes conv-seal-pulse {
  0%, 100% { box-shadow:
    inset 0 1px 0 rgba(255, 248, 224, 0.85),
    inset 0 -1px 2px rgba(110, 76, 30, 0.5),
    0 0 0 1px rgba(110, 76, 30, 0.35),
    0 0 18px rgba(242, 200, 121, 0.32); }
  50% { box-shadow:
    inset 0 1px 0 rgba(255, 248, 224, 0.85),
    inset 0 -1px 2px rgba(110, 76, 30, 0.5),
    0 0 0 1px rgba(110, 76, 30, 0.35),
    0 0 30px rgba(242, 200, 121, 0.55); }
}
@keyframes conv-seal-sheen {
  0%   { transform: translateX(-130%); }
  22%  { transform: translateX(130%); }
  100% { transform: translateX(130%); }
}

/* ── Inline blessed price (in the specs list) ──────────────────── */
.contract__price.is-blessed { gap: 0.05rem; }
.contract__price.is-blessed .is-struck {
  text-decoration: line-through;
  text-decoration-color: rgba(168, 60, 38, 0.85);
  text-decoration-thickness: 1.5px;
  opacity: 0.82;
  font-weight: 600;
  font-size: 0.8em;
}
.contract__price-new {
  display: grid;
  margin-top: 2px;
}
.contract__price-new strong {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 1rem;
  letter-spacing: 0.04em;
  color: #8a5a1a;
  text-shadow: 0 0 10px rgba(242, 200, 121, 0.5);
}
.contract__price-new em {
  font-style: normal;
  font-size: 0.72rem;
  font-family: "Cormorant Garamond", serif;
  letter-spacing: 0.06em;
  color: #6e4c1e;
  margin-top: 1px;
}

/* ── The convergence panel (above the CTA) ─────────────────────── */
.convergence {
  --conv-cut: 13px;                 /* chamfer for the beveled tablet */
  position: relative;
  overflow: hidden;
  margin: 0.35rem 0 1.25rem;
  padding: 1.45rem 1.35rem 1.35rem;
  text-align: center;
  background:
    radial-gradient(ellipse at 50% -12%, rgba(255, 244, 214, 0.78), transparent 60%),
    radial-gradient(ellipse at 50% 116%, rgba(242, 200, 121, 0.34), transparent 62%),
    radial-gradient(circle at 50% 62%, rgba(255, 236, 196, 0.4), transparent 58%),
    linear-gradient(180deg, rgba(255, 249, 233, 0.74), rgba(235, 212, 167, 0.56));
  /* Beveled arcane-tablet silhouette (cut corners) for a more
     interesting, artefact-like format than a plain rectangle. */
  clip-path: polygon(
    var(--conv-cut) 0, calc(100% - var(--conv-cut)) 0,
    100% var(--conv-cut), 100% calc(100% - var(--conv-cut)),
    calc(100% - var(--conv-cut)) 100%, var(--conv-cut) 100%,
    0 calc(100% - var(--conv-cut)), 0 var(--conv-cut));
  box-shadow:
    inset 0 0 0 1px rgba(110, 76, 30, 0.3),
    inset 0 1px 0 rgba(255, 250, 232, 0.75),
    inset 0 0 34px rgba(255, 236, 195, 0.5),
    0 12px 34px rgba(70, 44, 14, 0.2),
    0 0 40px rgba(242, 200, 121, 0.34);
  isolation: isolate;
  transition:
    transform 0.5s cubic-bezier(.2, .7, .2, 1),
    box-shadow 0.5s ease,
    filter 0.5s ease;
}

/* Breathing arcane aura — the rectangle glows from within and
   pulses gently, so the eye is drawn to the blessed offer. */
.convergence::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at 50% 44%, rgba(242, 200, 121, 0.26), transparent 66%);
  animation: conv-aura-breathe 5.6s ease-in-out infinite;
}
@keyframes conv-aura-breathe {
  0%, 100% { opacity: 0.55; transform: scale(0.97); }
  50%      { opacity: 1;    transform: scale(1.015); }
}

/* A slow sheen that sweeps the tablet — and snaps brighter on hover. */
.convergence::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(108deg,
    transparent 38%, rgba(255, 249, 226, 0.5) 50%, transparent 62%);
  transform: translateX(-130%);
  animation: conv-panel-sheen 7.5s ease-in-out infinite;
}
@keyframes conv-panel-sheen {
  0%   { transform: translateX(-130%); }
  26%  { transform: translateX(130%); }
  100% { transform: translateX(130%); }
}

/* Interactive: lifting the blessed offer intensifies its glow,
   speeds the orbiting frame and brightens the whole artefact. */
.convergence:hover {
  transform: translateY(-3px) scale(1.012);
  filter: saturate(1.08);
  box-shadow:
    inset 0 0 0 1px rgba(140, 96, 40, 0.42),
    inset 0 1px 0 rgba(255, 250, 232, 0.85),
    inset 0 0 42px rgba(255, 238, 198, 0.6),
    0 18px 44px rgba(70, 44, 14, 0.26),
    0 0 58px rgba(242, 200, 121, 0.52);
}
.convergence:hover .convergence__frame { animation-duration: 3.2s; }
.convergence:hover::after { animation-duration: 1.4s; }

/* Energy travelling the frame — a bright arc orbiting a faint ring. */
.convergence__frame {
  position: absolute;
  inset: 0;
  padding: 2px;
  clip-path: polygon(
    var(--conv-cut) 0, calc(100% - var(--conv-cut)) 0,
    100% var(--conv-cut), 100% calc(100% - var(--conv-cut)),
    calc(100% - var(--conv-cut)) 100%, var(--conv-cut) 100%,
    0 calc(100% - var(--conv-cut)), 0 var(--conv-cut));
  background:
    conic-gradient(from var(--conv-angle),
      rgba(201, 161, 95, 0.3) 0deg,
      rgba(201, 161, 95, 0.3) 54deg,
      rgba(242, 200, 121, 1) 104deg,
      rgba(255, 250, 224, 1) 126deg,
      rgba(242, 200, 121, 1) 148deg,
      rgba(201, 161, 95, 0.3) 200deg,
      rgba(201, 161, 95, 0.3) 360deg);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  filter: drop-shadow(0 0 6px rgba(242, 200, 121, 0.55));
  animation: conv-frame-orbit 7.5s linear infinite;
  pointer-events: none;
  z-index: 1;
}
@keyframes conv-frame-orbit { to { --conv-angle: 360deg; } }

.convergence__body { position: relative; z-index: 2; }

.convergence__eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0 0 0.45rem;
  font-family: "Cinzel", "Libre Caslon Text", Georgia, serif;
  font-size: 0.6rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: #8a5a1a;
}
.convergence__eyebrow span {
  color: #b88a3c;
  text-shadow: 0 0 8px rgba(242, 200, 121, 0.7);
}
.convergence__copy {
  margin: 0 auto 0.7rem;
  max-width: 30ch;
  font-family: "Cormorant Garamond", serif;
  font-size: 0.94rem;
  font-weight: 500;
  font-style: italic;
  line-height: 1.45;
  color: var(--ink, #341809);
}
.convergence__blessing {
  margin: 0 0 0.7rem;
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: #623f12;
}
.convergence__blessing-val {
  margin-left: 0.3rem;
  padding: 0.06rem 0.5rem;
  border-radius: 999px;
  font-weight: 700;
  color: #4a2e0c;
  background: linear-gradient(180deg, rgba(255, 240, 205, 0.9), rgba(231, 199, 122, 0.9));
  box-shadow: inset 0 0 0 1px rgba(110, 76, 30, 0.3), 0 0 14px rgba(242, 200, 121, 0.45);
}

.convergence__prices {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  margin: 0.2rem 0 0.55rem;
}
.convergence__old {
  display: flex;
  gap: 0.65rem;
  font-family: "Cormorant Garamond", serif;
  font-size: 0.92rem;
  font-weight: 600;
  color: rgba(86, 50, 22, 0.92);
}
.convergence__old s {
  text-decoration-color: rgba(168, 60, 38, 0.9);
  text-decoration-thickness: 1.5px;
}
.convergence__arrow {
  font-size: 0.9rem;
  line-height: 1;
  color: #b88a3c;
  animation: conv-arrow-fall 2.6s ease-in-out infinite;
}
@keyframes conv-arrow-fall {
  0%, 100% { transform: translateY(-1px); opacity: 0.55; }
  50%      { transform: translateY(2px);  opacity: 1; }
}
.convergence__new {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.7rem;
  padding: 0.15rem 0.9rem;
}
/* Soft spotlight that makes the blessed value the hero of the panel. */
.convergence__new::before {
  content: "";
  position: absolute;
  inset: -40% -10%;
  z-index: -1;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(255, 240, 200, 0.65), rgba(242, 200, 121, 0.22) 45%, transparent 72%);
  pointer-events: none;
}
.convergence__new strong {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 1.58rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #7e4f12;
  text-shadow: 0 0 18px rgba(242, 200, 121, 0.7), 0 1px 0 rgba(255, 250, 230, 0.6);
}
.convergence__new em {
  font-style: normal;
  font-family: "Cormorant Garamond", serif;
  font-size: 1rem;
  font-weight: 600;
  color: #5f3f12;
}

.convergence__rule {
  height: 1px;
  margin: 0.4rem auto 0.7rem;
  width: 70%;
  background: linear-gradient(90deg, transparent, rgba(110, 76, 30, 0.4), transparent);
}

.convergence__countdown-label {
  margin: 0 0 0.45rem;
  font-family: "Cinzel", "Libre Caslon Text", Georgia, serif;
  font-size: 0.56rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: #8a5a1a;
}
.convergence__timer {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 0.35rem;
}
.convergence__unit {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 2.4rem;
}
.convergence__unit b {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 1.28rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #4f3210;
  text-shadow: 0 0 12px rgba(242, 200, 121, 0.45);
}
.convergence__unit i {
  margin-top: 1px;
  font-style: normal;
  font-family: "Cormorant Garamond", serif;
  font-size: 0.56rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(90, 55, 25, 0.7);
}
.convergence__sep {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 1.1rem;
  line-height: 1.1;
  color: rgba(110, 76, 30, 0.4);
}

/* Drifting motes — discrete sparks of escaping energy. */
.convergence__motes { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.convergence__motes i {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 246, 214, 0.95), rgba(242, 200, 121, 0) 70%);
  opacity: 0;
  animation: conv-mote 7s ease-in-out infinite;
}
.convergence__motes i:nth-child(1) { left: 12%; bottom: 14%; animation-delay: 0s;    }
.convergence__motes i:nth-child(2) { left: 34%; bottom: 8%;  animation-delay: 1.6s;  }
.convergence__motes i:nth-child(3) { left: 56%; bottom: 18%; animation-delay: 3.1s;  }
.convergence__motes i:nth-child(4) { left: 72%; bottom: 10%; animation-delay: 0.9s;  }
.convergence__motes i:nth-child(5) { left: 86%; bottom: 22%; animation-delay: 2.4s;  }
.convergence__motes i:nth-child(6) { left: 22%; bottom: 26%; animation-delay: 4.2s;  }
@keyframes conv-mote {
  0%   { opacity: 0; transform: translateY(0) scale(0.7); }
  18%  { opacity: 0.85; }
  60%  { opacity: 0.5; }
  100% { opacity: 0; transform: translateY(-34px) scale(1.1); }
}

/* ── Dark theme (Vesper): parchment stays cream, so the gold reads
   the same — only deepen the panel base a touch for contrast. ──── */
html[data-theme="light"] .convergence {
  background:
    radial-gradient(ellipse at 50% -12%, rgba(255, 240, 205, 0.82), transparent 60%),
    radial-gradient(ellipse at 50% 116%, rgba(242, 200, 121, 0.36), transparent 62%),
    radial-gradient(circle at 50% 62%, rgba(255, 238, 198, 0.42), transparent 58%),
    linear-gradient(180deg, rgba(255, 250, 238, 0.82), rgba(238, 218, 178, 0.6));
}

/* ── Responsive ────────────────────────────────────────────────── */
@media (max-width: 600px) {
  .convergence__new strong { font-size: 1.3rem; }
  .convergence__unit { min-width: 2rem; }
  .convergence__unit b { font-size: 1.05rem; }
  .convergence-seal { letter-spacing: 0.18em; font-size: 0.56rem; }
}

@media (prefers-reduced-motion: reduce) {
  .convergence-seal,
  .convergence-seal__sheen,
  .convergence__frame,
  .convergence__arrow,
  .convergence__motes i,
  .convergence::before,
  .convergence::after {
    animation: none !important;
  }
  .convergence-seal__sheen,
  .convergence::after { display: none; }
  .convergence:hover { transform: none; }
  .convergence__frame { background:
    linear-gradient(180deg, rgba(242, 200, 121, 0.7), rgba(201, 161, 95, 0.45)); }
}

/* Difficulty stars */
.contract__stars {
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 0.88rem;
  letter-spacing: 0.16em;
  color: var(--rarity-accent, var(--gold-deep));
  text-shadow: 0 0 6px var(--rarity-glow, rgba(229, 190, 174, 0.4));
}
.contract__stars .off {
  color: rgba(60, 30, 15, 0.25);
  text-shadow: none;
}

/* Power bar (mirrors codex __attr-bar) */
.contract__power-bar {
  position: relative;
  width: 7rem;
  height: 9px;
  background:
    repeating-linear-gradient(90deg,
      rgba(140, 90, 47, 0.4) 0,
      rgba(140, 90, 47, 0.4) 1px,
      transparent 1px,
      transparent 10%),
    rgba(60, 30, 15, 0.18);
  border: 1px solid var(--rarity-accent-deep, var(--gold-deep));
  border-radius: 1px;
  overflow: hidden;
  justify-self: end;
}
.contract__power-fill {
  display: block;
  height: 100%;
  width: var(--w);
  background:
    linear-gradient(90deg,
      var(--rarity-accent-deep, var(--gold-deep)),
      var(--rarity-accent, var(--gold)) 50%,
      var(--rarity-accent-bright, var(--ember)));
  box-shadow:
    0 0 10px var(--rarity-glow, rgba(229, 190, 174, 0.7)),
    inset 0 0 4px rgba(255, 235, 190, 0.5);
  transform-origin: left;
  transform: scaleX(0);
}
@keyframes contract-bar-fill {
  to { transform: scaleX(1); }
}
/* The fill only animates once the contract scrolls into view, so the
   bars don't run silently behind the fold. */
.contract.reveal.is-visible .contract__power-fill,
.contract:not(.reveal) .contract__power-fill {
  animation: contract-bar-fill 1.6s cubic-bezier(.2, .7, .2, 1) 0.3s both;
}

/* ============================================================
   ENCANTAMENTOS VINCULADOS · bound enchantments
   ------------------------------------------------------------
   Two inscribed columns (Experiência · Entrega Profissional)
   sitting just above the wax-seal CTA. Each benefit reads like
   a rune carved into the contract; hovering one ignites a soft
   emerald glow, a slow magical pulse and a few floating sparks —
   reinforcing the sense of acquiring a complete arcane artifact.
   ============================================================ */
.contract__enchants {
  position: relative;
  margin-top: 0.35rem;
  padding: 0.7rem 0.7rem 0.2rem;
}
/* faint inscribed plaque framing the enchantments */
.contract__enchants::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(140, 90, 47, 0.22);
  border-radius: 5px;
  background:
    radial-gradient(ellipse at 50% 0%, rgba(120, 200, 150, 0.05), transparent 70%),
    linear-gradient(180deg, rgba(60, 30, 15, 0.04), transparent 40%);
  pointer-events: none;
}

.contract__enchants-title {
  position: relative;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.66rem;
  letter-spacing: 0.3em;
  color: var(--rarity-accent-deep, var(--gold-deep));
  text-transform: uppercase;
  margin: 0 0 0.2rem;
  text-align: center;
}
.contract__enchants-title::before,
.contract__enchants-title::after {
  content: "✦";
  font-size: 0.55rem;
  margin: 0 0.35rem;
  color: var(--rarity-accent, var(--gold));
  vertical-align: middle;
}
.contract__enchants-sub {
  position: relative;
  text-align: center;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.82rem;
  color: var(--ink-soft);
  line-height: 1.35;
  margin: 0 auto 0.75rem;
  max-width: 30ch;
}

.contract__enchant-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem 1.1rem;
}
.contract__enchant-cat {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.45rem;
  padding-bottom: 0.28rem;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.56rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--rarity-accent-deep, var(--gold-deep));
  border-bottom: 1px dashed rgba(140, 90, 47, 0.35);
}
.contract__enchant-cat-glyph {
  color: var(--rarity-accent, var(--gold));
  font-size: 0.5rem;
}

.contract__enchant-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 0.34rem;
}
.contract__enchant {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.12rem 0.25rem;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.86rem;
  color: var(--ink);
  letter-spacing: 0.02em;
  line-height: 1.25;
  border-radius: 5px;
  transition: transform 0.35s ease, background 0.4s ease;
}
/* soft emerald glow halo behind the hovered benefit */
.contract__enchant::before {
  content: "";
  position: absolute;
  inset: -2px -5px;
  border-radius: 6px;
  background: radial-gradient(ellipse at left center,
    rgba(120, 205, 150, 0.22) 0%, rgba(120, 205, 150, 0.06) 45%, transparent 72%);
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}
.contract__enchant:hover {
  transform: translateX(3px);
  background: rgba(120, 205, 150, 0.06);
}
.contract__enchant:hover::before { opacity: 1; }
.contract__enchant:hover .contract__enchant-name {
  color: #2f7350;
  text-shadow: 0 0 7px rgba(120, 205, 150, 0.45);
}

/* Rune sigil — carved gold by default, ignites emerald on hover */
.contract__enchant-rune {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 17px;
  height: 17px;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.82rem;
  line-height: 1;
  color: var(--rarity-accent-deep, var(--gold-deep));
  text-shadow: 0 0 3px var(--rarity-glow, rgba(229, 190, 174, 0.4));
  transition: color 0.35s ease, text-shadow 0.35s ease;
}
.contract__enchant:hover .contract__enchant-rune {
  color: #b9f4cf;
  text-shadow:
    0 0 7px rgba(120, 205, 150, 0.95),
    0 0 14px rgba(120, 205, 150, 0.6);
  animation: enchant-rune-pulse 1.5s ease-in-out infinite;
}
/* floating sparks that surface around the selected enchantment */
.contract__enchant-rune::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  box-shadow:
    -9px -3px 0 0 rgba(185, 244, 207, 0.95),
    9px -6px 0 -0.5px rgba(120, 205, 150, 0.85),
    6px 7px 0 -0.5px rgba(210, 255, 222, 0.8),
    -8px 6px 0 -0.5px rgba(120, 205, 150, 0.7);
}
.contract__enchant:hover .contract__enchant-rune::after {
  animation: enchant-spark 1.5s ease-in-out infinite;
}

@keyframes enchant-rune-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.2); }
}
@keyframes enchant-spark {
  0%   { opacity: 0; transform: translateY(3px) scale(0.6); }
  45%  { opacity: 1; transform: translateY(-2px) scale(1); }
  100% { opacity: 0; transform: translateY(-7px) scale(1.25); }
}

/* CTA — wax-seal style call to the Portal */
.contract__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  padding: 0.6rem 1rem;
  border: 1px solid var(--rarity-accent-deep, var(--gold-deep));
  border-radius: 4px;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.6), rgba(140, 90, 47, 0.18));
  font-family: "JetBrains Mono", monospace;
  font-size: 0.7rem;
  letter-spacing: 0.26em;
  color: var(--ink);
  text-decoration: none;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    transform 0.35s ease,
    box-shadow 0.35s ease,
    color 0.35s ease,
    background 0.35s ease;
  box-shadow:
    0 0 0 1px var(--parchment-1),
    inset 0 0 6px rgba(255, 235, 190, 0.5);
}
.contract__cta:hover,
.contract__cta:focus-visible {
  color: var(--ember);
  transform: translateY(-1px) scale(1.01);
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.78), rgba(229, 190, 174, 0.3));
  box-shadow:
    0 0 0 1px var(--parchment-1),
    0 0 0 1.5px var(--rarity-accent, var(--gold)),
    0 5px 15px var(--rarity-glow, rgba(229, 190, 174, 0.4));
  outline: none;
}

/* Page numbers (mirrors codex) */
.contract__page-num {
  text-align: center;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.58rem;
  letter-spacing: 0.38em;
  color: var(--rarity-accent-deep, var(--gold-deep));
  margin: 1.05rem 0 0;
  opacity: 0.7;
}

/* ============================================================
   ARTEFATO EXEMPLAR · relic footnote
   ------------------------------------------------------------
   Tiny medieval frame inserted under "Prazo Estimado" on the
   LEFT page of each contract. Acts as a marginal codex
   annotation — never as a marketing card. Strict palette of
   parchment + gold + ink, hairline gold borders, miniature
   thumbnail painted in illuminated-manuscript style.
   ============================================================ */
.contract__relic {
  position: relative;
  margin: 1rem 0 0.15rem;
  padding: 0.7rem 0.75rem 0.65rem 0.7rem;
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: 0.7rem;
  align-items: stretch;
  background:
    linear-gradient(180deg,
      rgba(255, 235, 190, 0.18) 0%,
      rgba(140, 90, 47, 0.07) 100%);
  border: 1px solid rgba(140, 90, 47, 0.30);
  border-radius: 3px;
  box-shadow:
    inset 0 0 0 1px rgba(255, 235, 190, 0.18),
    inset 0 0 14px rgba(140, 90, 47, 0.08);
}
/* Inner hairline ornament — evokes a manuscript marginalia frame */
.contract__relic::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(194, 164, 107, 0.22);
  pointer-events: none;
  border-radius: 2px;
}
/* Tiny "Artefato Exemplar" eyebrow label — sits above the relic */
.contract__relic-label {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: -0.15rem 0 0.5rem;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.56rem;
  letter-spacing: 0.32em;
  color: var(--rarity-accent-deep, var(--gold-deep));
  text-transform: uppercase;
  opacity: 0.85;
}
.contract__relic-label::before,
.contract__relic-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background:
    linear-gradient(90deg,
      transparent,
      rgba(140, 90, 47, 0.42) 50%,
      transparent);
}
.contract__relic-label span { flex: none; }

/* Miniature thumbnail — illuminated parchment scene
   The <figure> is now a non-clipping container so the mystical glow
   halo can bleed outside the thumb. The actual frame + crop happens
   on .contract__relic-thumb (an <a> wrapping the <img>). */
.contract__relic-figure {
  position: relative;
  margin: 0;
  width: 100%;
  aspect-ratio: 3 / 2;
  /* overflow stays visible so the halo can escape the frame */
}
/* Clickable thumbnail link — opens the project in a new tab.
   Wraps the <img> so the entire miniature is interactive while the
   "Examinar Artefato →" text link remains the primary tab-stop. */
.contract__relic-thumb {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 2px;
  overflow: hidden;
  cursor: pointer;
  outline: none;
  background:
    linear-gradient(180deg, rgba(255, 235, 190, 0.18), rgba(60, 30, 15, 0.18));
  box-shadow:
    inset 0 0 0 1px rgba(60, 30, 15, 0.35),
    inset 0 0 8px rgba(60, 30, 15, 0.22),
    0 0 0 0 transparent;
  transition:
    box-shadow 0.7s cubic-bezier(.18, .7, .16, 1.05),
    transform 0.5s ease;
}
.contract__relic-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: sepia(0.22) saturate(0.92) brightness(0.95);
  transition: filter 0.6s ease, transform 0.7s cubic-bezier(.2, .7, .2, 1);
}
/* Subtle vignette over the thumbnail — keeps it married to the parchment */
.contract__relic-thumb::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgba(60, 25, 10, 0.34) 100%),
    radial-gradient(ellipse at top left, rgba(80, 30, 10, 0.18), transparent 45%);
  mix-blend-mode: multiply;
  transition: opacity 0.6s ease;
}

/* MYSTICAL GLOW HALO
   Soft radial aura that swells outside the thumbnail when the cursor
   approaches the relic. Uses --rarity-glow so each contract gets its
   own arcane hue (gold for common, lavender for legendary, etc).
   The halo lives on the <figure> as ::before so it can bleed beyond
   the cropped thumbnail edge without clipping. */
.contract__relic-figure::before {
  content: "";
  position: absolute;
  inset: -18px;
  border-radius: 12px;
  background:
    radial-gradient(ellipse at center,
      var(--rarity-glow, rgba(229, 190, 174, 0.55)) 0%,
      rgba(255, 235, 190, 0.22) 30%,
      transparent 68%);
  filter: blur(14px);
  opacity: 0;
  transform: scale(0.85);
  transition:
    opacity 0.65s cubic-bezier(.2, .7, .2, 1),
    transform 0.75s cubic-bezier(.2, .7, .2, 1);
  pointer-events: none;
  z-index: 0;
}
.contract__relic-figure > * { position: relative; z-index: 1; }

/* Hover / focus on either the thumb OR the text link grows the halo */
.contract__relic:hover .contract__relic-figure::before,
.contract__relic:focus-within .contract__relic-figure::before {
  opacity: 1;
  transform: scale(1.08);
  animation: contract-relic-breathe 3.2s ease-in-out 0.35s infinite;
}
.contract__relic:hover .contract__relic-thumb,
.contract__relic:focus-within .contract__relic-thumb {
  box-shadow:
    inset 0 0 0 1px rgba(60, 30, 15, 0.25),
    inset 0 0 6px rgba(60, 30, 15, 0.18),
    0 0 22px var(--rarity-glow, rgba(229, 190, 174, 0.45));
}
.contract__relic:hover .contract__relic-thumb img,
.contract__relic:focus-within .contract__relic-thumb img {
  filter: sepia(0.06) saturate(1.08) brightness(1.04);
  transform: scale(1.03);
}
.contract__relic:hover .contract__relic-thumb::after,
.contract__relic:focus-within .contract__relic-thumb::after {
  opacity: 0.72;
}

@keyframes contract-relic-breathe {
  0%, 100% { opacity: 0.85; transform: scale(1.05); }
  50%      { opacity: 1.00; transform: scale(1.14); }
}

/* Right column: project name + description + examine link */
.contract__relic-body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.4rem;
  min-width: 0;
}
.contract__relic-name {
  margin: 0;
  font-family: "Libre Caslon Text", "Cormorant Garamond", Georgia, serif;
  font-size: 0.92rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.15;
  color: var(--ink);
  text-shadow: 0 1px 0 rgba(255, 235, 190, 0.5);
}
.contract__relic-desc {
  margin: 0;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.78rem;
  line-height: 1.32;
  color: var(--ink-soft);
  /* Clamp to 2 lines so the relic never grows the contract */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Examine link — discreet quill-arrow underline, NOT a button.
   Carries its own mystical glow that swells when the cursor
   approaches the relic (hover on link OR on thumb). */
.contract__relic-link {
  position: relative;
  align-self: flex-start;
  display: inline-flex;
  align-items: baseline;
  gap: 0.32rem;
  margin-top: 0.05rem;
  padding: 0;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rarity-accent-deep, var(--gold-deep));
  text-decoration: none;
  border-bottom: 1px solid rgba(140, 90, 47, 0.4);
  text-shadow: 0 0 0 transparent;
  transition:
    color 0.45s ease,
    border-color 0.45s ease,
    text-shadow 0.6s cubic-bezier(.2, .7, .2, 1);
}
.contract__relic-link::after {
  content: "→";
  font-family: "Libre Caslon Text", Georgia, serif;
  font-size: 0.78rem;
  letter-spacing: 0;
  transition: transform 0.4s cubic-bezier(.2, .7, .2, 1);
}
/* Soft halo that grows beneath the text — same arcane hue as the thumb */
.contract__relic-link::before {
  content: "";
  position: absolute;
  inset: -6px -10px -8px -10px;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at center,
      var(--rarity-glow, rgba(229, 190, 174, 0.55)) 0%,
      transparent 70%);
  filter: blur(8px);
  opacity: 0;
  transform: scale(0.85);
  transition:
    opacity 0.55s cubic-bezier(.2, .7, .2, 1),
    transform 0.7s cubic-bezier(.2, .7, .2, 1);
  pointer-events: none;
  z-index: -1;
}
.contract__relic:hover .contract__relic-link,
.contract__relic:focus-within .contract__relic-link {
  color: var(--ember);
  border-bottom-color: var(--rarity-accent, var(--gold));
  text-shadow: 0 0 10px var(--rarity-glow, rgba(229, 190, 174, 0.6));
}
.contract__relic:hover .contract__relic-link::before,
.contract__relic:focus-within .contract__relic-link::before {
  opacity: 0.9;
  transform: scale(1.08);
  animation: contract-relic-breathe 3.2s ease-in-out 0.4s infinite;
}
.contract__relic:hover .contract__relic-link::after,
.contract__relic:focus-within .contract__relic-link::after {
  transform: translateX(3px);
}
/* Keep outline visible only for keyboard users */
.contract__relic-link:focus-visible { outline: none; }
.contract__relic-thumb:focus-visible {
  outline: 1px solid var(--rarity-accent, var(--gold));
  outline-offset: 3px;
}

/* Reduced-motion respect */
@media (prefers-reduced-motion: reduce) {
  .contract__relic-thumb,
  .contract__relic-thumb img,
  .contract__relic-link,
  .contract__relic-link::after,
  .contract__relic-link::before,
  .contract__relic-figure::before,
  .contract__enchant,
  .contract__enchant-rune,
  .contract__enchant-rune::after {
    transition: none;
    animation: none !important;
  }
}

/* Narrow contract bodies (mobile, single-column spread) */
@media (max-width: 520px) {
  .contract__relic {
    grid-template-columns: 70px 1fr;
    gap: 0.6rem;
    padding: 0.6rem 0.65rem 0.55rem 0.6rem;
  }
  .contract__relic-name { font-size: 0.86rem; }
  .contract__relic-desc { font-size: 0.74rem; }
  .contract__relic-link { font-size: 0.56rem; letter-spacing: 0.2em; }
}
@media (max-width: 360px) {
  .contract__relic {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }
  .contract__relic-figure { aspect-ratio: 16 / 9; }
}

/* DISCLAIMER · referential delivery windows note
   Sits between the contracts grid and the wax-seal footer. Uses
   the parchment ink tone with reduced opacity so it reads as a
   marginal annotation, not a primary message. Italics + slightly
   wider letter-spacing echo the codex typography elsewhere. */
.contracts__disclaimer {
  max-width: 760px;
  margin: 2.2rem auto 0;
  padding: 0 1.25rem;
  text-align: center;
  font-family: "Cormorant Garamond", "EB Garamond", serif;
  font-style: italic;
  font-size: 0.78rem;
  line-height: 1.55;
  letter-spacing: 0.04em;
  color: var(--gold-deep, #8C5A2F);
  opacity: 0.7;
}
html[data-theme="light"] .contracts__disclaimer {
  color: var(--burgundy, #5C2B1F);
  opacity: 0.78;
}

/* SEAL footer */
.contracts__seal {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.7rem;
  margin: 1.4rem auto 0;
  max-width: 680px;
}
.contracts__seal-line {
  height: 1px;
  background:
    linear-gradient(90deg,
      transparent,
      var(--gold-deep) 30%,
      var(--gold-bright) 50%,
      var(--gold-deep) 70%,
      transparent);
  opacity: 0.55;
}
.contracts__seal-mark {
  display: grid;
  place-items: center;
  color: var(--gold);
  filter: drop-shadow(0 0 8px rgba(229, 190, 174, 0.45));
}
.contracts__seal-text {
  grid-column: 1 / -1;
  text-align: center;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.7rem;
  letter-spacing: 0.36em;
  color: var(--gold);
  margin: 0.3rem 0 0;
  text-transform: uppercase;
}

/* ============================================================
   RARITY ACCENTS · per-card colour scopes
   Each contract inherits a slightly different gem palette
   while keeping the parchment/leather book identical.
============================================================ */
/* Rarity progression (June 2026) — glow intensity now climbs with the
   tier so the codex reads as "increasingly powerful artifacts":
   COMUM soft bronze → RARO moderate blue → ÉPICO pulsing violet →
   LENDÁRIO golden particles → MÍTICO gold+violet intense aura.       */
.contract[data-rarity="common"] {
  --rarity-accent:        #C2A46B;   /* base gold */
  --rarity-accent-bright: #E5BEAE;
  --rarity-accent-deep:   #8C5A2F;
  --rarity-glow:          rgba(229, 190, 174, 0.32);   /* soft */
}
.contract[data-rarity="uncommon"] {
  --rarity-accent:        #5BA371;   /* moss-green verdigris */
  --rarity-accent-bright: #A6D9A6;
  --rarity-accent-deep:   #2F6B45;
  --rarity-glow:          rgba(135, 210, 150, 0.42);
}
.contract[data-rarity="rare"] {
  --rarity-accent:        #4F88C0;   /* arcane sapphire */
  --rarity-accent-bright: #A6CFEA;
  --rarity-accent-deep:   #1F3A5E;
  --rarity-glow:          rgba(120, 175, 230, 0.54);   /* moderate */
}
.contract[data-rarity="epic"] {
  --rarity-accent:        #9B5CD9;   /* royal violet */
  --rarity-accent-bright: #D4A8F2;
  --rarity-accent-deep:   #4A1A75;
  --rarity-glow:          rgba(190, 130, 240, 0.7);    /* pulsing energy */
}
.contract[data-rarity="legendary"] {
  --rarity-accent:        #D6A06B;   /* warm legendary gold */
  --rarity-accent-bright: #FFE7A0;
  --rarity-accent-deep:   #8C5A2F;
  --rarity-glow:          rgba(255, 215, 130, 0.8);    /* golden particles */
}
/* Mythic — apex tier: gold + violet blend, the most intense aura. */
.contract[data-rarity="mythic"] {
  --rarity-accent:        #C9A66B;   /* regal gold base */
  --rarity-accent-bright: #ECCAF4;   /* violet-touched light */
  --rarity-accent-deep:   #5A2E78;   /* deep violet */
  --rarity-glow:          rgba(206, 156, 240, 0.92);   /* gold+violet aura */
}
/* Legendary book: extra ember radiance for the final chapter.
   Phantom-border fix (June 2026): removed the hard 0/4px/5px
   solid rings — they reintroduced the rectangular frame the
   user reported. Now: hairline gold inset + deep drop shadow
   + wide ember halo, no perceptible rectangle. */
.contract[data-rarity="legendary"] .contract__book {
  box-shadow:
    inset 0 0 0 1px rgba(255, 215, 130, 0.22),
    0 22px 56px rgba(0, 0, 0, 0.5),
    0 0 110px rgba(255, 215, 130, 0.26);
}

/* Epic book — a quiet, pulsing violet energy beneath the parchment. */
.contract[data-rarity="epic"] .contract__book {
  box-shadow:
    inset 0 0 0 1px rgba(190, 130, 240, 0.2),
    0 20px 50px rgba(0, 0, 0, 0.48),
    0 0 96px rgba(170, 110, 230, 0.22);
}
/* Mythic book — apex aura: gold+violet glow, the strongest in the codex. */
.contract[data-rarity="mythic"] .contract__book {
  box-shadow:
    inset 0 0 0 1px rgba(236, 202, 244, 0.26),
    0 24px 62px rgba(0, 0, 0, 0.52),
    0 0 130px rgba(206, 156, 240, 0.3),
    0 0 60px rgba(255, 215, 130, 0.18);
}
/* Mythic apex aura — an extra slow-breathing violet+gold halo layer
   that no other rarity has, so the top tier feels unmistakably alive. */
.contract[data-rarity="mythic"] .contract__book::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  pointer-events: none;
  z-index: -1;
  background:
    radial-gradient(60% 120% at 50% 0%, rgba(206, 156, 240, 0.16), transparent 70%),
    radial-gradient(60% 120% at 50% 100%, rgba(255, 215, 130, 0.12), transparent 70%);
  opacity: 0.85;
  animation: contract-mythic-aura 6.5s ease-in-out infinite;
}
@keyframes contract-mythic-aura {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 0.95; }
}

/* ============================================================
   ANIMATIONS · breathing parchment, ink-reveal, shadow drift
============================================================ */
@keyframes contract-breath {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.004); }
}
/* Phantom-border fix (June 2026): the previous keyframe drifted
   THREE solid "ring" shadows on every contract book continuously
   — that loop is what kept reasserting the rectangular frame
   after the static .contract__book rule was already softened.
   The drift now only breathes the depth shadow and the rarity
   halo, leaving the parchment perceptually frame-less. */
@keyframes contract-shadow-drift {
  0%, 100% {
    box-shadow:
      inset 0 0 0 1px rgba(194, 164, 107, 0.18),
      0 18px 44px rgba(0, 0, 0, 0.45),
      0 0 80px var(--rarity-glow, rgba(229, 190, 174, 0.10));
  }
  50% {
    box-shadow:
      inset 0 0 0 1px rgba(220, 190, 140, 0.26),
      0 22px 54px rgba(0, 0, 0, 0.5),
      0 0 100px var(--rarity-glow, rgba(229, 190, 174, 0.18));
  }
}
@media (prefers-reduced-motion: no-preference) {
  .contract__book {
    animation:
      contract-breath 8s ease-in-out infinite,
      contract-shadow-drift 12s ease-in-out infinite;
    animation-delay: var(--breath-delay, 0s);
  }
  .contract:nth-child(1) .contract__book { --breath-delay: 0s; }
  .contract:nth-child(2) .contract__book { --breath-delay: -1.2s; }
  .contract:nth-child(3) .contract__book { --breath-delay: -2.4s; }
  .contract:nth-child(4) .contract__book { --breath-delay: -3.6s; }
  .contract:nth-child(5) .contract__book { --breath-delay: -4.8s; }
  .contract:nth-child(6) .contract__book { --breath-delay: -6s; }
  .contract:nth-child(7) .contract__book { --breath-delay: -7.2s; }
}

/* INK REVEAL on hover/focus — wash of arcane ink fades over the
   parchment, divider gradients glow brighter, gem brightens. */
.contract__book:hover,
.contract__book:focus-visible {
  transform: translateY(-3px);
}
.contract__book:hover .contract__spread::before,
.contract__book:focus-visible .contract__spread::before {
  opacity: 0.9;
}
.contract__book:hover .contract__gem,
.contract__book:focus-visible .contract__gem {
  transform: scale(1.18);
  box-shadow:
    inset 0 0 4px rgba(60, 30, 15, 0.4),
    0 0 16px var(--rarity-glow, rgba(229, 190, 174, 0.65));
}
.contract__book:hover .contract__divider-mark,
.contract__book:focus-visible .contract__divider-mark {
  text-shadow: 0 0 12px var(--rarity-glow, rgba(229, 190, 174, 0.85));
}

/* Reveal sequence when the book scrolls into view. We piggyback on
   the global `.reveal / .is-visible` system used elsewhere on the
   page so the section header and each contract fade in together as
   the user scrolls. The breathing/shadow drift continues afterward. */

/* Reduced motion: kill everything cinematic, keep colour & layout */
@media (prefers-reduced-motion: reduce) {
  .contract__book { animation: none !important; }
  .contract__book:hover,
  .contract__book:focus-visible { transform: none; }
  .contract__power-fill { animation: none; transform: scaleX(1); }
}

/* ============================================================
   RESPONSIVE · spread collapses below ~860px
============================================================ */
@media (max-width: 860px) {
  .contracts { padding: 3rem 1rem 3.4rem; }
  .contract__book { padding: 1.6rem 1.1rem 1.3rem; }
  .contract__corner { width: 30px; height: 30px; }
  .contract__corner--tl { top: 7px; left: 7px; }
  .contract__corner--tr { top: 7px; right: 7px; }
  .contract__corner--bl { bottom: 7px; left: 7px; }
  .contract__corner--br { bottom: 7px; right: 7px; }
  .contract__corner::before { width: 22px; }
  .contract__corner::after  { height: 22px; }
  .contract__spread {
    grid-template-columns: 1fr;
    gap: 0.7rem;
  }
  .contract__spine {
    height: 2px;
    width: 80%;
    margin: 0.5rem auto;
    background:
      linear-gradient(90deg,
        transparent 0,
        rgba(60, 30, 15, 0.55) 25%,
        rgba(60, 30, 15, 0.7) 50%,
        rgba(60, 30, 15, 0.55) 75%,
        transparent 100%);
    box-shadow:
      0 -2px 6px rgba(60, 30, 15, 0.3),
      0  2px 6px rgba(60, 30, 15, 0.3);
  }
  .contract__enchant-grid { grid-template-columns: 1fr; gap: 0.6rem; }
  .contract__power-bar { width: 6.5rem; }
}
@media (max-width: 520px) {
  .contracts__title { font-size: 1.5rem; }
  .contract__name { font-size: 1.2rem; }
  .contract__price strong { font-size: 0.88rem; }
  .contract__enchant { font-size: 0.82rem; }
}

/* ============================================================
   THEME · SOLIS (alvorada arcana / light mode)
   Vesper (dark) is default. Solis transforms the page into a
   cream-and-sepia parchment atmosphere while keeping arcane
   identity. Strategy for canvases:
     · Skill tree BG canvas (paints solid dark navy):
       use `mix-blend-mode: screen` — the dark fill blends to
       parchment, while stars/nebulas/runes shine through as
       luminous accents on cream paper.
     · Crystals canvas already renders with transparent alpha,
       so it composites directly over the parchment (additive
       blending in Three.js stays luminous).
============================================================ */
html { transition: background 0.6s ease, color 0.6s ease; }
body { transition: background 0.6s ease, color 0.6s ease; }
.bg-gradient,
.bg-godrays,
.bg-grain,
.tree-fullscreen,
#tree-canvas-bg,
#tree-canvas-fg,
.memories,
.tree-vault,
.nav,
.merlin,
.portal,
.hero,
.footer {
  transition: filter 0.6s ease, background 0.6s ease, color 0.6s ease, opacity 0.6s ease;
}

html[data-theme="light"] {
  /* SOLIS · "Codex Arcano" palette — ILLUMINATED MANUSCRIPT EDITION v2
     ============================================================
     Inspiração: manuscrito iluminado medieval / biblioteca antiga
     à luz do meio-dia / cofre de relíquias de Rivendell. Pergaminho
     envelhecido, ouro velho, bronze burilado, tinta ferro-gálica
     marrom escuro. Zero brancos puros. Zero cinzas neutros. Zero
     "SaaS aesthetic".

     Refinamentos v2 (vs v1):
       · Pergaminho mais profundo, mais aged (saiu da zona "cream"
         clara que ainda lia como quase-branco).
       · Bordas glass mais opacas e saturadas — cards parecem folhas
         de vellum empilhadas, não vidro fosco.
       · Variáveis novas: --vellum, --sepia-edge, --foxing, --ink-bleed
         para vinhetas de envelhecimento.

     Spec (paleta principal):
       Pergaminho iluminado  #ECD8A6   página sob luz natural
       Pergaminho secundário #DCC68C   cards / painéis
       Pergaminho profundo   #C8AC68   hover / divisões / margens
       Vellum brilho         #F2DEAA   pontos iluminados do papel
       Borda foxed           #B89858   limite envelhecido do papel
       Tinta ferro-gálica    #2A1D0E   texto principal (AAA)
       Tinta secundária      #4F3C25
       Ink bleed             rgba(42, 29, 14, 0.85)  sombra natural de tinta
       Ouro velho            #B07A2A   hover #C68C3A
       Ouro iluminura        #D8B86A   ouro folheado de capitulares
       Bronze burilado       #8B5A2B   bordas, molduras
       Sepia edge            #6B4A22   sombras de envelhecimento
       Verde-musgo arcano    #2F6F58   pactos / vegetação
       Lápis-tinta (azul)    #2E4A85   substitui o azul moderno
       Vinho-veludo (roxo)   #6E2347   substitui o roxo SaaS
       Selo-de-cera          #7A1614   capitulares + selos
       Núcleo dourado        #D8B86A   glow #F7CE7C (mais quente)

     Bordas (NUNCA cinza, sempre bronze burilado):
       Linha fina            rgba(139,  90,  43, 0.55)
       Linha média           rgba(139,  90,  43, 0.78)
       Linha forte           rgba(139,  90,  43, 0.95)

     Glass cards (sempre vellum envelhecido, NUNCA branco / NUNCA creme):
       fundo padrão          rgba(232, 210, 158, 0.88)
       fundo opaco           rgba(232, 210, 158, 0.96)
  */
  --surface:                 #E4CD98;     /* papiro envelhecido (era #ECD8A6) */
  --surface-dim:             #BEA25E;
  --surface-bright:          #ECD49E;     /* vellum iluminado, jamais cream */
  --surface-container:       #D3BC82;
  --surface-container-high:  #BEA25E;
  --surface-container-highest: #AC8E50;

  --on-surface:          #1F1408;         /* tinta ferro-gálica reforçada (vs E4CD98 ≈ 12.8:1 AAA) */
  --on-surface-variant:  #3A2A18;         /* deepenado de #4F3C25 para garantir contraste em textos secundários */
  --on-surface-muted:    rgba(31, 20, 8, 0.82);  /* opacidade de 0.62 → 0.82, com base na tinta mais escura */

  --primary:           #9F6A1F;           /* ouro velho deepenado para contrastar com papiro envelhecido */
  --primary-hover:     #B97E2C;
  --on-primary:        #ECD49E;
  --primary-container: #D3BC82;

  --gold:              #9F6A1F;
  --gold-hover:        #B97E2C;
  --gold-dim:          rgba(159, 106, 31, 0.55);

  /* Bronze burilado — borduras, molduras, divisórias.
     SEMPRE preferir estas variáveis a qualquer rgba cinza. */
  --bronze:            #8B5A2B;
  --bronze-soft:       rgba(139, 90, 43, 0.55);
  --bronze-mid:        rgba(139, 90, 43, 0.78);
  --bronze-strong:     rgba(139, 90, 43, 0.95);

  /* Vellum / envelhecimento — usadas nas vinhetas do backdrop */
  --vellum:            #ECD49E;
  --sepia-edge:        #5A3E1C;
  --foxing:            rgba(110, 60, 22, 0.22);
  --ink-bleed:         rgba(31, 20, 8, 0.88);

  --green:             #2F6F58;
  --green-hover:       #4A8C76;

  --blue:              #2E4A85;            /* lápis-tinta (sem azul SaaS) */
  --blue-glow:         #5B7CB6;

  --purple:            #6E2347;            /* vinho-veludo (sem roxo neon) */
  --purple-glow:       #9A4D72;

  --rust:              #8E5828;
  --burgundy:          #5E1010;            /* selo-de-cera deepenado para AAA contraste em capitulares */
  --ink-deep:          #1F1408;
  --tertiary:          #245746;
  --secondary:         #3A2A18;             /* matches --on-surface-variant */
  --secondary-container:#D3BC82;
  --core:              #C9A658;
  --core-glow:         #E6BC68;

  /* Glass cards: SEMPRE pergaminho envelhecido, NUNCA branco translúcido,
     NUNCA creme leitoso. Estas variáveis substituem todos os
     rgba(255,255,255,X) anteriores que davam o aspecto de SaaS / dashboard. */
  --glass-bg:          rgba(218, 196, 142, 0.92);   /* papiro envelhecido, mais opaco */
  --glass-bg-opaque:   rgba(218, 196, 142, 0.98);
  --glass-border:      rgba(139, 90, 43, 0.65);
  --glass-blur:        16px;
}

/* ----------------------------------------------------------------
   ILLUMINATED PARCHMENT · body backdrop (v2)
   ----------------------------------------------------------------
   Composição (camadas, de cima pra baixo):
     1. Laid lines — listras horizontais finíssimas em rgba bronze,
        imitando as marcas de forma do papel artesanal medieval
        (uma página de papel laid, não papel moderno calandrado).
     2. Sunbeam diagonal — luz natural batendo do canto superior
        esquerdo, como uma janela de biblioteca antiga ao meio-dia.
     3. Halo dourado superior — luz quente concentrada no alto,
        como vela ou lanterna iluminando o tampo da página.
     4. Foxing nos cantos — manchas sépia escuras nas 4 quinas,
        simulando o escurecimento natural das bordas de papel
        envelhecido. Reforça que NÃO é uma tela de SaaS.
     5. Aura bronze à esquerda + aura vinho à direita — cor
        institucional do códex.
     6. Sombra de musgo na base — chão da biblioteca.
     7. PERGAMINHO BASE — wash vertical em tons aged, do vellum
        iluminado #ECD8A6 ao pergaminho profundo #BFA468. O ponto
        mais "claro" da página continua sendo bege profundo, jamais
        creme leitoso, jamais branco. Estamos sobre couro/papel,
        não sobre tela de Slack.
   ---------------------------------------------------------------- */
html[data-theme="light"] body {
  background:
    /* (1) Laid lines — fibras horizontais finíssimas do molde */
    repeating-linear-gradient(0deg,
      rgba(120, 80, 36, 0.045) 0px,
      rgba(120, 80, 36, 0.045) 1px,
      transparent 1px,
      transparent 7px),
    /* (2) Sunbeam diagonal — luz natural da janela */
    linear-gradient(135deg,
      rgba(255, 220, 140, 0.38) 0%,
      rgba(255, 220, 140, 0.14) 24%,
      transparent 46%),
    /* (3) Halo dourado superior — vela / lanterna */
    radial-gradient(ellipse 80% 42% at 50% -6%,
      rgba(250, 218, 150, 0.55), transparent 65%),
    /* (4a) Foxing — canto superior direito */
    radial-gradient(ellipse 32% 28% at 100% 0%,
      rgba(95, 55, 18, 0.30), transparent 70%),
    /* (4b) Foxing — canto inferior esquerdo */
    radial-gradient(ellipse 30% 26% at 0% 100%,
      rgba(95, 55, 18, 0.28), transparent 70%),
    /* (4c) Foxing — canto superior esquerdo (mais suave) */
    radial-gradient(ellipse 24% 22% at 0% 0%,
      rgba(110, 70, 25, 0.20), transparent 70%),
    /* (4d) Foxing — canto inferior direito (mais suave) */
    radial-gradient(ellipse 26% 24% at 100% 100%,
      rgba(110, 70, 25, 0.22), transparent 70%),
    /* (5a) Aura bronze à esquerda */
    radial-gradient(ellipse 38% 58% at 4% 42%,
      rgba(176, 122, 42, 0.18), transparent 65%),
    /* (5b) Aura vinho-veludo à direita */
    radial-gradient(ellipse 40% 55% at 96% 70%,
      rgba(110, 35, 71, 0.14), transparent 65%),
    /* (6) Sombra de musgo na base — chão da biblioteca */
    radial-gradient(ellipse 72% 28% at 50% 110%,
      rgba(58, 80, 46, 0.26), transparent 60%),
    /* (7) PERGAMINHO BASE — wash vertical em tons aged (escurecido v2.1).
       Os 4 stops foram puxados ~5-7% para cima na escala sépia: o topo
       agora começa em papiro envelhecido (#DCC58E em vez de #ECD8A6) e
       a base atinge bronze terroso profundo (#A88848). Resultado: papel
       parece centenário, e texto secundário/ledes ganham contraste. */
    linear-gradient(180deg,
      #DCC58E 0%,
      #CFB67A 38%,
      #BFA266 72%,
      #A88848 100%);
  color: var(--on-surface);
}

/* Foxing — pequenas manchas dispersas (stains de tempo).
   Camada pseudo dedicada acima do .bg-vault (z-index 0) e abaixo
   do conteúdo (z-index 10). Multiplica sobre o papel para escurecer
   pontos específicos como o envelhecimento natural do pergaminho. */
html[data-theme="light"] body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background:
    radial-gradient(circle 4px at 12% 18%, rgba(95, 55, 18, 0.28), transparent 70%),
    radial-gradient(circle 6px at 78% 24%, rgba(95, 55, 18, 0.25), transparent 70%),
    radial-gradient(circle 5px at 42% 62%, rgba(110, 70, 25, 0.22), transparent 70%),
    radial-gradient(circle 7px at 88% 78%, rgba(95, 55, 18, 0.24), transparent 70%),
    radial-gradient(circle 4px at 24% 84%, rgba(110, 70, 25, 0.24), transparent 70%),
    radial-gradient(circle 5px at 56% 36%, rgba(95, 55, 18, 0.20), transparent 70%),
    radial-gradient(circle 3px at 8% 56%, rgba(95, 55, 18, 0.26), transparent 70%),
    radial-gradient(circle 6px at 64% 92%, rgba(110, 70, 25, 0.22), transparent 70%);
  opacity: 0.85;
  mix-blend-mode: multiply;
}

/* Vinheta de borda — escurecimento bronze nas quatro margens,
   simulando o anel sépia natural de uma página antiga colada
   numa pasta de couro. */
html[data-theme="light"] .bg-vault::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 120% 120% at 50% 50%,
      transparent 55%,
      rgba(95, 55, 18, 0.22) 88%,
      rgba(70, 38, 12, 0.32) 100%);
  mix-blend-mode: multiply;
}

/* Strengthen the noise plate over the parchment so the paper has
   visible fibres — mais pronunciado que v1 para sair da zona "tela". */
html[data-theme="light"] .bg-grain {
  opacity: 0.46;
  mix-blend-mode: multiply;
  filter: contrast(1.7) sepia(0.55);
}

/* ----------------------------------------------------------------
   INK BLEED & WEIGHT · Light Mode Readability
   ----------------------------------------------------------------
   Estratégia: NÃO trocamos as famílias de fonte. Em vez disso:
     1. Aumentamos sutilmente o font-weight do corpo (460), o que
        a Hanken Grotesk (variable font) absorve sem mudar layout.
     2. Aplicamos um text-shadow hairline em var(--ink-bleed) que
        simula a tinta ferro-gálica sangrando no papel — engrossa
        visualmente cada letra sem alterar o glifo.
     3. Textos secundários (ledes, infos, captions) recebem
        font-weight 500 + ink-bleed mais marcado.
     4. Headings (h1-h6) ganham ink-bleed forte porque são os
        primeiros pontos de leitura — devem parecer "carimbados".
   ---------------------------------------------------------------- */
html[data-theme="light"] body {
  font-weight: 460;
  text-shadow: 0 0 0.3px var(--ink-bleed);
}

html[data-theme="light"] p,
html[data-theme="light"] li,
html[data-theme="light"] span,
html[data-theme="light"] a {
  font-weight: inherit;
}

/* Headings — capitulares com ink-bleed reforçado */
html[data-theme="light"] h1,
html[data-theme="light"] h2,
html[data-theme="light"] h3,
html[data-theme="light"] h4,
html[data-theme="light"] h5,
html[data-theme="light"] h6 {
  text-shadow:
    0 0 0.4px var(--ink-bleed),
    0 1px 0 rgba(247, 232, 192, 0.35);  /* leve halo de pergaminho atrás da letra */
}

/* Textos descritivos (ledes, infos, parágrafos centrais) — peso 500
   + ink-bleed. Estes são justamente os textos que estavam difíceis
   de ler em telas mais brilhantes. */
html[data-theme="light"] .hero__lede,
html[data-theme="light"] .tree-vault__lede,
html[data-theme="light"] .memories__lede,
html[data-theme="light"] .portal__lede,
html[data-theme="light"] .contracts__subtitle,
html[data-theme="light"] .crystal-caption__name,
html[data-theme="light"] .tree-hud__label,
html[data-theme="light"] .tree-hint,
html[data-theme="light"] .footer,
html[data-theme="light"] .footer__line {
  font-weight: 500;
  text-shadow: 0 0 0.4px var(--ink-bleed);
}

/* Texto muted (on-surface-muted) — já está em 0.82 de opacidade
   sobre tinta deepenada, mas garantir que não vire pseudo-fantasma.
   Quando vir um elemento usando `color: var(--on-surface-muted)`,
   reforçamos com weight 480 + ink-bleed leve. */
html[data-theme="light"] [class*="__muted"],
html[data-theme="light"] [class*="--muted"],
html[data-theme="light"] .nav__role,
html[data-theme="light"] .crystal-caption__rarity {
  font-weight: 480;
  text-shadow: 0 0 0.35px var(--ink-bleed);
}

/* Links e botões — ink-bleed também, mas peso natural do botão */
html[data-theme="light"] .nav a,
html[data-theme="light"] .btn--ghost,
html[data-theme="light"] .btn--primary,
html[data-theme="light"] .portal__link,
html[data-theme="light"] .tool,
html[data-theme="light"] .lang-menu li {
  text-shadow: 0 0 0.35px var(--ink-bleed);
}

/* Hero name fica como gradient text — text-shadow não afeta gradiente,
   então não há colisão. Mas as letras das outras seções com gradient
   também ficam estáveis. */

/* ----------------------------------------------------------------
   SKILL TREE WALLPAPER · INK ON PARCHMENT
   The dark BG canvas stays hidden. The FG canvas continues to
   render bright runes / auroras, but JS now uses theme-aware
   colors for connections + labels. We add a multiply blend
   safety-net so any remaining bright sprites become darker tints
   on the parchment instead of washing out.
   ---------------------------------------------------------------- */
html[data-theme="light"] .tree-wall { isolation: auto; }
html[data-theme="light"] #tree-canvas-bg {
  opacity: 0;
  pointer-events: none;
}
html[data-theme="light"] #tree-canvas-fg {
  mix-blend-mode: multiply;
  filter: saturate(1.45) contrast(1.18);
  opacity: 0.95;
}

/* Atmospheric layers — tuned for the Codex Arcano palette (v2)
   Camada de atmosfera sépia sobre o papel: brilho de vellum no
   alto, ouro velho à direita, musgo verde profundo no centro, e
   uma sombra de tinta nos cantos para reforçar o peso do códex. */
html[data-theme="light"] .bg-gradient {
  background:
    /* warm vellum highlight (luz da janela no alto-esquerdo) */
    radial-gradient(ellipse at 25% 10%, rgba(250, 220, 150, 0.50), transparent 58%),
    /* old-gold haze nas margens direitas */
    radial-gradient(ellipse at 78% 78%, rgba(176, 122, 42, 0.22), transparent 60%),
    /* moss-green depth no centro (livro aberto sobre a mesa) */
    radial-gradient(ellipse at 50% 55%, rgba(47, 111, 88, 0.14),  transparent 70%),
    /* ink shadow — vinheta de tinta sépia nos cantos inferiores */
    radial-gradient(ellipse 70% 40% at 50% 110%,
      rgba(70, 38, 12, 0.20), transparent 65%);
  opacity: 0.78;
}
html[data-theme="light"] .bg-godrays {
  opacity: 0.34;
  mix-blend-mode: soft-light;
  filter: hue-rotate(-18deg) saturate(1.35) brightness(0.95);  /* amber/golden god-rays mais quentes */
}
/* (.bg-grain is configured in the parchment block above) */

/* MEMORY CRYSTALS · transparent compositing on the wallpaper plane */
html[data-theme="light"] #crystal-canvas { filter: none; }

/* ----------------------------------------------------------------
   NAV — vellum strip, bronze divider, ink text
   ---------------------------------------------------------------- */
html[data-theme="light"] .nav {
  /* Background is supplied by the base `.nav` / `.nav.is-scrolled`
     rules (dark arcane glass in both themes — matching the previous
     JS-driven inline colour). This rule intentionally does not set
     `background` so the scrolled-state toggle stays consistent. */
  border-bottom: 1px solid var(--bronze-mid);
  backdrop-filter: blur(16px) saturate(1.15);
  -webkit-backdrop-filter: blur(16px) saturate(1.15);
  color: var(--on-surface);
  box-shadow: 0 1px 0 var(--bronze-soft), 0 8px 24px rgba(43, 29, 14, 0.12);
}
html[data-theme="light"] .nav__brand,
html[data-theme="light"] .nav__role { color: var(--on-surface); }
html[data-theme="light"] .nav a { color: var(--on-surface); }
html[data-theme="light"] .nav a:hover { color: var(--primary); }

/* TOOL buttons — small parchment chips with bronze edge */
html[data-theme="light"] .tool {
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
  background: var(--glass-bg);
}
html[data-theme="light"] .tool:hover,
html[data-theme="light"] .tool:focus-visible {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--glass-bg-opaque);
}
html[data-theme="light"] .tool[aria-pressed="true"] {
  color: var(--burgundy);
  border-color: var(--primary);
  background: rgba(176, 122, 42, 0.20);
}

html[data-theme="light"] .lang-menu {
  background: var(--glass-bg-opaque);
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
  backdrop-filter: blur(16px) saturate(1.15);
  -webkit-backdrop-filter: blur(16px) saturate(1.15);
  box-shadow:
    0 0 0 1px var(--bronze-soft),
    0 12px 36px rgba(43, 29, 14, 0.22);
}
html[data-theme="light"] .lang-menu li { color: var(--on-surface); }
html[data-theme="light"] .lang-menu li:hover,
html[data-theme="light"] .lang-menu li[aria-selected="true"] {
  background: rgba(176, 122, 42, 0.20);
  color: var(--burgundy);
}

/* ----------------------------------------------------------------
   HERO
   ---------------------------------------------------------------- */
html[data-theme="light"] .hero__eyebrow {
  color: var(--burgundy);                     /* capitular vermelho-vinho */
  letter-spacing: 0.32em;
  text-shadow: 0 1px 0 rgba(255, 245, 200, 0.7);
}
html[data-theme="light"] .hero__name {
  background: linear-gradient(180deg, var(--ink-deep) 25%, var(--primary) 95%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 1px 0 rgba(255, 245, 200, 0.45);
}
html[data-theme="light"] .hero__name-last {
  color: var(--burgundy);                     /* iluminura wine */
  background: none;
  -webkit-background-clip: initial;
  background-clip: initial;
}
html[data-theme="light"] .hero__tagline { color: var(--green); }
/* Light-theme forged-metal variant — translates the engraving to
   parchment. The hero lede sits above the craft constellation,
   which itself is warm and busy on the parchment, so the light-
   theme palette is deliberately darker and the embers are almost
   imperceptible: this keeps the inscription readable as iron-gall
   ink with a faint bronze sheen, rather than competing with the
   constellation behind it. Weight bumps to 600 for a chiselled
   feel that survives against the busy backdrop. */
html[data-theme="light"] .hero__lede {
  font-weight: 600;
  background:
    /* Distant forge — barely-there warm wash, no longer a "patch" */
    radial-gradient(ellipse 45% 160% at 30% 50%,
      rgba(166, 59, 30, 0.16) 0%,
      rgba(74, 36, 16, 0.08) 40%,
      transparent 72%),
    radial-gradient(ellipse 40% 150% at 70% 50%,
      rgba(74, 36, 16, 0.14) 0%,
      transparent 70%),
    /* Mostly-black metal with a narrow bronze midtone */
    linear-gradient(96deg,
      #0E0604 0%,    /* deep iron-gall  */
      #2A140A 25%,   /* dark sienna     */
      #4F2A10 50%,   /* aged bronze     */
      #2A140A 75%,
      #0E0604 100%);
  background-size:
    260% 240%,
    240% 220%,
    220% 100%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* Strong paper-highlight underneath sells the engraving — the
     letters look pressed INTO the parchment, separating them from
     the constellation lines drawn on top of the wash behind. */
  text-shadow:
    0 0 8px  rgba(217, 101, 26, 0.08),
    0 1px 0  rgba(255, 248, 215, 0.75),
    0 1px 2px rgba(255, 248, 215, 0.45);
  filter: drop-shadow(0 0 2px rgba(14, 6, 4, 0.30));
}

/* Hover on parchment — the ember warms, the ink stays the same. */
html[data-theme="light"] .hero__lede:hover {
  filter: drop-shadow(0 0 5px rgba(217, 101, 26, 0.22));
  text-shadow:
    0 0 12px rgba(224, 138, 46, 0.18),
    0 0 22px rgba(166, 59, 30, 0.10),
    0 1px 0  rgba(255, 248, 215, 0.75);
}
html[data-theme="light"] .hero__rune-text { fill: var(--primary) !important; }
html[data-theme="light"] .hero__portrait-glow {
  background: radial-gradient(circle, rgba(216, 174, 99, 0.55) 0%, transparent 70%);
}

/* Hero CTAs · re-tone the seals to bronze-on-parchment so they
   read against the warm manuscript backdrop without losing the
   ritual feel of the dark theme. */
html[data-theme="light"] .hero__cta--primary {
  color: #2A1808;
  background: linear-gradient(160deg,
    rgba(255, 246, 218, 0.98),
    rgba(232, 200, 140, 0.95));
  border-color: rgba(120, 70, 30, 0.7);
  box-shadow:
    inset 0 0 0 1px rgba(255, 250, 235, 0.6),
    inset 0 -2px 6px rgba(120, 80, 40, 0.22),
    0 6px 16px rgba(60, 30, 8, 0.22);
}
html[data-theme="light"] .hero__cta--primary:hover {
  box-shadow:
    inset 0 0 0 1px rgba(255, 250, 235, 0.7),
    inset 0 -2px 6px rgba(120, 80, 40, 0.22),
    0 10px 22px rgba(60, 30, 8, 0.3),
    0 0 24px rgba(216, 174, 99, 0.4);
}
html[data-theme="light"] .hero__cta--ghost {
  color: var(--burgundy, #5C2B1F);
  background: linear-gradient(160deg,
    rgba(248, 232, 196, 0.7),
    rgba(228, 200, 150, 0.5));
  border-color: rgba(140, 90, 47, 0.55);
  box-shadow:
    inset 0 0 14px rgba(255, 240, 200, 0.4),
    0 4px 12px rgba(60, 30, 8, 0.15);
}
html[data-theme="light"] .hero__cta--ghost:hover {
  color: var(--rust, #A13E1E);
  background: linear-gradient(160deg,
    rgba(255, 245, 215, 0.85),
    rgba(232, 200, 140, 0.7));
  border-color: rgba(140, 90, 47, 0.85);
  box-shadow:
    inset 0 0 14px rgba(255, 245, 215, 0.55),
    0 8px 18px rgba(60, 30, 8, 0.22),
    0 0 20px rgba(216, 174, 99, 0.32);
}
/* Crystalline icon stays legible on parchment — deeper teal. */
html[data-theme="light"] .hero__cta--ghost .hero__cta-icon {
  color: #2C7A70;
  filter: drop-shadow(0 0 3px rgba(64, 160, 150, 0.45));
}

/* Narrative chapter spine · in light mode the medallions become
   burgundy wax stamps on an aged-paper line. */
html[data-theme="light"] .narrative__list::before {
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(140, 90, 47, 0.35) 12%,
    rgba(140, 90, 47, 0.55) 50%,
    rgba(140, 90, 47, 0.35) 88%,
    transparent 100%);
}
html[data-theme="light"] .narrative__roman {
  color: var(--burgundy, #5C2B1F);
  background: linear-gradient(160deg, rgba(255, 245, 215, 0.92), rgba(232, 200, 140, 0.9));
  border-color: rgba(140, 90, 47, 0.55);
  text-shadow: 0 1px 0 rgba(255, 245, 215, 0.5);
}
html[data-theme="light"] .narrative__label { color: var(--burgundy, #5C2B1F); }
html[data-theme="light"] .narrative__hint  { color: rgba(60, 30, 8, 0.65); }
html[data-theme="light"][data-narrative-act="1"] .narrative__act[data-act="1"] .narrative__roman,
html[data-theme="light"][data-narrative-act="2"] .narrative__act[data-act="2"] .narrative__roman,
html[data-theme="light"][data-narrative-act="3"] .narrative__act[data-act="3"] .narrative__roman,
html[data-theme="light"][data-narrative-act="4"] .narrative__act[data-act="4"] .narrative__roman,
html[data-theme="light"][data-narrative-act="5"] .narrative__act[data-act="5"] .narrative__roman {
  color: #FFE7A0;
  background: linear-gradient(160deg, rgba(120, 50, 18, 0.95), rgba(80, 25, 8, 0.95));
  border-color: rgba(255, 215, 130, 0.8);
  box-shadow:
    inset 0 0 8px rgba(255, 231, 160, 0.45),
    0 0 18px rgba(216, 174, 99, 0.45);
}

/* SECTION HEADERS */
html[data-theme="light"] .tree-vault__title,
html[data-theme="light"] .memories__title,
html[data-theme="light"] .portal__title {
  color: var(--on-surface);
}
html[data-theme="light"] .tree-vault__lede,
html[data-theme="light"] .memories__lede,
html[data-theme="light"] .portal__lede {
  color: var(--on-surface-variant);
}
html[data-theme="light"] .memories__eyebrow,
html[data-theme="light"] .tree-vault__eyebrow {
  color: var(--burgundy);
  text-shadow: 0 1px 0 rgba(255, 245, 200, 0.6);
}

/* ----------------------------------------------------------------
   TREE HUD — parchment card with bronze frame
   ---------------------------------------------------------------- */
html[data-theme="light"] .tree-hud {
  background: var(--glass-bg);
  border: 1px solid var(--bronze-mid);
  border-radius: 14px;
  /* Double-border filigree: inner pale ivory line + outer bronze */
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.55),
    0 6px 22px rgba(43, 29, 14, 0.14);
  color: var(--on-surface);
  text-shadow: none;
  backdrop-filter: blur(var(--glass-blur)) saturate(1.15);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.15);
}
html[data-theme="light"] .tree-hud__title,
html[data-theme="light"] .tree-hud__counter,
html[data-theme="light"] .tree-hud__title__counter,
html[data-theme="light"] .tree-hud strong {
  color: var(--burgundy);
  text-shadow: none;
}
html[data-theme="light"] .tree-hud__bar {
  background: rgba(42, 29, 14, 0.20);
  border-radius: 999px;
}
html[data-theme="light"] .tree-hud__bar > div {
  background: linear-gradient(90deg, var(--gold), var(--gold-hover));
  border-radius: 999px;
  box-shadow: 0 0 8px rgba(176, 122, 42, 0.55);
}
html[data-theme="light"] .tree-hud button {
  background: var(--glass-bg);
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
}
html[data-theme="light"] .tree-hud button:hover {
  background: rgba(176, 122, 42, 0.20);
  border-color: var(--primary);
  color: var(--burgundy);
}
html[data-theme="light"] .tree-hint {
  background: var(--glass-bg);
  border: 1px solid var(--bronze-mid);
  border-radius: 999px;
  color: var(--on-surface);
  text-shadow: none;
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}

/* TOOLTIPS */
html[data-theme="light"] .tree-tooltip {
  background: var(--glass-bg-opaque);
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.5),
    0 8px 26px rgba(43, 29, 14, 0.24);
}

/* CLUSTER LEGEND tags adapt to theme */
html[data-theme="light"] .cluster-tag {
  background: var(--glass-bg);
  border-color: var(--bronze-mid);
  color: var(--on-surface-variant);
}
html[data-theme="light"] .cluster-tag.is-mastered {
  background: rgba(176, 122, 42, 0.22);
  color: var(--burgundy);
  border-color: var(--primary);
}

/* ----------------------------------------------------------------
   BUTTONS
   ---------------------------------------------------------------- */
html[data-theme="light"] .btn--primary {
  background: linear-gradient(135deg, var(--gold-hover), var(--gold));
  color: #2A1D0E;
  border: 1px solid var(--bronze);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.4),
    0 6px 20px rgba(176, 122, 42, 0.38);
}
html[data-theme="light"] .btn--primary:hover {
  filter: brightness(1.04);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.55),
    0 8px 24px rgba(176, 122, 42, 0.50);
}
html[data-theme="light"] .btn--ghost {
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}
html[data-theme="light"] .btn--ghost:hover {
  background: rgba(176, 122, 42, 0.20);
  border-color: var(--primary);
  color: var(--burgundy);
}

/* ----------------------------------------------------------------
   CRYSTAL CAPTIONS — parchment chips
   ---------------------------------------------------------------- */
html[data-theme="light"] .crystal-caption {
  background: var(--glass-bg);
  border: 1px solid var(--bronze-mid);
  border-radius: 12px;
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.45),
    0 4px 14px rgba(43, 29, 14, 0.14);
  color: var(--on-surface);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}
html[data-theme="light"] .crystal-caption__name {
  color: var(--on-surface);
  text-shadow: none;
}
html[data-theme="light"] .crystal-caption__rarity {
  color: var(--burgundy);
  background: transparent;
  border: 0;
  text-shadow: none;
  padding: 0;
}

html[data-theme="light"] .crystal-loader {
  color: var(--on-surface);
  background: var(--glass-bg);
  border: 1px solid var(--bronze-mid);
  text-shadow: none;
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}

/* MEMORY VAULT (crystal modal) — manuscript dim backdrop, sepia-tinted */
/* Vault backdrop in light mode — sepia-veil instead of black grimoire.
   The card itself is colour-stable across themes (leather + bronze
   reads correctly on either background), so we only tweak the veil. */
html[data-theme="light"] .crystal-vault__backdrop {
  background:
    radial-gradient(ellipse 60% 50% at 50% 45%, rgba(120, 70, 28, 0.22), transparent 70%),
    radial-gradient(ellipse at center, rgba(58, 30, 8, 0.62) 0%, rgba(28, 14, 4, 0.90) 78%);
  backdrop-filter: blur(14px) saturate(1.2) sepia(0.18);
  -webkit-backdrop-filter: blur(14px) saturate(1.2) sepia(0.18);
}

/* PORTAL */
html[data-theme="light"] .portal__link {
  background: var(--glass-bg);
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.4),
    0 4px 16px rgba(43, 29, 14, 0.12);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}
html[data-theme="light"] .portal__link:hover,
html[data-theme="light"] .portal__link:focus-visible {
  background: rgba(176, 122, 42, 0.22);
  border-color: color-mix(in srgb, var(--channel-glow) 70%, var(--primary) 30%);
  color: var(--burgundy);
  /* Keep the zoom from the base rule; override only the colour
     so the mystical glow stays consistent across both themes. */
}

/* Light-theme region accents — deeper, ink-like hues so the
   column titles stay legible against parchment. The dark-mode
   bright greens/ambers would wash out on illuminated paper. */
html[data-theme="light"] .portal__column[data-region="atlantic"] {
  --col-accent: #0E5B33;                       /* forest ink */
  --col-glow:   rgba(14, 91, 51, 0.55);
}
html[data-theme="light"] .portal__column[data-region="iberian"] {
  --col-accent: #8B4A12;                       /* burnt sienna */
  --col-glow:   rgba(139, 74, 18, 0.55);
}
html[data-theme="light"] .portal__column-title {
  text-shadow:
    0 0 0 transparent,
    0 1px 0 rgba(255, 245, 200, 0.5);
}
html[data-theme="light"] .portal__flag {
  outline-color: rgba(76, 50, 18, 0.45);
}

/* MERLIN (light mode) — keep the parchment scroll feel but tune it
   for the Codex-Arcano paper background so it stays legible. */
html[data-theme="light"] .merlin__scroll {
  background:
    radial-gradient(ellipse 80% 60% at 30% 25%, rgba(255, 245, 220, 0.45), transparent 70%),
    linear-gradient(180deg, #F8ECC4 0%, #ECDAA8 55%, #DCC086 100%);
  color: #2A1F12;
  box-shadow:
    inset 0 0 0 1px rgba(120, 90, 55, 0.30),
    inset 0 0 0 2px rgba(255, 245, 220, 0.85),
    inset 0 0 18px rgba(120, 80, 40, 0.10),
    0 10px 24px rgba(43, 36, 28, 0.22),
    0 0 20px rgba(184, 138, 59, 0.18);
}
html[data-theme="light"] .merlin__text          { color: #2A1F12; }
html[data-theme="light"] .merlin__text::first-line { color: #831B1A; }

html[data-theme="light"] .merlin__quill {
  background:
    radial-gradient(ellipse 70% 60% at 30% 30%, rgba(255, 245, 220, 0.45), transparent 70%),
    linear-gradient(180deg, #F5E5BB 0%, #E5CE9C 100%);
  box-shadow:
    inset 0 0 0 1px rgba(120, 90, 55, 0.28),
    inset 0 0 0 2px rgba(255, 245, 220, 0.70),
    inset 0 0 12px rgba(120, 80, 40, 0.10),
    0 4px 14px rgba(43, 36, 28, 0.18);
}
html[data-theme="light"] .merlin__quill-input { color: #2A1F12; }
html[data-theme="light"] .merlin__quill-input::placeholder { color: rgba(42, 31, 18, 0.55); }
html[data-theme="light"] .merlin__quill-send {
  border-color: rgba(120, 90, 55, 0.55);
  background: rgba(255, 245, 220, 0.7);
  color: #831B1A;
}
html[data-theme="light"] .merlin__quill-send:hover,
html[data-theme="light"] .merlin__quill-send:focus-visible {
  background: #831B1A;
  color: #FFE6A8;
}

html[data-theme="light"] .merlin__avatar {
  filter: drop-shadow(0 5px 14px rgba(184, 138, 59, 0.40));
}

/* MILESTONE banner — illuminated parchment with bronze frame */
html[data-theme="light"] .milestone-banner {
  background:
    radial-gradient(ellipse 60% 80% at 50% 0%, rgba(255, 245, 200, 0.85), transparent 70%),
    linear-gradient(180deg, var(--surface-bright) 0%, var(--surface-container) 100%);
  border: 1px solid var(--bronze-mid);
  color: var(--on-surface);
  text-shadow: 0 1px 0 rgba(255, 245, 200, 0.55);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 200, 0.55),
    0 10px 28px rgba(43, 29, 14, 0.22);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}
html[data-theme="light"] .milestone-banner__sigil { color: var(--burgundy); }
html[data-theme="light"] .milestone-banner__text  { color: var(--on-surface); }

/* FOOTER — manuscript colophon with bronze rule above */
html[data-theme="light"] .footer {
  background: transparent;
  border-top: 1px solid var(--bronze-mid);
  color: var(--on-surface-variant);
  box-shadow: 0 -1px 0 var(--bronze-soft);
}
html[data-theme="light"] .footer__line { text-shadow: none; }

/* CODEX VEIL — sepia-ink backdrop, more aged-ink than pure black */
html[data-theme="light"] .codex__veil {
  background:
    radial-gradient(ellipse at center, rgba(42, 29, 14, 0.55) 0%, rgba(20, 12, 4, 0.92) 75%);
}

/* CONTRACTS · Codex dos Contratos Arcanos
   Pseudo intentionally disabled in dark mode (phantom-border fix);
   no Solis override needed — keep the rule here as a reminder so
   future edits don't reintroduce a bounded backdrop. */
html[data-theme="light"] .contracts::before {
  content: none;
  background: none;
  display: none;
}
html[data-theme="light"] .contracts__eyebrow {
  color: var(--burgundy);
  text-shadow: 0 1px 0 rgba(255, 245, 200, 0.55);
}
html[data-theme="light"] .contracts__title {
  background: linear-gradient(180deg, var(--ink-deep) 30%, var(--primary) 95%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 1px 0 rgba(255, 245, 200, 0.45);
}
html[data-theme="light"] .contracts__subtitle {
  color: var(--on-surface);
}
html[data-theme="light"] .contracts__crown { color: var(--primary); opacity: 0.78; }
html[data-theme="light"] .contracts__seal-text { color: var(--primary); }
html[data-theme="light"] .contracts__seal-mark { color: var(--primary); }
html[data-theme="light"] .contracts__seal-line {
  background: linear-gradient(90deg, transparent, var(--primary) 50%, transparent);
  opacity: 0.35;
}
/* Soften the legendary outer halo in light mode so the book does
   not bloom too aggressively over the warm parchment page. */
html[data-theme="light"] .contract[data-rarity="legendary"] .contract__book {
  box-shadow:
    0 0 0 1px rgba(140, 90, 47, 0.4),
    0 0 0 3px rgba(43, 36, 28, 0.5),
    0 0 0 4px rgba(216, 174, 99, 0.65),
    0 12px 32px rgba(43, 36, 28, 0.16),
    0 0 60px rgba(216, 174, 99, 0.24);
}

/* SCROLLBAR */
html[data-theme="light"] {
  scrollbar-color: var(--primary) transparent;
}

/* ======================================================
   ARCANE WELCOME · first-visit onboarding overlay
   - position: fixed full-screen, pointer-events: none
   - 1.5s materialize → 6s idle → 3s line-by-line dissolve
   - dissolves into golden particles that drift toward the
     Arcane Core (.hero__portrait), which then pulses once
   - respects prefers-reduced-motion
   Module: src/js/welcome.js · localStorage key cv:arcane-welcome
   ====================================================== */
.welcome {
  position: fixed;
  inset: 0;
  z-index: 4000;
  /* GHOSTLY: never blocks ANYTHING. Inherited by all nested
     elements (none override this). */
  pointer-events: none;
  overflow: hidden;
  isolation: isolate;
  opacity: 0;
  transition: opacity 0.5s ease;
  will-change: opacity;
}
.welcome.is-active { opacity: 1; }
.welcome.is-done {
  opacity: 0;
  transition: opacity 0.7s ease 0.2s;
}

/* Soft darkening veil that frames the message without blocking it.
   The welcome is now centred in the viewport (instruction June 2026),
   so the haze is centred at 50% 50% to wrap the message + breath
   together as a single warm spotlight. The veil is also a touch
   stronger so the bright magma text reads cleanly on any wallpaper. */
.welcome__veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 75vmin 55vmin at 50% 50%,
      rgba(8, 5, 10, 0.55) 0%,
      rgba(8, 5, 10, 0.28) 38%,
      rgba(8, 5, 10, 0.08) 60%,
      transparent 78%);
  opacity: 0;
  animation: welcome-veil-in 1.5s ease forwards;
}
@keyframes welcome-veil-in {
  to { opacity: 1; }
}

/* DRAGON'S BREATH (fire) removed June 2026 by request — the welcome
   message now materialises on its own (veil + motes + lava text),
   with no fire burst. All `.welcome__breath*` rules and their
   keyframes were deleted to keep the final build lean. */


/* Message panel · centred in the viewport (instruction June 2026).
   The panel now sits at (50%, 50%) so the welcome reads as a single
   focal moment in the middle of the screen — the message and the
   dragon's breath ignite around the same point. The h1 in the hero
   section is hidden behind the veil during the welcome anyway, so
   there's no overlap concern. */
.welcome__panel {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: min(680px, 92vw);
  padding: 0 1rem;
  text-align: center;
}

/* (Removed June 2026) The "initial beacon" — a small golden circle
   that flashed and expanded at the message spot — was the last
   remnant of the dragon's-breath ignition. Removed by request: the
   message now simply materialises (lava chars + motes) with no
   circular flash. The old sonar "expanding ring" cue was removed
   earlier for the same reason. */

/* Brief tremor on the panel to add a
   subtle "vibrant" pulse — settles before the text fades in.
   Updated to compose with the new translate(-50%, -50%) centring
   transform so the tremor doesn't accidentally undo the centring. */
@keyframes welcome-panel-tremor {
  0%, 100% { transform: translate(-50%, -50%); }
  20%      { transform: translate(-50%, calc(-50% - 1.5px)); }
  40%      { transform: translate(-50%, calc(-50% + 1.5px)); }
  60%      { transform: translate(-50%, calc(-50% - 1px)); }
  80%      { transform: translate(-50%, calc(-50% + 1px)); }
}
.welcome.is-active .welcome__panel {
  animation: welcome-panel-tremor 0.55s ease-out both;
}

.welcome__line {
  margin: 0;
  font-family: "Cinzel", "Libre Caslon Text", Georgia, serif;
  font-weight: 400;
  font-size: clamp(0.95rem, 2.2vmin, 1.35rem);
  letter-spacing: 0.04em;
  line-height: 1.65;
  /* The base color is irrelevant — every char is overridden by the
     lava background-clip. We keep a fallback for browsers without
     background-clip:text and for the brief window before the char
     spans replace the textContent. */
  color: #F4E8C6;
  /* Warmer shadow palette (matches the magma aura on chars). */
  text-shadow:
    0 0 12px rgba(255, 170, 80, 0.40),
    0 1px 2px rgba(20, 6, 4, 0.55);
  /* The line itself never animates — only its split-character spans do.
     We expose two CSS vars so chars can compose their delay:
       --line-delay  · when the first char starts materializing
       --leave-delay · when the first char starts dissolving
     Default to 0 so chars work even if data-line is absent. */
  --line-delay: 0s;
  --leave-delay: 0s;
  will-change: contents;
}
.welcome__line + .welcome__line { margin-top: 0.55rem; }

/* The title sits above the body lines visually but appears LAST.
   We let the natural source order keep it on top and just use
   animation-delay to push its entrance to the end. */
.welcome__title {
  font-family: "Cinzel", "Libre Caslon Text", serif;
  /* Heavier weight + a brightness/glow lift so the opening line reads
     as the dominant headline of the welcome message (user request). */
  font-weight: 700;
  /* Viewport-relative size so the title ALWAYS fits on a single line
     (white-space: nowrap below). The 3vw slope keeps the line width
     proportional to the container at every width; the clamp ceiling
     prevents it from getting oversized on wide screens. */
  font-size: clamp(0.66rem, 2.55vw, 1.18rem);
  letter-spacing: 0.02em;
  white-space: nowrap;
  /* Fallback color — chars override via background-clip; the line
     itself never paints because all glyphs are wrapped in spans. */
  color: #FFE8B5;
  /* Hot title aura matches the magma theme. */
  text-shadow:
    0 0 14px rgba(255, 160, 70, 0.65),
    0 0 36px rgba(220, 70, 25, 0.45),
    0 2px 4px rgba(20, 6, 4, 0.55);
  /* Parent-level lift brightens the whole title (including the lava
     char spans, whose own filter/text-shadow are pinned by their
     forwards animations and so can't be brightened individually). */
  filter: brightness(1.14) drop-shadow(0 0 12px rgba(255, 184, 96, 0.5));
  margin: 0 0 1rem;
}
/* Decorative bookend stars · stay as a stable golden sigil that
   contrasts the flowing lava letters, but the colour is shifted
   warmer (ember gold) so it doesn't read cold against the magma. */
.welcome__star {
  display: inline-block;
  color: #FFB868;
  font-size: 0.82em;
  margin: 0 0.28em;
  vertical-align: 0.05em;
  text-shadow:
    0 0 14px rgba(255, 175, 80, 0.85),
    0 0 28px rgba(220, 80, 30, 0.55);
  opacity: 0;
  transform: translateY(8px) scale(0.8);
  filter: blur(6px);
  animation: welcome-char-in 0.6s cubic-bezier(.2,.7,.2,1) forwards;
  animation-delay: var(--line-delay, 0s);
}
.welcome__line--intro {
  font-style: italic;
  color: #E9DBB5;
  margin-bottom: 0.45rem;
}

/* PER-LINE ENTRY/EXIT TIMING
   Materialize order (body lines first, title LAST):
     line 2 → line 3 → line 4 → line 5 → line 1 (title)
   Dissolve order (bottom-up, per the spec):
     line 5 → line 4 → line 3 → line 2 → line 1 (title) */
.welcome__line[data-line="2"] { --line-delay: 0.30s; --leave-delay: 1.50s; }
.welcome__line[data-line="3"] { --line-delay: 0.50s; --leave-delay: 1.00s; }
.welcome__line[data-line="4"] { --line-delay: 0.70s; --leave-delay: 0.50s; }
.welcome__line[data-line="5"] { --line-delay: 0.90s; --leave-delay: 0.00s; }
.welcome__line[data-line="1"] { --line-delay: 1.10s; --leave-delay: 2.00s; }

/* CHARACTER-LEVEL ANIMATIONS
   .welcome__char spans are injected by welcome.js (see splitLinesIntoChars).
   Each carries --ci = its 0-based index within its line so we can stagger
   the entrance/exit one letter at a time. The composite delay is:
     line_delay + (ci * step)
   step = 18ms gives a smooth wave that finishes a 30-char line in ~0.55s.
   The title's bookend stars animate via the rule above using only the
   line-delay so they appear together with the first/last title chars. */
/* MAGMA / LAVA TEXT (instruction June 2026)
   ────────────────────────────────────────────────────────────
   Every character is a window into a flowing volcanic field.
   The fill is `transparent` (via -webkit-text-fill-color) and
   the visible color is supplied by a multi-stop horizontal
   gradient clipped to the glyph's outline (background-clip:
   text). The gradient is 320% wide and its background-position
   animates infinitely, so molten material continuously streams
   across the letterforms — exactly like a slow magma current.

   The colour stops walk through real volcanic temperatures:
     #1A0303  basalt crust (cooled rock)
     #4D0A07  smouldering coal
     #B12C0E  dark ember
     #E94E15  bright ember
     #FF8326  flowing magma
     #FFD06A  molten yellow (hottest visible)
     ↑ then back down to crust on the right edge

   The orange/red text-shadow stack adds a heat aura that
   pulses through the emerge keyframes, then settles into a
   continuous warm halo around every glyph. */
/* Word wrapper injected by welcome.js — keeps the per-letter spans of
   a single word together so a line never breaks mid-word. Lines still
   wrap at the spaces between words (which sit outside these wrappers). */
.welcome__word {
  display: inline-block;
  white-space: nowrap;
}

.welcome__char {
  display: inline-block;
  padding: 0 0.04em;
  background:
    linear-gradient(
      105deg,
      #1A0303 0%,
      #4D0A07 6%,
      #8C1908 14%,
      #C8341A 24%,
      #F06A1F 36%,
      #FFB05A 47%,
      #FFE49A 52%,
      #FFB05A 57%,
      #F06A1F 68%,
      #C8341A 78%,
      #8C1908 86%,
      #4D0A07 94%,
      #1A0303 100%
    );
  background-size: 320% 100%;
  background-position: 0% 50%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* Persistent heat aura — survives across emergence keyframes
     and continues into the idle phase so each letter glows
     faintly even after the materialization finishes. */
  text-shadow:
    0 0 6px  rgba(255, 170, 70, 0.50),
    0 0 14px rgba(255, 110, 35, 0.40),
    0 0 28px rgba(180, 40, 12, 0.30),
    0 1px 1px rgba(40, 8, 4, 0.55);
  /* Initial state for the emergence: dark and unformed.
     Background still renders but the letter is blurred so
     the lava texture only sharpens as the glyph crystallises. */
  opacity: 0;
  transform: translateY(14px) scale(0.78);
  filter: blur(10px) brightness(1.4) saturate(1.4);
  /* TWO LAYERED ANIMATIONS:
       1. welcome-char-emerge  · single 0.85s materialization
       2. welcome-char-lava    · 8s infinite background-position
          sweep, starts shortly AFTER the emergence completes
          (offset by +0.4s on top of the cascade) so the lava
          starts flowing once the letter is sharp. */
  animation:
    welcome-char-emerge 0.85s cubic-bezier(.22, 1, .36, 1) forwards,
    welcome-char-lava 8s linear infinite;
  animation-delay:
    calc(var(--line-delay, 0s) + var(--ci, 0) * 0.024s),
    calc(var(--line-delay, 0s) + var(--ci, 0) * 0.024s + 0.4s);
  will-change: opacity, transform, filter, background-position;
}
.welcome__char--space {
  /* Preserve word spacing without animating an empty pill.
     The space has no glyph for background-clip to render, so
     we only need to fade it in. */
  filter: none;
  background: none;
  animation: welcome-char-in-space 0.85s linear forwards;
  animation-delay: calc(var(--line-delay, 0s) + var(--ci, 0) * 0.024s);
}

/* LAVA FLOW · infinite slow drift of the gradient across every
   glyph's clipped paint. 8s per cycle keeps each pass slow and
   meditative, like real molten rock; 320% size means the entire
   gradient revisits every position over multiple cycles without
   any visible jump. */
@keyframes welcome-char-lava {
  0%   { background-position: 0%   50%; }
  100% { background-position: 320% 50%; }
}

/* CINEMATIC EMERGENCE · volcanic aesthetic
   ────────────────────────────────────────────────────────────
   Three-phase contract — the keyframe drives opacity, transform,
   filter and a VOLCANIC text-shadow palette (orange / red / coal)
   so the materialization itself reads like a glyph cooling out
   of molten rock. After emergence, the persistent shadows defined
   on .welcome__char take over as the ambient heat halo.
     ember     (0 → 30%)  faint deep-red coal-glow in place
     condense  (30 → 70%) glyph crystallises, hottest orange peak
     settle    (70 → 100%) overshoot eases into ambient lava sheen */
@keyframes welcome-char-emerge {
  0% {
    opacity: 0;
    transform: translateY(14px) scale(0.78);
    filter: blur(10px) brightness(1.4) saturate(1.4);
    text-shadow: 0 0 0 transparent;
  }
  18% {
    opacity: 0.30;
    transform: translateY(10px) scale(0.86);
    filter: blur(7px) brightness(1.5) saturate(1.5);
    text-shadow:
      0 0 18px rgba(255, 130, 50, 0.65),
      0 0 6px  rgba(200, 50, 18, 0.55);
  }
  35% {
    opacity: 0.70;
    transform: translateY(6px) scale(0.94);
    filter: blur(3px) brightness(1.45) saturate(1.5);
    text-shadow:
      0 0 28px rgba(255, 160, 60, 0.85),
      0 0 12px rgba(255, 90, 30, 0.95),
      0 0 4px  rgba(255, 220, 140, 0.85);
  }
  55% {
    opacity: 1;
    transform: translateY(2px) scale(1.02);
    filter: blur(1px) brightness(1.22) saturate(1.45);
    text-shadow:
      0 0 34px rgba(255, 170, 70, 0.95),
      0 0 14px rgba(255, 100, 35, 1),
      0 0 6px  rgba(255, 230, 160, 0.85);
  }
  78% {
    opacity: 1;
    transform: translateY(0) scale(1.015);
    filter: blur(0.4px) brightness(1.08) saturate(1.35);
    text-shadow:
      0 0 22px rgba(255, 150, 60, 0.65),
      0 0 8px  rgba(220, 70, 25, 0.55),
      0 0 4px  rgba(255, 210, 140, 0.55);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0) brightness(1) saturate(1.25);
    /* Final shadows match the persistent lava aura defined on
       .welcome__char so there's no visible "snap" when the
       keyframe finishes. */
    text-shadow:
      0 0 6px  rgba(255, 170, 70, 0.50),
      0 0 14px rgba(255, 110, 35, 0.40),
      0 0 28px rgba(180, 40, 12, 0.30),
      0 1px 1px rgba(40, 8, 4, 0.55);
  }
}

/* Preserved for the original simple sequence — used by legacy
   contexts that opt-in by overriding the animation-name. */
@keyframes welcome-char-in {
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}
@keyframes welcome-char-in-space {
  to { opacity: 1; }
}

/* PARTICLES · 12 small golden motes scattered around the panel.
   They fade in with the message, drift slowly while idle, and
   converge inward during dissolution. */
.welcome__motes {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.welcome__mote {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: radial-gradient(circle, #FFE5A8 0%, #C9986A 60%, transparent 80%);
  box-shadow: 0 0 10px rgba(255, 215, 160, 0.7);
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.3);
  animation:
    welcome-mote-in 1.5s ease forwards,
    welcome-mote-drift 5s ease-in-out 1.6s infinite alternate;
  will-change: opacity, transform;
}
/* Deterministic positions distributed around the CENTRE of the
   viewport (instruction June 2026 — welcome was previously top-
   pinned). The 12 motes form an irregular ring around the
   message at top ~32–68% so they surround the dragon's breath
   without overlapping the title itself. */
.welcome__mote:nth-child(1)  { top: 42%; left: 26%; animation-delay: 0.10s, 1.6s; }
.welcome__mote:nth-child(2)  { top: 44%; left: 72%; animation-delay: 0.15s, 1.6s; }
.welcome__mote:nth-child(3)  { top: 32%; left: 50%; animation-delay: 0.20s, 1.6s; }
.welcome__mote:nth-child(4)  { top: 56%; left: 22%; animation-delay: 0.25s, 1.6s; }
.welcome__mote:nth-child(5)  { top: 58%; left: 78%; animation-delay: 0.30s, 1.6s; }
.welcome__mote:nth-child(6)  { top: 34%; left: 38%; animation-delay: 0.35s, 1.6s; }
.welcome__mote:nth-child(7)  { top: 34%; left: 62%; animation-delay: 0.40s, 1.6s; }
.welcome__mote:nth-child(8)  { top: 64%; left: 36%; animation-delay: 0.45s, 1.6s; }
.welcome__mote:nth-child(9)  { top: 66%; left: 64%; animation-delay: 0.50s, 1.6s; }
.welcome__mote:nth-child(10) { top: 50%; left: 14%; animation-delay: 0.55s, 1.6s; }
.welcome__mote:nth-child(11) { top: 50%; left: 86%; animation-delay: 0.60s, 1.6s; }
.welcome__mote:nth-child(12) { top: 38%; left: 82%; animation-delay: 0.65s, 1.6s; }

@keyframes welcome-mote-in {
  to {
    opacity: 0.85;
    transform: translate(-50%, -50%) scale(1);
  }
}
@keyframes welcome-mote-drift {
  0%   { transform: translate(-50%, -50%) scale(1)   translate(0, 0); }
  100% { transform: translate(-50%, -50%) scale(1.1) translate(-5px, -8px); }
}

/* DISSOLUTION · bottom→top, character-by-character, ~3s total.
   The line's --leave-delay defines when its first char starts to
   evaporate; subsequent chars stagger via --ci (left→right within
   each line, mirroring reading direction). The title goes LAST. */
.welcome.is-leaving .welcome__char {
  animation: welcome-char-out 0.55s cubic-bezier(.4, 0, .6, 1) forwards;
  animation-delay: calc(var(--leave-delay, 0s) + var(--ci, 0) * 0.018s);
}
.welcome.is-leaving .welcome__char--space {
  animation-name: welcome-char-out-space;
}
.welcome.is-leaving .welcome__star {
  animation: welcome-char-out 0.55s cubic-bezier(.4, 0, .6, 1) forwards;
  animation-delay: var(--leave-delay, 0s);
}

/* DISSOLUTION · the lava chars rise upward and bloom outward as
   the cooling rock evaporates — the shadows brighten toward
   orange at the midpoint and fade through transparent embers. */
@keyframes welcome-char-out {
  0% {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0) brightness(1) saturate(1.25);
    text-shadow:
      0 0 6px  rgba(255, 170, 70, 0.50),
      0 0 14px rgba(255, 110, 35, 0.40),
      0 0 28px rgba(180, 40, 12, 0.30);
  }
  55% {
    opacity: 0.55;
    transform: translateY(-4px) scale(1.08);
    filter: blur(3px) brightness(1.3) saturate(1.45);
    text-shadow:
      0 0 28px rgba(255, 175, 75, 0.95),
      0 0 50px rgba(255, 100, 30, 0.65),
      0 0 12px rgba(255, 220, 150, 0.85);
  }
  100% {
    opacity: 0;
    transform: translateY(-12px) scale(1.18);
    filter: blur(8px) brightness(1.4) saturate(1.5);
    text-shadow:
      0 0 40px rgba(255, 180, 80, 0),
      0 0 80px rgba(255, 100, 30, 0);
  }
}
@keyframes welcome-char-out-space {
  to { opacity: 0; }
}

/* Motes drift toward the Arcane Core during dissolution */
.welcome.is-leaving .welcome__mote {
  animation: welcome-mote-out 2.6s cubic-bezier(.4,0,.6,1) forwards;
}
.welcome.is-leaving .welcome__mote:nth-child(1)  { animation-delay: 0.10s; }
.welcome.is-leaving .welcome__mote:nth-child(2)  { animation-delay: 0.18s; }
.welcome.is-leaving .welcome__mote:nth-child(3)  { animation-delay: 0.05s; }
.welcome.is-leaving .welcome__mote:nth-child(4)  { animation-delay: 0.22s; }
.welcome.is-leaving .welcome__mote:nth-child(5)  { animation-delay: 0.28s; }
.welcome.is-leaving .welcome__mote:nth-child(6)  { animation-delay: 0.12s; }
.welcome.is-leaving .welcome__mote:nth-child(7)  { animation-delay: 0.16s; }
.welcome.is-leaving .welcome__mote:nth-child(8)  { animation-delay: 0.32s; }
.welcome.is-leaving .welcome__mote:nth-child(9)  { animation-delay: 0.36s; }
.welcome.is-leaving .welcome__mote:nth-child(10) { animation-delay: 0.40s; }
.welcome.is-leaving .welcome__mote:nth-child(11) { animation-delay: 0.44s; }
.welcome.is-leaving .welcome__mote:nth-child(12) { animation-delay: 0.48s; }

@keyframes welcome-mote-out {
  0% {
    opacity: 0.85;
    transform: translate(-50%, -50%) scale(1);
    filter: blur(0);
  }
  100% {
    /* Converge DOWN toward the Arcane Core (hero portrait, ~50vh from top).
       Since the welcome is anchored above the hero, this trajectory really
       feels like the particles falling into the awakening core below. */
    opacity: 0;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.18);
    filter: blur(2px);
  }
}

/* Veil retracts during dissolution. The dragon's breath has already
   fully dissipated by the time the message starts dissolving, so it
   doesn't need its own exit animation. */
.welcome.is-leaving .welcome__veil {
  animation: welcome-veil-out 1.8s ease 1.2s forwards;
}
@keyframes welcome-veil-out {
  to { opacity: 0; }
}

/* SINGLE ARCANE CORE PULSE · triggered by welcome.js after the last
   line dissolves. Targets the existing .hero__portrait-glow ring so
   we don't introduce a new permanent element. Auto-removes itself. */
.hero__portrait.is-welcome-pulse .hero__portrait-glow {
  animation: welcome-core-pulse 1.5s cubic-bezier(.2,.7,.2,1);
}
@keyframes welcome-core-pulse {
  0%   { opacity: 0.55; transform: scale(1); filter: blur(0); }
  35%  {
    opacity: 1;
    transform: scale(1.32);
    filter: blur(2px) brightness(1.4);
  }
  100% { opacity: 0.55; transform: scale(1); filter: blur(0); }
}

/* Mobile tweaks */
@media (max-width: 640px) {
  .welcome__panel {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    max-width: min(94vw, 22rem);
    max-height: min(72dvh, calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 2rem));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 0.35rem 0.65rem;
  }
  .welcome__line { font-size: clamp(0.95rem, 4vw, 1.15rem); }
  /* Keep the headline on one line on phones too: a slightly steeper
     vw slope still fits the full title across narrow viewports while
     the nowrap + brightness lift carry over from the base rule. */
  .welcome__title { font-size: clamp(0.55rem, 2.7vw, 1.05rem); margin-bottom: 0.7rem; white-space: nowrap; }
  .welcome__mote { width: 3px; height: 3px; }
}
@media (max-width: 380px) {
  .welcome__line + .welcome__line { margin-top: 0.4rem; }
}

@media (prefers-reduced-motion: reduce) {
  .welcome,
  .welcome__veil,
  .welcome__line,
  .welcome__char,
  .welcome__star,
  .welcome__mote,
  .welcome__panel,
  .welcome.is-active .welcome__panel,
  .welcome.is-leaving .welcome__char,
  .welcome.is-leaving .welcome__star,
  .welcome.is-leaving .welcome__mote,
  .welcome.is-leaving .welcome__veil {
    animation: none !important;
    transition-duration: 0.25s !important;
  }
  /* Reduced motion: no tremor on the message panel. */
  .welcome__line {
    opacity: 1;
    transform: none;
    filter: none;
  }
  .welcome__char,
  .welcome__star {
    opacity: 1;
    transform: none;
    filter: none;
  }
  .welcome__mote { opacity: 0.6; transform: translate(-50%, -50%) scale(1); }
  .welcome__veil { opacity: 1; }
  .welcome.is-leaving .welcome__char,
  .welcome.is-leaving .welcome__star,
  .welcome.is-leaving .welcome__mote,
  .welcome.is-leaving .welcome__veil,
  .welcome.is-done .welcome__char,
  .welcome.is-done .welcome__star,
  .welcome.is-done .welcome__mote {
    opacity: 0;
  }
  .hero__portrait.is-welcome-pulse .hero__portrait-glow {
    animation: none;
  }
}

/* ============================================================
   NARRATIVE · Per-Act Entry Animations
   ────────────────────────────────────────────────────────────
   Each section earns a one-shot animation when the visitor
   enters it. The trigger is the [data-narrative-entered="true"]
   attribute set by src/js/narrative.js. When the visitor leaves
   the section, the attribute is removed, so the animation
   replays on re-entry. All animations have `forwards` so they
   settle gracefully at their destination state.

   ARCHITECTURAL RULES
   ─ Never disturb the underlying layout. Animations target
     pseudo elements (::before/::after) or already-decorative
     elements (auras, glows, watermarks) — never the load-
     bearing content layer.
   ─ Use `pointer-events: none` on every animated overlay so
     none of these effects accidentally block clicks.
   ─ Keep total durations ≤ 5s and let the animation end on a
     transparent / scaled-out state so subsequent hover/idle
     animations resume cleanly.
   ─ Honor prefers-reduced-motion by skipping all keyframes.
   ============================================================ */

/* ─────────────────────────────────────────────────────────────
   GLOBAL · The single thread of energy
   ─────────────────────────────────────────────────────────────
   #narrative-particles is the fullscreen canvas painted by
   src/js/narrative-particles.js. It sits BELOW the chapter
   spine (z-index 50) and ABOVE the body-wide skill-tree
   wallpaper (z-index 1). Pointer events are blocked so it
   never interferes with clicks on the page.
   ───────────────────────────────────────────────────────────── */
#narrative-particles {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 2;
  mix-blend-mode: screen;
}
/* Main content sits ABOVE the particle canvas so the DOM
   letters of "Carlos Vaz" stay legible while the particles
   converge BEHIND them as a glowing halo. Without this rule
   the canvas would float on top of the H1 and cover it. */
main {
  position: relative;
  z-index: 3;
}

/* ─────────────────────────────────────────────────────────────
   ATO I · O UNIVERSO  — entry on #hero
   ─────────────────────────────────────────────────────────────
   The particle canvas does the heavy lifting: thousands of
   gold/violet pinpricks converge from chaos into the letterforms
   of "CARLOS VAZ" exactly where the H1 lives. This CSS layer
   handles the letter-by-letter glyph reveal, the portrait halo
   burst and the supporting copy fade-up — so DOM glyphs become
   visible in lockstep with the particle formation.
   Sensation: "an identity surfaces from the universe."
   ───────────────────────────────────────────────────────────── */

#hero { position: relative; }

/* Portrait halo burst — retimed so the heartbeat fires WITH the
   ray sweep in the Cosmic Resonance narrative (the ray crosses the
   screen at t=1.1s and lasts 0.6s; this halo ignites in lockstep). */
#hero[data-narrative-entered="true"] .hero__rune-fire {
  animation: act1-rune-burst 1.8s 1.10s cubic-bezier(.16,1,.3,1) forwards;
}
@keyframes act1-rune-burst {
  0%   { opacity: 0.0; transform: scale(0.85); filter: blur(8px) brightness(1.0); }
  25%  { opacity: 0.85; transform: scale(1.08); filter: blur(4px) brightness(1.6); }
  60%  { opacity: 0.45; transform: scale(1.02); filter: blur(6px) brightness(1.2); }
  100% { opacity: 0;   transform: scale(1);    filter: blur(8px) brightness(1.0); }
}

/* LETTER MATERIALIZATION · Cinematic three-phase emergence
   ────────────────────────────────────────────────────────────
   The previous one-keyframe ink got cropped at the descenders
   (italic "z" lost its tail because filter:blur shrinks the
   element's paint bounds outward but the inline-block clipped
   it). This redesign:

   1. The two name-halves stay as `display: block` (their
      original style) — italic descenders are NOT inside a
      smaller inline-block box anymore.
   2. Each .hero__letter is `inline-block` with generous
      padding so blur/glow never reach the box edge.
   3. The keyframe is split into three perceptual phases:
        ember     0% → 30%   faint coal-glow appears in place,
                              heavy blur, very low opacity
        condense  30% → 70%  the glow solidifies into a sharp
                              glyph, peaks in brightness mid-way
        settle    70% → 100% scale eases back from a tiny
                              overshoot and the glow fades out
   4. Generous timing (1.6s per letter, 0.14s stagger) keeps
      the cascade continuous and visible — no abrupt blink.

   The H1 explicitly clears overflow:visible (insurance against
   any inherited rule), and `padding-block` on .hero__name-*
   reserves vertical room for the glow halo so the page layout
   doesn't shift when the animation starts. */
.hero__name {
  overflow: visible;
}
.hero__name-first,
.hero__name-last {
  /* Keep their original `display: block` from the existing rules
     so each name half occupies its own line. */
  padding-block: 0;
  overflow: visible;
}
/* Pull "Vaz" upward so it sits visually close to "Carlos" instead
   of leaving a full line of dead space between them. The negative
   margin is in em-units so it scales with the font, and was
   tuned by runtime measurement: pre-fix the gap was 66px, with
   -0.28em it collapsed to 46px, and with -0.55em it lands at a
   visually-tight ~7-10px (depending on viewport) — close enough
   that the two halves of the name read as one continuous block
   while leaving room for italic ascenders. */
.hero__name-last {
  margin-top: -0.85em;
}
.hero__letter {
  display: inline-block;
  /* Padding gives the blur halo and text-shadow room to render
     OUTSIDE the glyph's natural box without being clipped by
     inline-block's overflow. */
  padding: 0 0.04em;
  /* Compact line-height so the per-letter inline-blocks don't
     inject extra leading inside .hero__name-first/.hero__name-last
     (which is what was leaving a full empty line above "Vaz"). */
  line-height: 0.95;

  /* VOLCANIC LAVA TEXT (June 2026) — same treatment as the
     welcome screen's .welcome__char. The glyph paint is clipped
     to a wide horizontal magma gradient (coal → ember → molten
     yellow → ember → coal) that slowly drifts across the letter
     via the welcome-char-lava keyframe.
     We declare it on .hero__letter itself (instead of overriding
     it in a separate state) so the lava is in the FINAL visual
     vocabulary of the hero name — once the act1 emergence
     finishes, the lava sheen takes over without any handoff
     flicker. The italic colour on .hero__name-last would
     normally win the cascade for the second line, but our
     -webkit-text-fill-color: transparent here trumps it
     specifically for the letterforms. */
  background:
    linear-gradient(
      105deg,
      #1A0303 0%,
      #4D0A07 6%,
      #8C1908 14%,
      #C8341A 24%,
      #F06A1F 36%,
      #FFB05A 47%,
      #FFE49A 52%,
      #FFB05A 57%,
      #F06A1F 68%,
      #C8341A 78%,
      #8C1908 86%,
      #4D0A07 94%,
      #1A0303 100%
    );
  background-size: 320% 100%;
  background-position: 0% 50%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;

  /* At rest: the glyph is dimmed embers, never crisp. This is the
     state both BEFORE the animation triggers (first visit while
     welcome is up) AND after a returning visitor leaves the act. */
  opacity: 0;
  transform: translateY(14px) scale(0.78);
  filter: blur(10px) brightness(1.4);
  text-shadow:
    0 0 18px rgba(255, 231, 160, 0.0),
    0 0 0    transparent;
  transform-origin: 50% 60%;
  will-change: opacity, transform, filter, background-position;
}
#hero[data-narrative-entered="true"] .hero__letter {
  /* TWO LAYERED ANIMATIONS (June 2026):
       1. act1-letter-emerge   · single 1.3s materialization
                                 (per-letter staggered)
       2. welcome-char-lava    · 8s infinite background-position
                                 sweep — same gradient flow used
                                 on the welcome screen. Starts
                                 SHORTLY AFTER each letter finishes
                                 emerging so the lava reads only on
                                 the crystallised glyph.
     The earlier particle-formation sequence ("form-text") was
     removed at user request, so we no longer chain timings to
     1.1s/1.7s/4.2s/6.0s phases. The name now begins emerging
     at 0.6s after the act enters the viewport. */
  animation:
    act1-letter-emerge 1.3s cubic-bezier(.22, 1, .36, 1) both,
    welcome-char-lava 8s linear infinite;
  animation-delay:
    calc(0.6s + var(--i) * 0.14s),
    calc(0.6s + var(--i) * 0.14s + 1.0s);
}
/* Volcanic palette emergence (June 2026) — mirrors the keyframe
   used by .welcome__char on the welcome screen so "Carlos Vaz"
   materializes with the same magma aura. The text-shadow stack
   moves through coal → ember → molten yellow exactly like the
   welcome chars, and ends on the persistent lava halo that
   matches the gradient clipped to the glyph. */
@keyframes act1-letter-emerge {
  0% {
    opacity: 0;
    transform: translateY(14px) scale(0.78);
    filter: blur(10px) brightness(1.4) saturate(1.4);
    text-shadow: 0 0 0 transparent;
  }
  18% {
    opacity: 0.30;
    transform: translateY(10px) scale(0.86);
    filter: blur(7px) brightness(1.5) saturate(1.5);
    text-shadow:
      0 0 18px rgba(255, 130, 50, 0.65),
      0 0 6px  rgba(200, 50, 18, 0.55);
  }
  35% {
    opacity: 0.70;
    transform: translateY(6px) scale(0.94);
    filter: blur(3px) brightness(1.45) saturate(1.5);
    text-shadow:
      0 0 28px rgba(255, 160, 60, 0.85),
      0 0 12px rgba(255, 90, 30, 0.95),
      0 0 4px  rgba(255, 220, 140, 0.85);
  }
  55% {
    opacity: 1;
    transform: translateY(2px) scale(1.02);
    filter: blur(1px) brightness(1.22) saturate(1.45);
    text-shadow:
      0 0 34px rgba(255, 170, 70, 0.95),
      0 0 14px rgba(255, 100, 35, 1),
      0 0 6px  rgba(255, 230, 160, 0.85);
  }
  78% {
    opacity: 1;
    transform: translateY(0) scale(1.015);
    filter: blur(0.4px) brightness(1.08) saturate(1.35);
    text-shadow:
      0 0 22px rgba(255, 150, 60, 0.65),
      0 0 8px  rgba(220, 70, 25, 0.55),
      0 0 4px  rgba(255, 210, 140, 0.55);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0) brightness(1) saturate(1.25);
    /* Persistent lava halo — survives after the keyframe ends
       so the letters keep glowing with the ambient heat aura
       even when only the lava sweep is animating. */
    text-shadow:
      0 0 6px  rgba(255, 170, 70, 0.50),
      0 0 14px rgba(255, 110, 35, 0.40),
      0 0 28px rgba(180, 40, 12, 0.30),
      0 1px 1px rgba(40, 8, 4, 0.55);
  }
}

/* Eyebrow + tagline + lede + CTAs fade-up AFTER the name finishes
   forming — so the visitor's eye lands on "Carlos Vaz" first,
   then the supporting copy quietly follows. */
#hero[data-narrative-entered="true"] .hero__eyebrow,
#hero[data-narrative-entered="true"] .hero__tagline,
#hero[data-narrative-entered="true"] .hero__lede {
  animation: act1-fade-up 0.95s cubic-bezier(.16,1,.3,1) both;
}
#hero[data-narrative-entered="true"] .hero__eyebrow  { animation-delay: 0.20s; }
/* Supporting copy waits for the name to fully forge before fading
   up. Now that the particle-formation prelude has been removed,
   the 9-letter cascade resolves at 0.6 + 8*0.14 + 1.3 ≈ 3.02s,
   so the trailing copy starts at 3.15s and staggers 0.25s. The
   name is still the focal moment; everything else respectfully
   follows. Hero CTAs are excluded — see .hero__actions above. */
#hero[data-narrative-entered="true"] .hero__tagline  { animation-delay: 3.15s; }
#hero[data-narrative-entered="true"] .hero__lede     { animation-delay: 3.40s; }
@keyframes act1-fade-up {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}


/* ─────────────────────────────────────────────────────────────
   ATO II · A CONVERGÊNCIA  — entry on #knowledge
   ─────────────────────────────────────────────────────────────
   All six pillar crystals pulse simultaneously in a synchronized
   "awakening". Each crystal's aura swells and brightens once,
   while every connection line briefly lights up so the energy
   visibly propagates from the center outward.
   Sensation: "the pillars reveal their presence."
   ───────────────────────────────────────────────────────────── */

#knowledge[data-narrative-entered="true"] .craft__node-aura {
  animation: act2-aura-burst 3.4s 0.25s cubic-bezier(.16,1,.3,1);
}
@keyframes act2-aura-burst {
  0%   { transform: scale(1);    opacity: 0.6; filter: brightness(1)  saturate(1); }
  18%  { transform: scale(1.45); opacity: 1;   filter: brightness(1.6) saturate(1.35); }
  55%  { transform: scale(1.18); opacity: 0.85;filter: brightness(1.3) saturate(1.18); }
  100% { transform: scale(1);    opacity: 0.6; filter: brightness(1)   saturate(1); }
}

/* The crystal body itself receives a sympathy pulse — slight
   scale + brightness lift on the same beat as its aura. */
#knowledge[data-narrative-entered="true"] .craft__node-crystal {
  animation: act2-crystal-pulse 3.0s 0.30s cubic-bezier(.16,1,.3,1);
}
@keyframes act2-crystal-pulse {
  0%   { transform: scale(1);    filter: brightness(1)   drop-shadow(0 0 0 transparent); }
  22%  { transform: scale(1.12); filter: brightness(1.45) drop-shadow(0 0 12px rgba(255, 231, 160, 0.55)); }
  100% { transform: scale(1);    filter: brightness(1)   drop-shadow(0 0 0 transparent); }
}

/* Connection lines: a SEQUENTIAL energy wave travelling outward
   through the constellation, line by line. The luminance pulse
   propagates from the central core to each pillar in turn —
   like a nerve impulse fanning out through a synaptic web. The
   per-line delays correspond to clockwise rotation around the
   crystal, so the visitor perceives a single wave sweep rather
   than six discrete blinks. */
#knowledge[data-narrative-entered="true"] .craft__line {
  animation: act2-line-pulse 1.4s cubic-bezier(.16,1,.3,1) both;
}
#knowledge[data-narrative-entered="true"] .craft__line[data-key="story"]     { animation-delay: 0.35s; }
#knowledge[data-narrative-entered="true"] .craft__line[data-key="ux"]        { animation-delay: 0.55s; }
#knowledge[data-narrative-entered="true"] .craft__line[data-key="direction"] { animation-delay: 0.75s; }
#knowledge[data-narrative-entered="true"] .craft__line[data-key="theme"]     { animation-delay: 0.95s; }
#knowledge[data-narrative-entered="true"] .craft__line[data-key="identity"]  { animation-delay: 1.15s; }
#knowledge[data-narrative-entered="true"] .craft__line[data-key="ambience"]  { animation-delay: 1.35s; }
@keyframes act2-line-pulse {
  0%   { stroke-opacity: 0.35; filter: drop-shadow(0 0 0 transparent); }
  35%  { stroke-opacity: 1;    filter: drop-shadow(0 0 14px rgba(255, 231, 160, 0.85)); }
  100% { stroke-opacity: 0.35; filter: drop-shadow(0 0 0 transparent); }
}

/* The aura/crystal pulses also stagger to ride the same wave —
   each pillar lights when its line reaches it. */
#knowledge[data-narrative-entered="true"] .craft__node[data-key="story"]     .craft__node-aura,
#knowledge[data-narrative-entered="true"] .craft__node[data-key="story"]     .craft__node-crystal { animation-delay: 0.65s; }
#knowledge[data-narrative-entered="true"] .craft__node[data-key="ux"]        .craft__node-aura,
#knowledge[data-narrative-entered="true"] .craft__node[data-key="ux"]        .craft__node-crystal { animation-delay: 0.85s; }
#knowledge[data-narrative-entered="true"] .craft__node[data-key="direction"] .craft__node-aura,
#knowledge[data-narrative-entered="true"] .craft__node[data-key="direction"] .craft__node-crystal { animation-delay: 1.05s; }
#knowledge[data-narrative-entered="true"] .craft__node[data-key="theme"]     .craft__node-aura,
#knowledge[data-narrative-entered="true"] .craft__node[data-key="theme"]     .craft__node-crystal { animation-delay: 1.25s; }
#knowledge[data-narrative-entered="true"] .craft__node[data-key="identity"]  .craft__node-aura,
#knowledge[data-narrative-entered="true"] .craft__node[data-key="identity"]  .craft__node-crystal { animation-delay: 1.45s; }
#knowledge[data-narrative-entered="true"] .craft__node[data-key="ambience"]  .craft__node-aura,
#knowledge[data-narrative-entered="true"] .craft__node[data-key="ambience"]  .craft__node-crystal { animation-delay: 1.65s; }

/* The central core feels the wave too — a small reciprocal
   pulse on its outer ring. */
#knowledge[data-narrative-entered="true"] .craft__core-ring {
  animation: act2-core-pulse 3.2s 0.20s cubic-bezier(.16,1,.3,1);
}
@keyframes act2-core-pulse {
  0%   { transform: scale(1);    opacity: 0.85; }
  25%  { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(1);    opacity: 0.85; }
}

/* ENERGY BULLETS · the visible "impulse" that travels through
   each connection line during Act II. Each <line.craft__energy>
   sits invisible at rest (stroke transparent) and on entry is
   given a stroke-dasharray of "30 1000" — a 30px bright
   segment followed by a 1000px gap. Animating stroke-dashoffset
   from the line's length down to a small negative number slides
   that segment from the central core to the crystal's edge.

   The 6 line lengths are all ~210–215px (radii from the centre
   to each pillar), so a single offset value works for all of
   them — the small visual mismatch is imperceptible.

   The per-line delays form a "fanning out" wave: storytelling
   fires first (12 o'clock), then UX (ne), direction (se),
   theme (s), identity (sw), ambience (nw), in clockwise order
   so the visitor sees a single continuous sweep of light
   around the constellation. */
.craft__energy {
  stroke: rgba(255, 231, 160, 0);
  stroke-dasharray: 30 1000;
  stroke-dashoffset: 230;
  filter: drop-shadow(0 0 6px rgba(255, 231, 160, 0.9));
}
#knowledge[data-narrative-entered="true"] .craft__energy {
  animation: act2-energy-flow 1.45s cubic-bezier(.4, 0, .25, 1) both;
}
#knowledge[data-narrative-entered="true"] .craft__energy[data-key="story"]     { animation-delay: 0.30s; }
#knowledge[data-narrative-entered="true"] .craft__energy[data-key="ux"]        { animation-delay: 0.42s; }
#knowledge[data-narrative-entered="true"] .craft__energy[data-key="direction"] { animation-delay: 0.54s; }
#knowledge[data-narrative-entered="true"] .craft__energy[data-key="theme"]     { animation-delay: 0.66s; }
#knowledge[data-narrative-entered="true"] .craft__energy[data-key="identity"]  { animation-delay: 0.78s; }
#knowledge[data-narrative-entered="true"] .craft__energy[data-key="ambience"]  { animation-delay: 0.90s; }
@keyframes act2-energy-flow {
  0% {
    stroke: rgba(255, 231, 160, 0);
    stroke-dashoffset: 230;
  }
  12% {
    stroke: rgba(255, 231, 160, 1);
    filter: drop-shadow(0 0 14px rgba(255, 231, 160, 1));
  }
  88% {
    stroke: rgba(255, 231, 160, 1);
    filter: drop-shadow(0 0 14px rgba(255, 231, 160, 1));
  }
  100% {
    stroke: rgba(255, 231, 160, 0);
    stroke-dashoffset: -10;
    filter: drop-shadow(0 0 6px rgba(255, 231, 160, 0));
  }
}


/* ─────────────────────────────────────────────────────────────
   ATO III · CRISTAIS DE MEMÓRIA  — entry on #memories
   ─────────────────────────────────────────────────────────────
   Gravitational waves emanate from the header. The rings are
   crystalline (not radar): three concentric pulses, each with
   a subtly different rotation and a hex-edge inner stroke, so
   they read as arcane energy rather than sonar.
   Plus a slow refraction shimmer over the whole section.
   Sensation: "each crystal guards a memory or creation."
   ───────────────────────────────────────────────────────────── */

/* Phantom-border fix (June 2026): overflow:hidden on the section
   clipped the Big Bang flash and bordered wave rings, revealing the
   section box as a semi-transparent rectangle. Keep overflow visible
   and never paint borders on the section shell itself. */
#memories {
  position: relative;
  overflow: visible;
  border: none;
  outline: none;
  box-shadow: none;
  background: transparent;
}

/* The wave layer: two pseudo rings on .memories__head — borderless
   (only glow) so scaling rings never read as a UI frame. */
.memories__head { position: relative; }
.memories__head::before,
.memories__head::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 60%;
  width: 80px;
  height: 80px;
  border: none;
  border-radius: 50%;
  background: transparent;
  pointer-events: none;
  opacity: 0;
  /* Crystalline ring via box-shadow only — no stroke = no rectangle */
  box-shadow:
    0 0 0 1px rgba(244, 221, 192, 0.42),
    inset 0 0 18px rgba(155, 124, 214, 0.28),
    0 0 28px rgba(255, 231, 160, 0.22);
  transform: translate(-50%, -50%) scale(0.3);
  z-index: 0;
}
#memories[data-narrative-entered="true"] .memories__head::before {
  animation: act3-wave 4s 0.10s cubic-bezier(.22,.61,.36,1) forwards;
}
#memories[data-narrative-entered="true"] .memories__head::after {
  animation: act3-wave 4s 0.85s cubic-bezier(.22,.61,.36,1) forwards;
}
@keyframes act3-wave {
  0%   {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.3) rotate(0deg);
  }
  15%  { opacity: 0.9; }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(11) rotate(28deg);
  }
}

/* ─────────────────────────────────────────────────────────────
   MULTI-WAVE LAYER · a train of concentric pulses (more organic
   than the two header pseudos alone). Five borderless rings ripple
   outward on staggered delays with slightly varied scale, hue and
   rotation, so the emanation reads as a continuous gravitational
   swell rather than two discrete blips. Pointer-inert and clipped
   to nothing visual when the section hasn't been entered yet. */
.memories__waves {
  position: absolute;
  left: 50%;
  top: 60%;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 0;
}
.memories__wave {
  position: absolute;
  left: 0;
  top: 0;
  width: 90px;
  height: 90px;
  margin-left: -45px;
  margin-top: -45px;
  border-radius: 50%;
  opacity: 0;
  transform: scale(0.25);
  box-shadow:
    0 0 0 1px rgba(244, 221, 192, 0.34),
    inset 0 0 16px rgba(155, 124, 214, 0.22),
    0 0 24px rgba(255, 231, 160, 0.18);
}
/* Each ring: staggered start, varied terminal scale + spin so no two
   pulses travel in lockstep — the organic part. */
#memories[data-narrative-entered="true"] .memories__wave:nth-child(1) {
  animation: act3-wave-pulse 4.2s 0.15s cubic-bezier(.22,.61,.36,1) forwards;
  --wave-scale: 10;  --wave-rot: 22deg;
}
#memories[data-narrative-entered="true"] .memories__wave:nth-child(2) {
  animation: act3-wave-pulse 4.4s 0.70s cubic-bezier(.22,.61,.36,1) forwards;
  --wave-scale: 12; --wave-rot: -18deg;
}
#memories[data-narrative-entered="true"] .memories__wave:nth-child(3) {
  animation: act3-wave-pulse 4.6s 1.30s cubic-bezier(.22,.61,.36,1) forwards;
  --wave-scale: 9;  --wave-rot: 30deg;
}
#memories[data-narrative-entered="true"] .memories__wave:nth-child(4) {
  animation: act3-wave-pulse 4.8s 1.95s cubic-bezier(.22,.61,.36,1) forwards;
  --wave-scale: 13; --wave-rot: -26deg;
}
#memories[data-narrative-entered="true"] .memories__wave:nth-child(5) {
  animation: act3-wave-pulse 5.0s 2.65s cubic-bezier(.22,.61,.36,1) forwards;
  --wave-scale: 11; --wave-rot: 14deg;
}
@keyframes act3-wave-pulse {
  0%   { opacity: 0;    transform: scale(0.25) rotate(0deg); }
  14%  { opacity: 0.8; }
  100% { opacity: 0;    transform: scale(var(--wave-scale, 11)) rotate(var(--wave-rot, 24deg)); }
}

/* Section ::before stays disabled (.memories::before display:none) —
   deep wave removed here to avoid painting on the section box. */

/* Header text drifts up subtly as the wave passes through it. */
#memories[data-narrative-entered="true"] .memories__title,
#memories[data-narrative-entered="true"] .memories__eyebrow,
#memories[data-narrative-entered="true"] .memories__lede {
  animation: act3-head-rise 1.6s 0.10s cubic-bezier(.16,1,.3,1) both;
}

/* ─────────────────────────────────────────────────────────────
   BIG BANG FLASH · the visible counterpart of the JS singularity
   ─────────────────────────────────────────────────────────────
   Driven by .memories--big-bang, a class added/removed by
   src/js/crystals.js around the singularity sequence. The flash
   timeline:
     0 → 34%   invisible (implosion phase, crystals collapsing)
     34 → 42%  brief intense bloom (the Big Bang itself)
     42 → 100% expanding shockwave fading to nothing
   Total runtime matches the JS singularity (3.2s) so the class
   removal coincides with the visual fade-out.
   ───────────────────────────────────────────────────────────── */
.memories--big-bang::after {
  content: "";
  /* Fixed to the viewport centre so the flash is never clipped by
     the #memories section rectangle (phantom-border fix). */
  position: fixed;
  left: 50%;
  top: 50%;
  width: 220px;
  height: 220px;
  border: none;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0);
  opacity: 0;
  background: radial-gradient(circle,
    rgba(255, 245, 210, 0.85) 0%,
    rgba(255, 231, 160, 0.55) 22%,
    rgba(155, 124, 214, 0.30) 50%,
    transparent 78%);
  z-index: 8;
  mix-blend-mode: screen;
  animation: act3-bigbang-flash 3.2s cubic-bezier(.22, 1, .36, 1) forwards;
}
@keyframes act3-bigbang-flash {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0);
    filter: blur(0);
  }
  34% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.04);
    filter: blur(0);
  }
  /* PEAK · the singularity ignites */
  42% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(0.55);
    filter: blur(2px) brightness(1.4);
  }
  /* SHOCKWAVE · energy fans outward */
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(6.5);
    filter: blur(8px) brightness(0.6);
  }
}

/* SECONDARY HALO · a sharper ring (no fill) that races outward
   slightly ahead of the main glow. Reads as the actual shockwave
   front of the explosion. */
.memories--big-bang .memories__head::after {
  /* Override the soft crystalline wave during the Big Bang for
     a brighter, sharper shock-front. Borderless — glow ring only. */
  animation: act3-bigbang-shock 3.2s cubic-bezier(.22, 1, .36, 1) forwards;
  border: none;
  box-shadow:
    0 0 0 2px rgba(255, 245, 210, 0.75),
    inset 0 0 28px rgba(255, 231, 160, 0.55),
    0 0 64px rgba(255, 231, 160, 0.65);
}
@keyframes act3-bigbang-shock {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.05);
  }
  34% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.1);
  }
  42% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(0.4);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(18) rotate(8deg);
  }
}
#memories[data-narrative-entered="true"] .memories__eyebrow { animation-delay: 0.05s; }
#memories[data-narrative-entered="true"] .memories__title   { animation-delay: 0.25s; }
#memories[data-narrative-entered="true"] .memories__lede    { animation-delay: 0.55s; }
@keyframes act3-head-rise {
  0%   { opacity: 0; transform: translateY(14px); filter: blur(2px); }
  100% { opacity: 1; transform: translateY(0);    filter: blur(0); }
}


/* ─────────────────────────────────────────────────────────────
   ATO IV · O CODEX DOS OFÍCIOS  — entry on #contracts
   ─────────────────────────────────────────────────────────────
   The codex opens: contracts unfurl page by page with a 3D
   rotateY perspective. Corners glow briefly to suggest gold
   leaf catching the light. Section runes (the crown svg) ink
   in slightly afterwards.
   Sensation: "I am consulting a tome of knowledge."
   ───────────────────────────────────────────────────────────── */

#contracts { perspective: 1400px; }

/* Each contract book reveals with a subtle book-opening
   rotation around its left spine. Stagger lives on the
   nth-child to avoid touching any inline style. */
#contracts[data-narrative-entered="true"] .contract {
  animation: act4-book-open 1.6s cubic-bezier(.16,1,.3,1) both;
  transform-origin: left center;
}
#contracts[data-narrative-entered="true"] .contract:nth-child(1) { animation-delay: 0.10s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(2) { animation-delay: 0.30s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(3) { animation-delay: 0.50s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(4) { animation-delay: 0.70s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(5) { animation-delay: 0.90s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(6) { animation-delay: 1.10s; }
@keyframes act4-book-open {
  0% {
    opacity: 0;
    transform: rotateY(-22deg) translateY(12px);
    filter: brightness(0.85) blur(2px);
  }
  60% {
    opacity: 1;
    filter: brightness(1.05) blur(0);
  }
  100% {
    opacity: 1;
    transform: rotateY(0) translateY(0);
    filter: brightness(1) blur(0);
  }
}

/* Page-corner glow — the four gold corners flash gently as
   each contract opens. We override only the brightness via a
   one-shot key on the corners; their position/shape come from
   the existing rules. */
#contracts[data-narrative-entered="true"] .contract__corner {
  animation: act4-corner-shine 2.2s 0.40s ease-out both;
}
@keyframes act4-corner-shine {
  0%   { filter: brightness(1)   drop-shadow(0 0 0 transparent); }
  35%  { filter: brightness(1.6) drop-shadow(0 0 8px rgba(255, 231, 160, 0.85)); }
  100% { filter: brightness(1)   drop-shadow(0 0 0 transparent); }
}

/* AUTOMATIC WRITING · the contract names reveal as if being
   inked by an invisible quill, left-to-right. We use a
   horizontal clip-path sweep so the existing typography (Cinzel
   weight, gradient fills, ligatures) is preserved unchanged —
   only the visible portion is animated. A subtle blur trails
   behind the writing tip, mimicking still-wet ink. */
#contracts[data-narrative-entered="true"] .contract__name {
  animation: act4-handwrite 1.2s cubic-bezier(.22,1,.36,1) both;
}
/* Each contract's name fires shortly after its book opens.
   The base offset (0.40s) puts the writing AFTER the book
   completes its 1.6s rotation — and the +0.20s per-contract
   stagger continues the quill from one page to the next. */
#contracts[data-narrative-entered="true"] .contract:nth-child(1) .contract__name { animation-delay: 0.50s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(2) .contract__name { animation-delay: 0.70s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(3) .contract__name { animation-delay: 0.90s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(4) .contract__name { animation-delay: 1.10s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(5) .contract__name { animation-delay: 1.30s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(6) .contract__name { animation-delay: 1.50s; }
@keyframes act4-handwrite {
  0% {
    clip-path: inset(0 100% 0 0);
    filter: blur(1.6px);
    text-shadow: 0 0 12px rgba(255, 231, 160, 0.55);
  }
  85% {
    text-shadow: 0 0 8px rgba(255, 231, 160, 0.35);
  }
  100% {
    clip-path: inset(0 0 0 0);
    filter: blur(0);
    text-shadow: 0 0 0 transparent;
  }
}

/* The horizontal hairline divider beneath each contract name
   draws itself in from the left immediately after the name
   finishes inking. Reinforces the "quill keeps writing" feel. */
#contracts[data-narrative-entered="true"] .contract__divider {
  animation: act4-divider-draw 0.9s cubic-bezier(.22,1,.36,1) both;
}
#contracts[data-narrative-entered="true"] .contract:nth-child(1) .contract__divider { animation-delay: 1.30s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(2) .contract__divider { animation-delay: 1.50s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(3) .contract__divider { animation-delay: 1.70s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(4) .contract__divider { animation-delay: 1.90s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(5) .contract__divider { animation-delay: 2.10s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(6) .contract__divider { animation-delay: 2.30s; }
@keyframes act4-divider-draw {
  0%   { clip-path: inset(0 100% 0 0); opacity: 0; }
  60%  { opacity: 1; }
  100% { clip-path: inset(0 0 0 0);    opacity: 1; }
}

/* The contract__gem (rarity icon) flashes briefly when the page
   opens — a small rune surfacing on the page corner. */
#contracts[data-narrative-entered="true"] .contract__gem {
  animation: act4-rune-surface 1.4s cubic-bezier(.22,1,.36,1) both;
}
#contracts[data-narrative-entered="true"] .contract:nth-child(1) .contract__gem { animation-delay: 0.35s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(2) .contract__gem { animation-delay: 0.55s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(3) .contract__gem { animation-delay: 0.75s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(4) .contract__gem { animation-delay: 0.95s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(5) .contract__gem { animation-delay: 1.15s; }
#contracts[data-narrative-entered="true"] .contract:nth-child(6) .contract__gem { animation-delay: 1.35s; }
@keyframes act4-rune-surface {
  0%   { opacity: 0; transform: scale(0.6) rotate(-25deg); filter: drop-shadow(0 0 0 transparent); }
  50%  { opacity: 1; transform: scale(1.18) rotate(2deg);  filter: drop-shadow(0 0 10px rgba(255, 231, 160, 0.9)); }
  100% { opacity: 1; transform: scale(1) rotate(0);        filter: drop-shadow(0 0 0 transparent); }
}

/* Header & crown ink-in earlier than the books so the codex
   "opens to its frontispiece" first, then the contents reveal. */
#contracts[data-narrative-entered="true"] .contracts__eyebrow,
#contracts[data-narrative-entered="true"] .contracts__title,
#contracts[data-narrative-entered="true"] .contracts__subtitle,
#contracts[data-narrative-entered="true"] .contracts__crown {
  animation: act4-ink-in 1.4s cubic-bezier(.16,1,.3,1) both;
}
#contracts[data-narrative-entered="true"] .contracts__eyebrow  { animation-delay: 0.00s; }
#contracts[data-narrative-entered="true"] .contracts__title    { animation-delay: 0.15s; }
#contracts[data-narrative-entered="true"] .contracts__subtitle { animation-delay: 0.30s; }
#contracts[data-narrative-entered="true"] .contracts__crown    { animation-delay: 0.40s; }
@keyframes act4-ink-in {
  0%   { opacity: 0; transform: translateY(8px); filter: blur(3px); }
  100% { opacity: 1; transform: translateY(0);   filter: blur(0); }
}


/* ─────────────────────────────────────────────────────────────
   ATO V · O PORTAL  — entry on #portal
   ─────────────────────────────────────────────────────────────
   The portal awakens: energy ripples from the canvas center,
   contact links converge from a slight outward offset, and a
   gold halo briefly washes the stage. The portal canvas keeps
   its own particle system — we only layer this entry burst on
   top, then fade out.
   Sensation: "every great journey begins with a conversation."
   ───────────────────────────────────────────────────────────── */

#portal { position: relative; }

/* Sleeping halo · always present at low intensity, slowly
   pulsing like a portal asleep but breathing. When the visitor
   enters Act V, it ignites with the burst keyframe below. */
#portal::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 60%;
  width: 280px;
  height: 280px;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.55);
  opacity: 0.18;
  background:
    radial-gradient(circle, rgba(255, 231, 160, 0.35) 0%,
                            rgba(155, 124, 214, 0.22) 40%,
                            transparent 70%);
  z-index: 0;
  animation: act5-portal-breathe 6s ease-in-out infinite;
}
@keyframes act5-portal-breathe {
  0%, 100% { opacity: 0.14; transform: translate(-50%, -50%) scale(0.5); }
  50%      { opacity: 0.28; transform: translate(-50%, -50%) scale(0.7); }
}
#portal[data-narrative-entered="true"]::before {
  /* The breathe pauses while the burst overrides it for the
     duration of the awakening. */
  animation: act5-portal-burst 4.2s 0.15s cubic-bezier(.16,1,.3,1) forwards;
}
@keyframes act5-portal-burst {
  0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0.25); }
  20%  { opacity: 0.85; }
  100% { opacity: 0.18; transform: translate(-50%, -50%) scale(2.0); }
}

/* SLOW ROTATION · the portal stage itself receives a permanent,
   barely-perceptible rotation — a galactic spin that lives
   beneath the existing canvas. The duration is intentionally
   long (110s) so the motion reads as ambient rather than
   active. The hover boost shortens it temporarily, giving the
   portal a "reacting to your presence" feel. */
.portal__stage {
  position: relative;
}
.portal__stage::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 420px;
  height: 420px;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%);
  /* A faint counter-rotating sheen layered OVER the canvas galaxy
     to add a second, slower depth plane. Kept low-opacity so the
     canvas remains the star of the portal. */
  background:
    conic-gradient(from 0deg,
      rgba(255, 231, 160, 0.0) 0deg,
      rgba(255, 231, 160, 0.12) 60deg,
      rgba(155, 124, 214, 0.1) 180deg,
      rgba(255, 231, 160, 0.12) 300deg,
      rgba(255, 231, 160, 0.0) 360deg);
  mix-blend-mode: screen;
  opacity: 0.32;
  animation: act5-portal-spin 140s linear infinite reverse;
  z-index: 1;
}
.portal__stage:hover::after {
  animation-duration: 30s;
  opacity: 0.6;
  transition: opacity 0.6s ease;
}
@keyframes act5-portal-spin {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}

/* The contact link rail converges inward — each link slides
   from a small outward offset with a slight delay, like the
   portal pulling its tributaries back to center. */
#portal[data-narrative-entered="true"] .portal__link {
  animation: act5-link-converge 1.4s cubic-bezier(.16,1,.3,1) both;
}
/* Each column slides in from its own side, cards cascading top-
   to-bottom — the Atlantic column drifts from the LEFT margin,
   the Iberian column from the RIGHT. Column heads (flags + title)
   ink in slightly earlier to set the regional context first. */
#portal[data-narrative-entered="true"] .portal__column[data-region="atlantic"] .portal__link {
  --act5-from-x: -22px;
}
#portal[data-narrative-entered="true"] .portal__column[data-region="iberian"] .portal__link {
  --act5-from-x: 22px;
}
#portal[data-narrative-entered="true"] .portal__column .portal__links li:nth-child(1) .portal__link { animation-delay: 0.32s; }
#portal[data-narrative-entered="true"] .portal__column .portal__links li:nth-child(2) .portal__link { animation-delay: 0.48s; }
#portal[data-narrative-entered="true"] .portal__column .portal__links li:nth-child(3) .portal__link { animation-delay: 0.64s; }

/* Column heads fade up first, gently establishing the regional
   framing before the channel buttons converge inward. */
#portal[data-narrative-entered="true"] .portal__column-head {
  animation: act5-column-head-rise 1s cubic-bezier(.16,1,.3,1) both;
}
#portal[data-narrative-entered="true"] .portal__column[data-region="atlantic"] .portal__column-head { animation-delay: 0.10s; }
#portal[data-narrative-entered="true"] .portal__column[data-region="iberian"]  .portal__column-head { animation-delay: 0.20s; }
@keyframes act5-column-head-rise {
  0%   { opacity: 0; translate: 0 10px; filter: blur(2px); }
  100% { opacity: 1; translate: 0 0;    filter: blur(0);   }
}
/* IMPORTANT · uses individual `translate` / `scale` CSS properties
   (NOT the `transform` shorthand) so the hover rule's
   `transform: scale(1.06)` is free to compound with it without
   being clobbered by CSS Animations' fill-mode forwards. */
@keyframes act5-link-converge {
  0% {
    opacity: 0;
    translate: var(--act5-from-x, 0) 14px;
    scale: 0.96;
    filter: blur(2px);
  }
  100% {
    opacity: 1;
    translate: 0 0;
    scale: 1;
    filter: blur(0);
  }
}

/* Header ink — short, ahead of the burst, so the eye lands
   on the invitation first. */
#portal[data-narrative-entered="true"] .section-head__title,
#portal[data-narrative-entered="true"] .section-head__lede {
  animation: act5-head-glow 1.4s cubic-bezier(.16,1,.3,1) both;
}
#portal[data-narrative-entered="true"] .section-head__title { animation-delay: 0.05s; }
#portal[data-narrative-entered="true"] .section-head__lede  { animation-delay: 0.22s; }
@keyframes act5-head-glow {
  0% {
    opacity: 0;
    transform: translateY(8px);
    text-shadow: 0 0 0 transparent;
  }
  50% {
    text-shadow: 0 0 22px rgba(255, 231, 160, 0.55);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
    text-shadow: 0 0 12px rgba(255, 231, 160, 0.18);
  }
}


/* ── REDUCED MOTION ──────────────────────────────────────────
   Disable every per-act keyframe but leave the destination
   styles in place by setting `animation: none`. Because each
   animation uses `forwards`/`both`, the elements still render
   at their final state without any motion. */
@media (prefers-reduced-motion: reduce) {
  #narrative-particles { display: none; }
  #hero[data-narrative-entered="true"] .hero__rune-fire,
  #hero[data-narrative-entered="true"] .hero__letter,
  #hero[data-narrative-entered="true"] .hero__eyebrow,
  #hero[data-narrative-entered="true"] .hero__tagline,
  #hero[data-narrative-entered="true"] .hero__lede,
  #knowledge[data-narrative-entered="true"] .craft__node-aura,
  #knowledge[data-narrative-entered="true"] .craft__node-crystal,
  #knowledge[data-narrative-entered="true"] .craft__line,
  #knowledge[data-narrative-entered="true"] .craft__energy,
  #knowledge[data-narrative-entered="true"] .craft__core-ring,
  #memories[data-narrative-entered="true"] .memories__head::before,
  #memories[data-narrative-entered="true"] .memories__head::after,
  #memories[data-narrative-entered="true"] .memories__wave,
  .memories--big-bang::after,
  .memories--big-bang .memories__head::after,
  #memories[data-narrative-entered="true"] .memories__title,
  #memories[data-narrative-entered="true"] .memories__eyebrow,
  #memories[data-narrative-entered="true"] .memories__lede,
  #contracts[data-narrative-entered="true"] .contract,
  #contracts[data-narrative-entered="true"] .contract__corner,
  #contracts[data-narrative-entered="true"] .contract__name,
  #contracts[data-narrative-entered="true"] .contract__divider,
  #contracts[data-narrative-entered="true"] .contract__gem,
  #contracts[data-narrative-entered="true"] .contracts__eyebrow,
  #contracts[data-narrative-entered="true"] .contracts__title,
  #contracts[data-narrative-entered="true"] .contracts__subtitle,
  #contracts[data-narrative-entered="true"] .contracts__crown,
  #portal::before,
  .portal__stage::after,
  #portal[data-narrative-entered="true"] .portal__link,
  #portal[data-narrative-entered="true"] .section-head__title,
  #portal[data-narrative-entered="true"] .section-head__lede {
    animation: none !important;
  }
  /* Reveal letters statically so the name isn't permanently hidden
     for reduced-motion visitors. The lava gradient on welcome chars
     stays visible as a STATIC volcanic pattern (no animated flow). */
  .hero__letter,
  .welcome__char {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  /* Stop the infinite lava drift but keep the gradient at a fixed
     "centred" position so the chars still read as magma at rest. */
  .welcome__char {
    animation: none !important;
    background-position: 50% 50% !important;
  }
}

/* ============================================================
   KNOWLEDGE TREE OVERLAY · "Árvore do Conhecimento"
   ------------------------------------------------------------
   A fullscreen mystical artifact rendered on <canvas> by
   knowledgetree.js. The overlay itself only owns the chrome:
   the blurred/darkened backdrop, the title, the hint, the relic
   close button and the floating hover label. Everything tree-
   shaped (roots, trunk, branches, leaves, crystals, particles)
   lives in the canvas.
   ============================================================ */
.ktree {
  position: fixed;
  inset: 0;
  z-index: 4500;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-out);
}
.ktree.is-open {
  opacity: 1;
  pointer-events: auto;
  touch-action: none;
  overscroll-behavior: none;
}

/* Backdrop — blurs + darkens the living page behind. The
   background canvases are paused while open so the blur stays
   perfectly stable (no compositor shimmer). */
.ktree__backdrop {
  position: absolute;
  inset: 0;
  /* The body-wide wallpaper (.tree-wall) is hidden while the tree is
     open, so a live backdrop-filter blur would only re-blur a static
     dark page — yet it was being re-rasterised EVERY animated frame
     (~63 ms/frame of compositor cost, proven by runtime logs). We
     instead paint a near-opaque dark atmosphere here (visually
     identical) and drop backdrop-filter entirely, so the per-frame
     compositor cost collapses to near zero. */
  /* RPG-library ambience photo sits at the very back of the stack;
     the dark radial gradients above it keep the explorable tree (its
     branches + crystals) the clear focus and preserve label legibility. */
  background:
    radial-gradient(ellipse 90% 70% at 32% 88%, rgba(28, 64, 58, 0.38) 0%, transparent 60%),
    radial-gradient(ellipse 80% 60% at 50% 32%, rgba(40, 86, 120, 0.2) 0%, transparent 72%),
    radial-gradient(ellipse at center, rgba(4, 10, 12, 0.6) 0%, rgba(1, 3, 4, 0.86) 86%),
    url("../assets/oracle/library-bg.png") center center / cover no-repeat;
  background-color: #050a0c;
  filter: saturate(0.82) brightness(0.82);
  cursor: default;
}
@media (max-width: 767px) {
  .ktree__backdrop {
    /* Mobile: a touch darker so the canvas tree stays dominant and crisp. */
    background:
      radial-gradient(ellipse at center, rgba(4, 10, 12, 0.68) 0%, rgba(1, 3, 4, 0.9) 86%),
      url("../assets/oracle/library-bg.png") center center / cover no-repeat;
    background-color: #050a0c;
    filter: saturate(0.76) brightness(0.74);
  }
}

body.ktree-open {
  overflow: hidden;
  /* Prevent the page underneath from rubber-banding while panning
     the Knowledge Tree — the "blanket being pulled up" effect. */
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Suspend the body-wide skill-tree + crystal wallpaper while the
   Knowledge Tree is open — keeps backdrop-filter stable and frees
   GPU/CPU for the explorable tree canvas. Restored on close. */
body.ktree-open .tree-wall {
  visibility: hidden;
  pointer-events: none;
}

/* (backdrop-filter removed entirely — see .ktree__backdrop note) */

.ktree__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  display: block;
  /* Isolate the animating canvas on its own compositor layer so
     per-frame repaints do not cascade into the rest of the page. */
  will-change: transform;
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* ── Title block (top-centre) ─────────────────────────────── */
.ktree__head {
  position: absolute;
  top: clamp(1.1rem, 3.4vh, 2.6rem);
  left: 50%;
  transform: translateX(-50%) translateY(-12px);
  z-index: 3;
  width: min(92vw, 760px);
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.7s var(--ease-out) 0.35s,
              transform 0.7s var(--ease-out) 0.35s;
}
.ktree.is-open .ktree__head {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.ktree__sigil {
  display: block;
  font-size: 0.9rem;
  color: var(--gold-burning, #F2C879);
  opacity: 0.85;
  margin-bottom: 0.3rem;
  text-shadow: 0 0 14px rgba(242, 200, 121, 0.5);
}
.ktree__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.45rem, 3.4vw, 2.5rem);
  letter-spacing: 0.06em;
  line-height: 1.05;
  color: #F4E4BE;
  text-shadow:
    0 0 22px rgba(242, 200, 121, 0.3),
    0 2px 10px rgba(0, 0, 0, 0.7);
}
.ktree__subtitle {
  margin: 0.55rem auto 0;
  max-width: 46ch;
  font-family: var(--font-body);
  font-size: clamp(0.72rem, 1.4vw, 0.88rem);
  letter-spacing: 0.02em;
  line-height: 1.5;
  color: rgba(214, 224, 222, 0.72);
}

/* ── Hint (bottom-centre) ─────────────────────────────────── */
.ktree__hint {
  position: absolute;
  bottom: clamp(1rem, 3vh, 2rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  margin: 0;
  padding: 0 1rem;
  width: max-content;
  max-width: 90vw;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(201, 184, 150, 0.6);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s var(--ease-out) 1.4s;
}
.ktree.is-open .ktree__hint { opacity: 1; }
.ktree.is-open .ktree__hint.is-dismissed { opacity: 0; transition: opacity 0.5s var(--ease-out); }

/* ── Relic close button (top-right) ───────────────────────── */
.ktree__close {
  position: absolute;
  top: clamp(1rem, 3vh, 1.8rem);
  right: clamp(1rem, 3vw, 2rem);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 1.05rem 0.6rem 0.9rem;
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: #F3E3BC;
  background:
    radial-gradient(ellipse 80% 120% at 18% 20%, rgba(64, 46, 22, 0.65), transparent 70%),
    linear-gradient(180deg, rgba(26, 22, 14, 0.86) 0%, rgba(12, 10, 7, 0.9) 100%);
  border: 1px solid rgba(194, 164, 107, 0.42);
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.08),
    inset 0 1px 0 rgba(242, 200, 121, 0.14),
    0 10px 26px rgba(0, 0, 0, 0.5),
    0 0 22px rgba(242, 200, 121, 0.12);
  opacity: 0;
  transform: translateY(-10px);
  transition: opacity 0.6s var(--ease-out) 0.5s,
              transform 0.6s var(--ease-out) 0.5s,
              border-color 0.3s var(--ease-out),
              box-shadow 0.3s var(--ease-out);
}
.ktree.is-open .ktree__close {
  opacity: 1;
  transform: translateY(0);
}
.ktree__close:hover,
.ktree__close:focus-visible {
  border-color: rgba(242, 200, 121, 0.75);
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.14),
    inset 0 1px 0 rgba(242, 200, 121, 0.2),
    0 12px 30px rgba(0, 0, 0, 0.55),
    0 0 30px rgba(242, 200, 121, 0.28);
  outline: none;
}
.ktree__close-sigil {
  font-size: 0.9rem;
  color: var(--gold-burning, #F2C879);
  text-shadow: 0 0 12px rgba(242, 200, 121, 0.6);
  transition: transform 0.5s var(--ease-out);
}
.ktree__close:hover .ktree__close-sigil {
  transform: rotate(180deg) scale(1.12);
}

/* ── Floating hover tooltip (crystal name + short desc) ────── */
.ktree__tip {
  position: fixed;
  z-index: 7;
  left: 0;
  top: 0;
  max-width: 230px;
  padding: 0.5rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.16rem;
  border-radius: 10px;
  pointer-events: none;
  background:
    radial-gradient(ellipse 90% 120% at 14% 0%, color-mix(in srgb, var(--ktree-accent, #C2A46B) 16%, transparent), transparent 70%),
    linear-gradient(180deg, rgba(20, 26, 24, 0.94) 0%, rgba(9, 13, 12, 0.96) 100%);
  border: 1px solid color-mix(in srgb, var(--ktree-accent, #C2A46B) 50%, rgba(194, 164, 107, 0.4));
  box-shadow:
    0 10px 26px rgba(0, 0, 0, 0.55),
    0 0 22px color-mix(in srgb, var(--ktree-accent, #C2A46B) 22%, transparent);
  opacity: 0;
  transform: translate(-50%, calc(-100% - 8px)) scale(0.94);
  transition: opacity 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}
.ktree__tip.is-visible {
  opacity: 1;
  transform: translate(-50%, calc(-100% - 8px)) scale(1);
}
.ktree__tip-kicker {
  font-family: var(--font-mono);
  font-size: 0.52rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ktree-accent, #C2A46B);
}
.ktree__tip-name {
  font-family: var(--font-display);
  font-size: 0.96rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: #F4E8CE;
}
.ktree__tip-desc {
  font-family: var(--font-body);
  font-size: 0.72rem;
  line-height: 1.4;
  color: rgba(214, 224, 222, 0.78);
}

/* ── Contextual relic panel (opens on crystal click) ───────── */
.ktree__panel {
  position: absolute;
  z-index: 8;
  top: 50%;
  right: clamp(1rem, 3vw, 2.4rem);
  width: min(92vw, 340px);
  max-height: 78vh;
  overflow-y: auto;
  padding: 1.5rem 1.4rem 1.4rem;
  border-radius: 16px;
  transform: translateY(-50%) translateX(28px);
  opacity: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 120% 80% at 100% 0%, color-mix(in srgb, var(--ktree-accent, #C2A46B) 14%, transparent), transparent 60%),
    linear-gradient(180deg, rgba(20, 24, 22, 0.95) 0%, rgba(9, 12, 11, 0.97) 100%);
  border: 1px solid color-mix(in srgb, var(--ktree-accent, #C2A46B) 45%, rgba(194, 164, 107, 0.35));
  box-shadow:
    inset 0 1px 0 rgba(242, 200, 121, 0.1),
    0 26px 60px rgba(0, 0, 0, 0.6),
    0 0 40px color-mix(in srgb, var(--ktree-accent, #C2A46B) 18%, transparent);
  transition: opacity 0.45s var(--ease-out), transform 0.45s var(--ease-out);
}
.ktree__panel.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(-50%) translateX(0);
}
.ktree__panel-close {
  position: absolute;
  top: 0.7rem;
  right: 0.7rem;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  cursor: pointer;
  color: var(--ktree-accent, #C2A46B);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid color-mix(in srgb, var(--ktree-accent, #C2A46B) 40%, transparent);
  transition: background 0.25s var(--ease-out), transform 0.25s var(--ease-out);
}
.ktree__panel-close:hover { background: rgba(255, 255, 255, 0.1); transform: rotate(90deg); }
.ktree__panel-sigil {
  display: block;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  transform: rotate(45deg);
  margin-bottom: 0.8rem;
  box-shadow: 0 0 18px color-mix(in srgb, var(--ktree-accent, #C2A46B) 60%, transparent);
}
.ktree__panel-kicker {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.56rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ktree-accent, #C2A46B);
  margin-bottom: 0.3rem;
}
.ktree__panel-title {
  margin: 0 0 0.4rem;
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.1;
  color: #F4E8CE;
}
.ktree__panel-years {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 0.9rem;
  padding: 0.18rem 0.6rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--ktree-accent, #C2A46B) 45%, transparent);
  background: color-mix(in srgb, var(--ktree-accent, #C2A46B) 12%, transparent);
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ktree-accent, #C2A46B) 70%, #F4E8CE);
}
.ktree__panel-years::before { content: "✦"; font-size: 0.6rem; opacity: 0.8; }
.ktree__panel-years:empty { display: none; }
.ktree__panel-desc {
  margin: 0 0 1.1rem;
  font-family: var(--font-body);
  font-size: 0.86rem;
  line-height: 1.55;
  color: rgba(220, 228, 226, 0.85);
}
.ktree__panel-section { margin-bottom: 0.95rem; }
.ktree__panel-section:last-child { margin-bottom: 0; }
.ktree__panel-label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.54rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(201, 184, 150, 0.6);
  margin-bottom: 0.4rem;
}
.ktree__panel-exp {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.8rem;
  line-height: 1.5;
  color: rgba(214, 224, 222, 0.82);
}
.ktree__panel-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.32rem;
}
.ktree__panel-list li {
  position: relative;
  padding-left: 1rem;
  font-family: var(--font-body);
  font-size: 0.8rem;
  line-height: 1.4;
  color: rgba(214, 224, 222, 0.82);
}
.ktree__panel-list li::before {
  content: "✦";
  position: absolute;
  left: 0;
  top: 0.05em;
  font-size: 0.62rem;
  color: var(--ktree-accent, #C2A46B);
}
.ktree__panel-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.ktree__panel-tag {
  padding: 0.22rem 0.55rem;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  color: color-mix(in srgb, var(--ktree-accent, #C2A46B) 80%, #F4E8CE);
  background: color-mix(in srgb, var(--ktree-accent, #C2A46B) 12%, rgba(255, 255, 255, 0.03));
  border: 1px solid color-mix(in srgb, var(--ktree-accent, #C2A46B) 35%, transparent);
}

@media (max-width: 640px) {
  .ktree__close-label { display: none; }
  .ktree__close { padding: 0.6rem; gap: 0; }
  .ktree__subtitle { display: none; }
  .ktree__panel { top: auto; bottom: 0; right: 0; left: 0; width: 100%; max-height: 60vh;
    border-radius: 16px 16px 0 0; transform: translateY(40px); }
  .ktree__panel.is-open { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .ktree,
  .ktree__head,
  .ktree__close,
  .ktree__hint,
  .ktree__tip,
  .ktree__panel {
    transition-duration: 0.2s !important;
    transition-delay: 0s !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   PROFESSIONAL EVOLUTION LAYER · June 2026
   --------------------------------------------------------------------
   New conversion/clarity sections layered ON TOP of the existing arcane
   universe — never replacing it. Everything here reuses the site tokens
   (--gold, --primary, --font-display…) so the additions read as part of
   the same manuscript. Motion is GPU-friendly (transform/opacity only)
   and fully disabled under prefers-reduced-motion at the foot of this
   block.
   ════════════════════════════════════════════════════════════════════ */

/* Shared rhythm for the new full-width sections. */
.differentials,
.milestones,
.relatos,
.invoke {
  position: relative;
  z-index: 1;
  padding: clamp(3.5rem, 9vw, 7rem) clamp(1.25rem, 5vw, 3rem);
}
.differentials__head,
.relatos .section-head,
.milestones .section-head {
  margin-left: auto;
  margin-right: auto;
}

/* ── CONTRACTS · "Serviços Profissionais" professional kicker ─────────
   A plain-language line above the arcane title so a recruiter reads the
   intent instantly. Sits between the latin eyebrow and the codex name. */
.contracts__kicker {
  font-family: var(--font-display);
  font-size: clamp(0.92rem, 2.4vw, 1.15rem);
  font-weight: 600;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--gold-burning, #f2c879);
  margin: 0.1rem 0 0.45rem;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
html[data-theme="light"] .contracts__kicker {
  color: #8a5a1f;
  text-shadow: none;
}

/* ════════════════════════════════════════════════════════════════════
   #1b · DIFERENCIAIS — "Por que trabalhar comigo?" runestone pillars
   ════════════════════════════════════════════════════════════════════ */
.differentials__grid {
  list-style: none;
  margin: clamp(2rem, 4vw, 3rem) auto 0;
  padding: 0;
  max-width: 1180px;
  display: grid;
  gap: clamp(0.9rem, 1.8vw, 1.4rem);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
/* On wide screens, lay the 5 pillars as 3 + 2 with the trio on top,
   centred — avoids a lonely orphan card from auto-fit. */
@media (min-width: 980px) {
  .differentials__grid { grid-template-columns: repeat(6, 1fr); }
  .pillar:nth-child(1) { grid-column: 1 / 3; }
  .pillar:nth-child(2) { grid-column: 3 / 5; }
  .pillar:nth-child(3) { grid-column: 5 / 7; }
  .pillar:nth-child(4) { grid-column: 2 / 4; }
  .pillar:nth-child(5) { grid-column: 4 / 6; }
}

.pillar {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: clamp(1.3rem, 2.5vw, 1.8rem) clamp(1.2rem, 2.2vw, 1.6rem) clamp(1.4rem, 2.6vw, 1.9rem);
  border-radius: 14px;
  background:
    linear-gradient(158deg,
      rgba(26, 38, 28, 0.66) 0%,
      rgba(12, 20, 13, 0.62) 70%,
      rgba(9, 15, 10, 0.66) 100%);
  border: 1px solid rgba(201, 161, 95, 0.30);
  box-shadow:
    inset 0 1px 0 rgba(242, 200, 121, 0.10),
    inset 0 0 22px rgba(201, 161, 95, 0.04),
    0 14px 32px rgba(0, 0, 0, 0.34);
  -webkit-backdrop-filter: blur(7px) saturate(1.04);
  backdrop-filter: blur(7px) saturate(1.04);
  transition:
    transform 0.5s var(--ease-out),
    border-color 0.5s var(--ease-out),
    box-shadow 0.5s var(--ease-out);
}
/* Faint engraved corner ticks — "inscribed stone" feel. */
.pillar::before {
  content: "";
  position: absolute;
  inset: 7px;
  border-radius: 10px;
  border: 1px solid rgba(201, 161, 95, 0.14);
  pointer-events: none;
  z-index: -1;
}
/* Soft gold aura that wells up from behind on hover/focus. */
.pillar__aura {
  position: absolute;
  inset: -40% 10% auto;
  height: 80%;
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
    rgba(242, 200, 121, 0.26), rgba(201, 161, 95, 0) 70%);
  opacity: 0;
  transform: translateY(20px) scale(0.85);
  transition: opacity 0.55s var(--ease-out), transform 0.55s var(--ease-out);
  pointer-events: none;
  z-index: -1;
}
/* A single ember that drifts up across the stone when hovered. */
.pillar__spark {
  position: absolute;
  left: 50%;
  bottom: 18%;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffe9a8, rgba(242, 200, 121, 0) 70%);
  opacity: 0;
  pointer-events: none;
}
.pillar__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  color: var(--gold-aged, #c9a15f);
  background: radial-gradient(circle at 50% 38%,
    rgba(242, 200, 121, 0.14), rgba(201, 161, 95, 0.04) 70%);
  border: 1px solid rgba(201, 161, 95, 0.32);
  margin-bottom: 1rem;
  transition: color 0.5s var(--ease-out), transform 0.55s var(--ease-out),
    box-shadow 0.5s var(--ease-out);
}
.pillar__name {
  font-family: var(--font-display);
  font-size: clamp(1.02rem, 2.3vw, 1.18rem);
  font-weight: 600;
  line-height: 1.25;
  color: var(--primary);
  margin: 0 0 0.5rem;
  letter-spacing: 0.01em;
}
.pillar__desc {
  font-family: var(--font-body);
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--on-surface-variant);
  margin: 0;
  text-wrap: pretty;
}
.pillar:hover,
.pillar:focus-within {
  transform: translateY(-4px);
  border-color: rgba(242, 200, 121, 0.55);
  box-shadow:
    inset 0 1px 0 rgba(242, 200, 121, 0.18),
    inset 0 0 28px rgba(201, 161, 95, 0.08),
    0 20px 44px rgba(0, 0, 0, 0.42),
    0 0 26px rgba(242, 200, 121, 0.16);
}
.pillar:hover .pillar__aura,
.pillar:focus-within .pillar__aura {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.pillar:hover .pillar__glyph,
.pillar:focus-within .pillar__glyph {
  color: var(--gold-burning, #f2c879);
  transform: translateY(-2px) rotate(-4deg);
  box-shadow: 0 0 18px rgba(242, 200, 121, 0.30);
}
.pillar:hover .pillar__spark {
  animation: pillar-ember 1.5s var(--ease-out) infinite;
}
@keyframes pillar-ember {
  0%   { opacity: 0;   transform: translate(-50%, 0) scale(0.6); }
  18%  { opacity: 0.9; }
  100% { opacity: 0;   transform: translate(-50%, -120px) scale(1.1); }
}
html[data-theme="light"] .pillar {
  background: linear-gradient(158deg, rgba(244, 232, 205, 0.86), rgba(232, 216, 182, 0.8));
  border-color: rgba(120, 84, 40, 0.34);
  box-shadow: 0 14px 32px rgba(74, 45, 20, 0.14), inset 0 0 0 1px rgba(120, 84, 40, 0.05);
}
html[data-theme="light"] .pillar__name { color: #3a2410; }
html[data-theme="light"] .pillar__desc { color: #4f3c25; }
html[data-theme="light"] .pillar__glyph { color: #8a5a1f; border-color: rgba(120, 84, 40, 0.4); }

/* ════════════════════════════════════════════════════════════════════
   #1c · CONQUISTAS E MARCOS — animated count-up stats
   ════════════════════════════════════════════════════════════════════ */
.milestones__grid {
  list-style: none;
  margin: clamp(2rem, 4vw, 3rem) auto 0;
  padding: 0;
  max-width: 920px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(0.8rem, 2vw, 1.6rem);
}
.stat {
  position: relative;
  text-align: center;
  padding: clamp(1.1rem, 2.4vw, 1.7rem) 0.6rem;
}
/* Hairline dividers between stats (not after the last). */
.stat:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 22%;
  right: 0;
  width: 1px;
  height: 56%;
  background: linear-gradient(180deg, transparent, rgba(201, 161, 95, 0.32), transparent);
}
.stat__rune {
  display: block;
  font-size: 0.9rem;
  color: var(--gold-aged, #c9a15f);
  opacity: 0.7;
  margin-bottom: 0.35rem;
}
.stat__num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 4.6vw, 2.7rem);
  font-weight: 600;
  line-height: 1;
  color: var(--gold-burning, #f2c879);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 18px rgba(242, 200, 121, 0.18);
  letter-spacing: -0.01em;
}
.stat__label {
  display: block;
  margin-top: 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-surface-variant);
}
html[data-theme="light"] .stat__num { color: #9f6a1f; text-shadow: none; }
html[data-theme="light"] .stat__rune { color: #8a5a1f; }
@media (max-width: 640px) {
  .milestones__grid { grid-template-columns: repeat(2, 1fr); gap: 0.4rem 1rem; }
  .stat:nth-child(2)::after { display: none; }   /* no divider mid-row */
}

/* ════════════════════════════════════════════════════════════════════
   #1d · RELATOS DO REINO — parchment testimonials slider
   ════════════════════════════════════════════════════════════════════ */
.relatos__stage {
  position: relative;
  max-width: 600px;
  margin: clamp(1.8rem, 3.5vw, 2.6rem) auto 0;
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
.relatos__track {
  position: relative;
  flex: 1;
  min-height: 248px;
}
/* A leaf from the Royal Archive — aged parchment with a faint laid-paper
   texture, a slim gilt frame and elven corner filigree. */
.relato {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.9rem;
  padding: clamp(1.6rem, 3.2vw, 2.2rem) clamp(1.6rem, 3.2vw, 2.4rem);
  border-radius: 3px;
  background:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.018) 0 2px, transparent 2px 4px),
    linear-gradient(160deg, rgba(38, 32, 23, 0.86), rgba(22, 18, 12, 0.8));
  box-shadow:
    inset 0 0 0 1px rgba(201, 161, 95, 0.22),
    inset 0 0 0 5px rgba(201, 161, 95, 0.07),
    inset 0 0 50px rgba(201, 161, 95, 0.05),
    0 14px 34px rgba(0, 0, 0, 0.42);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out), visibility 0s linear 0.6s;
  pointer-events: none;
}
.relato.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
}
/* Elven corner filigree — small gilt right-angles at each corner */
.relato__corner {
  position: absolute;
  width: 16px;
  height: 16px;
  border: 1px solid rgba(201, 161, 95, 0.55);
  pointer-events: none;
}
.relato__corner--tl { top: 9px;    left: 9px;    border-right: 0; border-bottom: 0; }
.relato__corner--tr { top: 9px;    right: 9px;   border-left: 0;  border-bottom: 0; }
.relato__corner--bl { bottom: 9px; left: 9px;    border-right: 0; border-top: 0; }
.relato__corner--br { bottom: 9px; right: 9px;   border-left: 0;  border-top: 0; }
.relato__quote-mark {
  position: absolute;
  top: 0.55rem;
  left: 1.1rem;
  font-family: var(--font-display);
  font-size: 2.4rem;
  line-height: 1;
  color: var(--gold-aged, #c9a15f);
  opacity: 0.28;
}
.relato__text {
  margin: 0;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: clamp(1.04rem, 2.2vw, 1.18rem);
  line-height: 1.62;
  font-style: italic;
  color: #ece2cf;
  text-wrap: pretty;
}
/* Gilt rule separating the chronicle from the signature */
.relato__rule {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: rgba(201, 161, 95, 0.55);
  font-size: 0.7rem;
}
.relato__rule::before,
.relato__rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(201, 161, 95, 0.45), transparent);
}
.relato__by {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
/* Wax-seal monogram — a round aged-gold sigil (no stock photo) */
.relato__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  flex: 0 0 42px;
  border-radius: 50%;
  font-family: var(--font-display);
  font-size: 0.86rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #2a1808;
  background:
    radial-gradient(circle at 38% 32%, rgba(255, 245, 220, 0.7), transparent 55%),
    linear-gradient(160deg, #e9cf9f, #b88b48);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.4),
    inset 0 0 0 3px rgba(120, 80, 40, 0.3),
    0 3px 10px rgba(0, 0, 0, 0.32);
}
.relato__who { display: flex; flex-direction: column; gap: 0.1rem; }
.relato__name {
  font-family: "Cinzel", "Cormorant Garamond", serif;
  font-size: 0.96rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--gold-burning, #f2c879);
}
.relato__role {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(201, 161, 95, 0.85);
}
/* Navigation — thin, discrete chevrons (no heavy filled circles) */
.relatos__nav {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  cursor: pointer;
  color: rgba(201, 161, 95, 0.75);
  background: none;
  border: 1px solid rgba(201, 161, 95, 0.28);
  transition: color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
}
.relatos__nav svg { width: 15px; height: 15px; }
.relatos__nav:hover,
.relatos__nav:focus-visible {
  outline: none;
  color: var(--gold-burning, #f2c879);
  border-color: rgba(242, 200, 121, 0.55);
  box-shadow: 0 0 12px rgba(242, 200, 121, 0.18);
}
.relatos__nav:active { transform: scale(0.94); }
.relatos__dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1.7rem;
  display: flex;
  justify-content: center;
  gap: 0.5rem;
}
.relatos__dot {
  width: 6px;
  height: 6px;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  border: 1px solid rgba(201, 161, 95, 0.45);
  background: transparent;
  transition: background 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}
.relatos__dot.is-active {
  background: var(--gold-aged, #c9a15f);
  box-shadow: 0 0 7px rgba(201, 161, 95, 0.45);
  transform: scale(1.25);
}
.relatos__dot:focus-visible { outline: none; box-shadow: 0 0 0 2px rgba(242, 200, 121, 0.5); }

html[data-theme="light"] .relato {
  background:
    repeating-linear-gradient(0deg, rgba(120,84,40,0.022) 0 2px, transparent 2px 4px),
    linear-gradient(160deg, rgba(245, 234, 209, 0.96), rgba(232, 217, 184, 0.92));
  box-shadow:
    inset 0 0 0 1px rgba(120, 84, 40, 0.3),
    inset 0 0 0 5px rgba(120, 84, 40, 0.08),
    0 14px 34px rgba(74, 45, 20, 0.15);
}
html[data-theme="light"] .relato__corner { border-color: rgba(120, 84, 40, 0.5); }
html[data-theme="light"] .relato__text { color: #2a1c0e; }
html[data-theme="light"] .relato__name { color: #6b4316; }
html[data-theme="light"] .relato__role { color: #8a5a1f; }
html[data-theme="light"] .relatos__nav { color: #8a5a1f; border-color: rgba(120, 84, 40, 0.35); }
@media (max-width: 560px) {
  .relatos__stage { gap: 0.5rem; }
  .relatos__nav { width: 28px; height: 28px; }
  .relatos__track { min-height: 290px; }
}

/* ════════════════════════════════════════════════════════════════════
   #1e · INVOCAÇÃO FINAL — the conversion close (most emphatic block)
   ════════════════════════════════════════════════════════════════════ */
/* INVOCAÇÃO FINAL · reframed as a compact, ornamented closing page —
   a noble invitation, not a banner. Half the former height, smaller
   title, framed by elven rules. */
.invoke {
  text-align: center;
  overflow: hidden;
  padding-top: clamp(2.6rem, 6vw, 4.4rem);
  padding-bottom: clamp(2.6rem, 6vw, 4.4rem);
}
/* Soft focused veil — gentler than before so the page stays calm. */
.invoke__veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 60% 55% at 50% 48%,
      rgba(242, 200, 121, 0.09) 0%,
      rgba(201, 161, 95, 0.04) 40%,
      transparent 72%);
}
.invoke__inner {
  position: relative;
  max-width: 560px;
  margin: 0 auto;
}
/* Elven decorative rules — gilt lines with a central glyph (top) and a
   leaf tail (bottom), bracketing the invitation like a tome's last page. */
.invoke__rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
  color: rgba(201, 161, 95, 0.7);
}
.invoke__rule-line {
  flex: 1;
  max-width: 130px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(201, 161, 95, 0.5), transparent);
}
.invoke__rule-glyph {
  display: inline-flex;
  color: var(--gold-aged, #c9a15f);
  filter: drop-shadow(0 0 8px rgba(242, 200, 121, 0.22));
}
.invoke__rule--top { margin-bottom: 1.1rem; }
.invoke__rule--bottom { margin-top: 1.6rem; }
.invoke__rule-tail {
  font-size: 1rem;
  color: rgba(201, 161, 95, 0.7);
  transform: translateY(-1px);
}
.invoke__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.7rem;
}
.invoke__title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 4.2vw, 2.5rem);
  font-weight: 600;
  line-height: 1.14;
  color: var(--primary);
  margin: 0 auto 0.85rem;
  max-width: 18ch;
  text-wrap: balance;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
.invoke__lede {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: clamp(0.98rem, 2.3vw, 1.12rem);
  line-height: 1.55;
  color: var(--on-surface-variant);
  max-width: 42ch;
  margin: 0 auto clamp(1.4rem, 3vw, 1.9rem);
  text-wrap: pretty;
}
.invoke__actions {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.7rem 0.9rem;
}
/* CTAs styled as small royal seals — slimmer padding, refined finish,
   restrained glow. Inscribed rather than inflated. */
.invoke__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.62rem 1.4rem;
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  isolation: isolate;
  transition: transform 0.35s var(--ease-out), box-shadow 0.45s ease,
    background 0.45s ease, color 0.45s ease, border-color 0.45s ease;
}
.invoke__cta:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgba(255, 231, 160, 0.55);
}
.invoke__cta--primary {
  color: #2a1808;
  background: linear-gradient(160deg, #f1dcb8 0%, #d8b984 52%, #bc954f 100%);
  border: 1px solid rgba(120, 80, 40, 0.6);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.45),
    0 4px 14px rgba(0, 0, 0, 0.34);
}
.invoke__cta--primary:hover {
  transform: translateY(-1px);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.55),
    0 7px 20px rgba(0, 0, 0, 0.4),
    0 0 18px rgba(255, 231, 160, 0.3);
}
.invoke__cta--ghost {
  color: #e8dcc6;
  background: linear-gradient(160deg, rgba(40, 34, 24, 0.45), rgba(20, 16, 11, 0.38));
  border: 1px solid rgba(201, 161, 95, 0.45);
}
.invoke__cta--ghost:hover {
  transform: translateY(-1px);
  color: #fff6e6;
  border-color: rgba(242, 200, 121, 0.65);
  box-shadow: 0 5px 16px rgba(0, 0, 0, 0.36), 0 0 14px rgba(242, 200, 121, 0.2);
}
.invoke__cta--ghost .invoke__cta-icon { display: inline-flex; }
html[data-theme="light"] .invoke__title { color: #3a2410; text-shadow: none; }
html[data-theme="light"] .invoke__lede { color: #4f3c25; }
html[data-theme="light"] .invoke__cta--ghost { color: #4a2e16; background: linear-gradient(160deg, rgba(244,232,205,0.7), rgba(232,216,182,0.6)); border-color: rgba(120,84,40,0.5); }
html[data-theme="light"] .invoke__cta--ghost:hover { color: #2a1c0e; }

/* ── Reduced-motion: keep the new layer calm but fully legible ──────── */
@media (prefers-reduced-motion: reduce) {
  .pillar,
  .pillar__aura,
  .pillar__glyph,
  .pillar__spark,
  .relato,
  .relato.is-active,
  .invoke__sigil,
  .invoke__cta--primary::after {
    animation: none !important;
    transition: opacity 0.25s linear !important;
    transform: none !important;
  }
  .pillar:hover, .pillar:focus-within { transform: none; }
}

/* ════════════════════════════════════════════════════════════════════
   RELÍQUIA DO APRENDIZ · entry contract (data-entry="true")
   --------------------------------------------------------------------
   Same common-tier palette as the codex, but tuned to aged bronze/copper
   and a quieter glow than rare/epic books. The "Primeiro Passo" seal
   marks it as the gateway without shouting like a marketplace banner.
   ════════════════════════════════════════════════════════════════════ */
.contract--entry {
  --rarity-accent:        #B87333;   /* aged copper */
  --rarity-accent-bright: #D4A574;
  --rarity-accent-deep:   #6B4423;
  --rarity-glow:          rgba(184, 115, 51, 0.38);
}

/* Wax ribbon seal · top-right of the grimoire spread */
.contract__entry-seal {
  position: absolute;
  top: 14px;
  right: 18px;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.32rem 0.72rem 0.34rem;
  border-radius: 4px 10px 4px 10px;
  font-family: var(--font-display);
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #2a1808;
  background: linear-gradient(160deg,
    rgba(244, 221, 192, 0.96) 0%,
    rgba(212, 165, 116, 0.92) 55%,
    rgba(184, 115, 51, 0.9) 100%);
  border: 1px solid rgba(107, 68, 35, 0.55);
  box-shadow:
    inset 0 0 0 1px rgba(255, 245, 220, 0.35),
    0 4px 14px rgba(0, 0, 0, 0.32),
    0 0 16px rgba(184, 115, 51, 0.22);
  pointer-events: none;
}
.contract__entry-seal-star {
  font-size: 0.7rem;
  opacity: 0.9;
  animation: entry-seal-twinkle 3.2s ease-in-out infinite;
}
@keyframes entry-seal-twinkle {
  0%, 100% { opacity: 0.65; transform: scale(0.92); }
  50%      { opacity: 1;    transform: scale(1.08); }
}

/* Entry book · softer bronze aura, never competing with legendary */
.contract--entry .contract__book {
  box-shadow:
    inset 0 0 0 1px rgba(184, 115, 51, 0.22),
    0 18px 44px rgba(0, 0, 0, 0.42),
    0 0 72px rgba(184, 115, 51, 0.18);
}
.contract--entry .contract__book::before {
  /* Discrete motes — lighter than epic/legendary particle fields */
  opacity: 0.35;
}

/* Entry price · legible emphasis without cheapening upper tiers.
   Brightened (June 2026) — the soft copper read too dim; a warm
   luminous gold keeps the bronze tier identity but stays readable. */
.contract--entry .contract__price strong {
  font-size: 1.12rem;
  color: #f5cd86;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* Lore line · inscribed at the foot of the left page */
.contract__lore {
  margin: 1.1rem 0 0;
  padding-top: 0.85rem;
  border-top: 1px solid rgba(201, 161, 95, 0.2);
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-style: italic;
  line-height: 1.55;
  color: var(--gold-aged, #c9a15f);
  opacity: 0.88;
  text-wrap: pretty;
}

/* Entry CTA · "Invocar Relíquia" — copper-tinted seal button */
.contract--entry .contract__cta {
  background: linear-gradient(160deg,
    rgba(212, 165, 116, 0.95) 0%,
    rgba(184, 115, 51, 0.92) 100%);
  border-color: rgba(107, 68, 35, 0.6);
  color: #1a1008;
}
.contract--entry .contract__cta:hover,
.contract--entry .contract__cta:focus-visible {
  background: linear-gradient(160deg,
    rgba(244, 221, 192, 0.98) 0%,
    rgba(212, 165, 116, 0.95) 100%);
  box-shadow:
    0 8px 22px rgba(0, 0, 0, 0.38),
    0 0 24px rgba(184, 115, 51, 0.42);
  transform: translateY(-2px);
}

/* Hover on entry book · gentle pulse (less than rare+) */
@media (prefers-reduced-motion: no-preference) {
  .contract--entry .contract__book:hover,
  .contract--entry .contract__book:focus-visible {
    box-shadow:
      inset 0 0 0 1px rgba(212, 165, 116, 0.32),
      0 22px 50px rgba(0, 0, 0, 0.48),
      0 0 90px rgba(184, 115, 51, 0.28);
  }
  .contract--entry .contract__book:hover .contract__entry-seal,
  .contract--entry .contract__book:focus-visible .contract__entry-seal {
    box-shadow:
      inset 0 0 0 1px rgba(255, 245, 220, 0.45),
      0 6px 18px rgba(0, 0, 0, 0.36),
      0 0 22px rgba(184, 115, 51, 0.38);
  }
}

html[data-theme="light"] .contract--entry .contract__book {
  box-shadow:
    inset 0 0 0 1px rgba(120, 84, 40, 0.28),
    0 16px 36px rgba(74, 45, 20, 0.16),
    0 0 48px rgba(184, 115, 51, 0.12);
}
html[data-theme="light"] .contract__entry-seal {
  color: #2a1808;
  background: linear-gradient(160deg, #f4e8c8, #d4a574);
  border-color: rgba(120, 84, 40, 0.45);
}
html[data-theme="light"] .contract__lore { color: #7a4b1e; }
html[data-theme="light"] .contract--entry .contract__price strong { color: #8a5a1f; text-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .contract__entry-seal-star { animation: none; }
}

/* ════════════════════════════════════════════════════════════════════
   SHARED BLESSINGS BAND · inherited by every contract
   --------------------------------------------------------------------
   A fixed inscription above the codex listing the six boons bound to
   EVERY pact. Aged-gold, runic, intentionally not a marketplace banner.
   ════════════════════════════════════════════════════════════════════ */
.contract-blessings {
  position: relative;
  max-width: 880px;
  margin: 0 auto clamp(2.2rem, 5vw, 3.4rem);
  padding: clamp(1.4rem, 3vw, 2rem) clamp(1.2rem, 3.5vw, 2.6rem) clamp(1.5rem, 3vw, 2.1rem);
  text-align: center;
  border-radius: 14px;
  background:
    radial-gradient(120% 140% at 50% 0%, rgba(212, 175, 110, 0.07), transparent 60%),
    linear-gradient(180deg, rgba(28, 20, 12, 0.42), rgba(20, 14, 9, 0.28));
  isolation: isolate;
}
.contract-blessings__frame {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  border: 1px solid rgba(212, 175, 110, 0.28);
  box-shadow:
    inset 0 0 0 1px rgba(212, 175, 110, 0.1),
    inset 0 0 38px rgba(212, 175, 110, 0.06),
    0 18px 44px rgba(0, 0, 0, 0.32);
}
/* corner ✦ marks etched into the frame */
.contract-blessings__frame::before,
.contract-blessings__frame::after {
  content: "✦";
  position: absolute;
  font-size: 0.7rem;
  color: rgba(212, 175, 110, 0.5);
  top: 8px;
}
.contract-blessings__frame::before { left: 12px; }
.contract-blessings__frame::after  { right: 12px; }

.contract-blessings__title {
  margin: 0 0 0.45rem;
  font-family: "Cinzel", "Cormorant Garamond", serif;
  font-size: clamp(0.92rem, 2.1vw, 1.16rem);
  font-weight: 600;
  letter-spacing: 0.05em;
  line-height: 1.32;
  color: #ecd29a;
  /* glow tamed so the engraving stays crisp, not blurry */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.contract-blessings__star {
  color: rgba(212, 175, 110, 0.7);
  margin: 0 0.5rem;
  font-size: 0.8em;
}
.contract-blessings__sub {
  margin: 0 auto clamp(1.2rem, 2.6vw, 1.7rem);
  max-width: 48ch;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: clamp(0.9rem, 1.9vw, 1.02rem);
  color: rgba(222, 208, 184, 0.82);
  line-height: 1.42;
}
.contract-blessings__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.55rem 1.6rem;
}
/* Left-aligned so the eye lands on the rune then the name — immediate
   reading. The NAME is the dominant element; the rune is a quiet sigil. */
.contract-blessing {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.6rem;
  padding: 0.42rem 0.7rem;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: clamp(0.98rem, 2vw, 1.08rem);
  font-weight: 600;
  color: #f1e7d4;
  letter-spacing: 0.005em;
  border-radius: 7px;
  transition: background 0.4s ease, transform 0.35s ease;
}
.contract-blessing__name { flex: 1; }
.contract-blessing:hover {
  background: rgba(212, 175, 110, 0.06);
  transform: translateX(2px);
}
/* Rune · secondary sigil — smaller, dimmer, no competing glow */
.contract-blessing__rune {
  flex: none;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  font-size: 0.82rem;
  font-weight: 400;
  color: rgba(196, 158, 102, 0.7);
  text-shadow: none;
}

@media (max-width: 620px) {
  .contract-blessings__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 380px) {
  .contract-blessings__list { grid-template-columns: 1fr; }
}

html[data-theme="light"] .contract-blessings {
  background:
    radial-gradient(120% 140% at 50% 0%, rgba(150, 110, 50, 0.08), transparent 60%),
    linear-gradient(180deg, rgba(245, 235, 215, 0.7), rgba(238, 226, 202, 0.55));
}
html[data-theme="light"] .contract-blessings__frame { border-color: rgba(150, 110, 50, 0.3); }
html[data-theme="light"] .contract-blessings__title { color: #7a4f1a; text-shadow: none; }
html[data-theme="light"] .contract-blessing { color: #3a2a18; }
html[data-theme="light"] .contract-blessing__rune { color: rgba(140, 96, 36, 0.7); text-shadow: none; }

/* ════════════════════════════════════════════════════════════════════
   IDEAL-FOR + ESTIMATED TIME · the "who is this for / how long" block
   sits directly under the price specs so value is instantly legible.
   ════════════════════════════════════════════════════════════════════ */
.contract__fit {
  position: relative;
  margin: 0.7rem 0 0.2rem;
  padding: 0.6rem 0.7rem;
  border-radius: 8px;
  background: linear-gradient(180deg,
    var(--rarity-glow, rgba(229, 190, 174, 0.12)) -120%,
    rgba(0, 0, 0, 0.02) 90%);
  border: 1px dashed rgba(140, 90, 47, 0.3);
}
.contract__fit-row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0;
  flex-wrap: wrap;
}
.contract__fit-key {
  flex: none;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.56rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--rarity-accent-deep, var(--gold-deep));
}
.contract__fit-val {
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink, #ece2cf);
  line-height: 1.25;
}
.contract__fit-eta {
  margin: 0.4rem 0 0;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-style: italic;
  font-size: 0.84rem;
  color: var(--ink-soft, rgba(225, 210, 185, 0.78));
  letter-spacing: 0.02em;
}

html[data-theme="light"] .contract__fit { border-color: rgba(150, 110, 50, 0.32); }
html[data-theme="light"] .contract__fit-val { color: #3a2a18; }

/* ════════════════════════════════════════════════════════════════════
   POWER LIST · the EXCLUSIVE powers each rarity adds (single column).
   Reuses .contract__enchant base styling; the ✓ check is tinted by the
   card's rarity accent, and the "Tudo do contrato X" row is gilded.
   ════════════════════════════════════════════════════════════════════ */
.contract__enchants--powers .contract__enchant-list.contract__power-list {
  grid-template-columns: 1fr;
  gap: 0.3rem;
  max-width: 34ch;
  margin: 0 auto;
}
.contract__power-check {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 17px;
  height: 17px;
  font-size: 0.78rem;
  line-height: 1;
  color: var(--rarity-accent, var(--gold));
  text-shadow: 0 0 5px var(--rarity-glow, rgba(229, 190, 174, 0.5));
  transition: color 0.35s ease, text-shadow 0.35s ease, transform 0.35s ease;
}
.contract__enchant:hover .contract__power-check {
  color: #b9f4cf;
  text-shadow: 0 0 9px rgba(120, 205, 150, 0.7);
  transform: scale(1.12);
}
/* "Tudo do contrato anterior" — gilded inheritance row */
.contract__enchant--inherit {
  margin-bottom: 0.15rem;
  padding-bottom: 0.32rem;
  border-bottom: 1px dashed rgba(140, 90, 47, 0.3);
}
.contract__enchant--inherit .contract__enchant-name {
  font-style: italic;
  font-weight: 600;
  color: var(--rarity-accent-bright, var(--gold));
}
.contract__enchant--inherit .contract__power-check {
  color: var(--rarity-accent-bright, var(--gold));
}

html[data-theme="light"] .contract__enchant--inherit .contract__enchant-name {
  color: var(--rarity-accent-deep, #8a5a1f);
}

@media (prefers-reduced-motion: reduce) {
  .contract[data-rarity="mythic"] .contract__book::after { animation: none; opacity: 0.7; }
}

/* ════════════════════════════════════════════════════════════════════
   CRISTAL DA AMBIÊNCIA · a tiny hidden soundtrack relic (bottom-left)
   --------------------------------------------------------------------
   Aged gold + arcane violet, runic facets, a slow dormant pulse and a
   small grimoire panel ("Trilha do Reino") that unfurls above it. Built
   to read as a collector's detail, never a media player / audio bar.
   ════════════════════════════════════════════════════════════════════ */
.ambience {
  position: fixed;
  left: 1.25rem;
  bottom: 1.25rem;
  z-index: 150;
  display: flex;
  flex-direction: column-reverse;   /* the panel unfurls ABOVE the crystal */
  align-items: flex-start;
  gap: 0.55rem;
}

/* ── The crystal (dormant button) ──────────────────────────────────── */
.ambience__crystal {
  position: relative;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 8px;
  cursor: pointer;
  color: #c9a15f;
  background:
    radial-gradient(circle at 36% 28%, rgba(168, 85, 247, 0.20), transparent 60%),
    linear-gradient(160deg, rgba(40, 30, 22, 0.62), rgba(18, 13, 22, 0.56));
  border: 1px solid rgba(201, 161, 95, 0.42);
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.08),
    0 4px 14px rgba(0, 0, 0, 0.42);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  isolation: isolate;
  transition:
    transform 0.4s var(--ease-out, cubic-bezier(.16,1,.3,1)),
    border-color 0.4s ease, box-shadow 0.5s ease, color 0.4s ease;
}
.ambience__gem {
  position: relative;
  z-index: 2;
  filter: drop-shadow(0 0 3px rgba(242, 200, 121, 0.35));
  transition: filter 0.5s ease;
}
.ambience__gem-facets { color: #f2c879; }

/* Soft aura — faint slow pulse while dormant ("there's something here"). */
.ambience__aura {
  position: absolute;
  inset: -3px;
  z-index: 1;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(circle, rgba(242, 200, 121, 0.22), transparent 70%);
  opacity: 0.2;
  animation: ambience-dormant 5.5s ease-in-out infinite;
}
@keyframes ambience-dormant {
  0%, 100% { opacity: 0.14; transform: scale(0.9); }
  50%      { opacity: 0.36; transform: scale(1.06); }
}

.ambience__crystal:hover,
.ambience__crystal:focus-visible {
  outline: none;
  color: #f2c879;
  transform: translateY(-2px);
  border-color: rgba(242, 200, 121, 0.6);
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.14),
    0 6px 18px rgba(0, 0, 0, 0.46),
    0 0 16px rgba(168, 85, 247, 0.28);
}

/* Discreet motes — invisible until the relic is awakened. */
.ambience__motes { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.ambience__motes i {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffe9a8, rgba(242, 200, 121, 0) 70%);
  opacity: 0;
}
.ambience__motes i:nth-child(1) { left: 16%; bottom: 22%; }
.ambience__motes i:nth-child(2) { left: 70%; bottom: 30%; }
.ambience__motes i:nth-child(3) { left: 44%; bottom: 64%; }

/* ── AWAKENED state (music playing) ────────────────────────────────── */
.ambience.is-awake .ambience__crystal {
  color: #f7d98e;
  border-color: rgba(242, 200, 121, 0.6);
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.16),
    0 4px 16px rgba(0, 0, 0, 0.46),
    0 0 18px rgba(168, 85, 247, 0.32);
}
.ambience.is-awake .ambience__aura {
  background: radial-gradient(circle,
    rgba(242, 200, 121, 0.34), rgba(168, 85, 247, 0.12) 56%, transparent 74%);
  animation: ambience-awake 3.6s ease-in-out infinite;
}
@keyframes ambience-awake {
  0%, 100% { opacity: 0.4; transform: scale(1); }
  50%      { opacity: 0.68; transform: scale(1.12); }
}
.ambience.is-awake .ambience__gem {
  filter: drop-shadow(0 0 6px rgba(242, 200, 121, 0.6));
  animation: ambience-gem-breathe 4.4s ease-in-out infinite;
}
@keyframes ambience-gem-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.08); }
}
.ambience.is-awake .ambience__motes i { animation: ambience-mote 4.2s ease-in-out infinite; }
.ambience.is-awake .ambience__motes i:nth-child(2) { animation-delay: 1.3s; }
.ambience.is-awake .ambience__motes i:nth-child(3) { animation-delay: 2.5s; }
@keyframes ambience-mote {
  0%       { opacity: 0; transform: translateY(2px) scale(0.6); }
  30%      { opacity: 0.9; }
  100%     { opacity: 0; transform: translateY(-12px) scale(1); }
}

/* ── Tooltip (hover) ───────────────────────────────────────────────── */
.ambience__tooltip {
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%) translateX(-4px);
  white-space: nowrap;
  padding: 0.34rem 0.62rem;
  border-radius: 4px;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.82rem;
  font-style: italic;
  color: #f0e2cf;
  background: linear-gradient(160deg, rgba(34, 26, 18, 0.96), rgba(20, 15, 24, 0.94));
  border: 1px solid rgba(201, 161, 95, 0.42);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.42);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease, transform 0.35s var(--ease-out, cubic-bezier(.16,1,.3,1));
}
.ambience__crystal:hover .ambience__tooltip,
.ambience__crystal:focus-visible .ambience__tooltip {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
.ambience.is-open .ambience__tooltip { opacity: 0 !important; }

/* ── Grimoire panel ────────────────────────────────────────────────── */
.ambience__panel {
  position: relative;
  width: 196px;
  padding: 0.85rem 0.95rem 0.95rem;
  border-radius: 4px;
  background:
    repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.02) 0 2px, transparent 2px 4px),
    linear-gradient(158deg, rgba(38, 30, 22, 0.97), rgba(22, 16, 26, 0.95));
  border: 1px solid rgba(201, 161, 95, 0.38);
  box-shadow:
    inset 0 0 0 1px rgba(242, 200, 121, 0.07),
    inset 0 0 26px rgba(168, 85, 247, 0.05),
    0 16px 38px rgba(0, 0, 0, 0.5);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transform-origin: left bottom;
  animation: ambience-unfurl 0.4s var(--ease-out, cubic-bezier(.16,1,.3,1)) both;
}
@keyframes ambience-unfurl {
  from { opacity: 0; transform: translateY(6px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
/* Elven gilt corners */
.ambience__panel-corner {
  position: absolute;
  width: 11px;
  height: 11px;
  border: 1px solid rgba(201, 161, 95, 0.55);
  pointer-events: none;
}
.ambience__panel-corner--tl { top: 6px;    left: 6px;    border-right: 0; border-bottom: 0; }
.ambience__panel-corner--tr { top: 6px;    right: 6px;   border-left: 0;  border-bottom: 0; }
.ambience__panel-corner--bl { bottom: 6px; left: 6px;    border-right: 0; border-top: 0; }
.ambience__panel-corner--br { bottom: 6px; right: 6px;   border-left: 0;  border-top: 0; }

.ambience__panel-title {
  margin: 0 0 0.4rem;
  text-align: center;
  font-family: "Cinzel", "Cormorant Garamond", serif;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: #ecd29a;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.ambience__panel-rule {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.7rem;
  color: rgba(201, 161, 95, 0.55);
  font-size: 0.6rem;
}
.ambience__panel-rule::before,
.ambience__panel-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(201, 161, 95, 0.45), transparent);
}

/* Play / Pause action — a small wax-seal style button */
.ambience__action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  margin-bottom: 0.7rem;
  padding: 0.5rem 0.7rem;
  border-radius: 4px;
  cursor: pointer;
  font-family: "Cormorant Garamond", "Libre Caslon Text", serif;
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #2a1808;
  background: linear-gradient(160deg, #f1dcb8 0%, #d8b984 52%, #bc954f 100%);
  border: 1px solid rgba(120, 80, 40, 0.6);
  box-shadow: inset 0 0 0 1px rgba(255, 245, 220, 0.4), 0 3px 10px rgba(0, 0, 0, 0.34);
  transition: transform 0.3s var(--ease-out, cubic-bezier(.16,1,.3,1)), box-shadow 0.4s ease, background 0.4s ease;
}
.ambience__action-rune {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: #4a2e12;
}
.ambience__action:hover,
.ambience__action:focus-visible {
  outline: none;
  transform: translateY(-1px);
  background: linear-gradient(160deg, #f8e7c6 0%, #e3c590 52%, #c8a056 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 245, 220, 0.55), 0 5px 14px rgba(0, 0, 0, 0.4), 0 0 14px rgba(255, 231, 160, 0.3);
}

/* Volume — discreet runic slider */
.ambience__volume {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.ambience__volume-label {
  font-family: var(--font-mono);
  font-size: 0.56rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(201, 161, 95, 0.85);
}
.ambience__volume-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 3px;
  border-radius: 3px;
  cursor: pointer;
  background: linear-gradient(90deg, rgba(242, 200, 121, 0.7), rgba(168, 85, 247, 0.5));
  outline: none;
}
.ambience__volume-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #fff2d4, #c9a15f);
  border: 1px solid rgba(120, 80, 40, 0.7);
  box-shadow: 0 0 6px rgba(242, 200, 121, 0.5);
}
.ambience__volume-slider::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #fff2d4, #c9a15f);
  border: 1px solid rgba(120, 80, 40, 0.7);
  box-shadow: 0 0 6px rgba(242, 200, 121, 0.5);
}
.ambience__volume-slider:focus-visible {
  box-shadow: 0 0 0 2px rgba(242, 200, 121, 0.5);
}

/* Recede during focused experiences, mirroring domains/merlin. */
body.vault-open .ambience,
body.is-codex-summoning .ambience {
  opacity: 0;
  pointer-events: none;
}

/* ── Light theme · aged manuscript ─────────────────────────────────── */
html[data-theme="light"] .ambience__crystal {
  color: #8a5a1f;
  background:
    radial-gradient(circle at 36% 28%, rgba(139, 92, 246, 0.16), transparent 60%),
    linear-gradient(160deg, rgba(244, 232, 205, 0.92), rgba(232, 216, 182, 0.88));
  border-color: rgba(120, 84, 40, 0.45);
}
html[data-theme="light"] .ambience__gem-facets { color: #9a6a28; }
html[data-theme="light"] .ambience__tooltip {
  color: #2a1c0e;
  background: linear-gradient(160deg, rgba(245, 234, 209, 0.97), rgba(232, 217, 184, 0.95));
  border-color: rgba(120, 84, 40, 0.4);
}
html[data-theme="light"] .ambience__panel {
  background:
    repeating-linear-gradient(0deg, rgba(120, 84, 40, 0.025) 0 2px, transparent 2px 4px),
    linear-gradient(158deg, rgba(245, 234, 209, 0.98), rgba(232, 217, 184, 0.96));
  border-color: rgba(120, 84, 40, 0.4);
  box-shadow: 0 16px 38px rgba(74, 45, 20, 0.18);
}
html[data-theme="light"] .ambience__panel-corner { border-color: rgba(120, 84, 40, 0.5); }
html[data-theme="light"] .ambience__panel-title { color: #7a4f1a; text-shadow: none; }
html[data-theme="light"] .ambience__volume-label { color: #8a5a1f; }

/* ── Mobile · lift above the bottom-left Domains handle ────────────── */
@media (max-width: 1100px) {
  .ambience { bottom: 4.75rem; }
}

/* ── Reduced motion ────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ambience__aura,
  .ambience.is-awake .ambience__aura,
  .ambience.is-awake .ambience__gem,
  .ambience.is-awake .ambience__motes i,
  .ambience__panel {
    animation: none !important;
  }
  .ambience__crystal { transition: none; }
}

/* ============================================================
   MOBILE PERFORMANCE OVERRIDES
   ------------------------------------------------------------
   On-device profiling showed the page dropping to ~2 FPS during
   the welcome and while scrolling the contracts, WHILE the canvas
   loops were idle (the 2D/WebGL wallpapers drew 0 frames).
   That isolates the cost to DOM paint / compositing, not the
   WebGL/2D wallpaper. Two culprits, fixed below for touch devices:

     1. .welcome__char — ~80 letter spans each animating
        `background-position` on a `background-clip:text` gradient
        (CPU repaint of every glyph per frame) PLUS per-letter
        `filter: blur()` + 4-layer text-shadow + will-change. We
        swap to a cheap fade (static lava fill, no blur sweep).

     2. .contract__book ::before/::after used `mix-blend-mode:
        multiply` full-bleed layers + large blurred box-shadows
        that recomposite on every scroll frame. We drop the blend
        mode and shrink the shadow on phones.
   ============================================================ */
@media (hover: none) and (pointer: coarse), (max-width: 767px) {
  /* Promote the fixed wallpaper stack to its own compositor layer so
     iOS Safari doesn't drop it during momentum scroll. */
  .tree-wall,
  .tree-wall__canvas,
  .tree-wall__crystal-canvas,
  #narrative-particles {
    transform: translateZ(0);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }

  /* Anchor the wallpaper plane to the LARGE viewport (URL-bar hidden).
     `lvh` does not change when the mobile address bar shows/hides, so
     the canvases never reflow on the first scroll — that height change
     was shifting the whole skill-tree (centred on h/2) by ~50px and
     reading as the background "repositioning itself". The plane simply
     extends a little below the initial fold; being a fixed backdrop,
     that overscan is invisible. JS reads these CSS-driven sizes. */
  .tree-wall {
    height: 100lvh;
    min-height: 100lvh;
  }
  #narrative-particles {
    height: 100lvh;
  }

  /* — Act II / craft (#knowledge) — scroll-linked blur + translateY on
     .craft and filter on .tree-wall were the lag + "background sliding
     down" (content moves up → wallpaper feels like it drops). Snap vars
     in narrative.js instead; keep visuals static and cheap here. — */
  .craft {
    filter: none !important;
    transform: none !important;
  }
  .craft__head::before {
    filter: blur(20px);
    animation: none !important;
  }
  .tree-wall,
  html[data-craft-active] .tree-wall {
    filter: none !important;
    transition: none !important;
  }

  /* Hide the multi-canvas wallpaper while the welcome DOM is on screen —
     compositing ~2.75Mpx of fixed canvases under the overlay was still
     costing ~2 FPS even with JS loops paused (proven by overlay logs). */
  body.cv-welcome-active .tree-wall,
  body.cv-welcome-active #narrative-particles,
  body:has(#arcane-welcome.is-active) .tree-wall,
  body:has(#arcane-welcome.is-leaving) .tree-wall,
  body:has(#arcane-welcome.is-active) #narrative-particles,
  body:has(#arcane-welcome.is-leaving) #narrative-particles {
    visibility: hidden !important;
    pointer-events: none !important;
  }

  /* — Welcome LITE (welcome.js adds .welcome--mobile-lite): no per-char
     spans, no lava sweep, no motes — line-level fade only. — */
  .welcome--mobile-lite .welcome__motes { display: none !important; }
  .welcome--mobile-lite .welcome__veil {
    animation: none !important;
    opacity: 1 !important;
  }
  .welcome--mobile-lite.is-active .welcome__panel {
    animation: none !important;
    transform: translate(-50%, -50%) !important;
  }
  .welcome--mobile-lite .welcome__line {
    opacity: 0;
    color: #f4e8c6 !important;
    -webkit-text-fill-color: #f4e8c6 !important;
    background: none !important;
    filter: none !important;
    text-shadow: 0 0 8px rgba(255, 150, 70, 0.35) !important;
    animation: cv-welcome-line-in-m 0.45s ease forwards !important;
    animation-delay: var(--line-delay, 0s) !important;
    will-change: auto !important;
  }
  .welcome--mobile-lite .welcome__title {
    color: #ffe49a !important;
    -webkit-text-fill-color: #ffe49a !important;
    background: none !important;
    white-space: normal !important;
  }
  .welcome--mobile-lite .welcome__star {
    animation: cv-welcome-line-in-m 0.45s ease forwards !important;
    animation-delay: var(--line-delay, 0s) !important;
    filter: none !important;
  }
  .welcome--mobile-lite.is-leaving .welcome__line,
  .welcome--mobile-lite.is-leaving .welcome__star {
    animation: cv-welcome-line-out-m 0.4s ease forwards !important;
    animation-delay: var(--leave-delay, 0s) !important;
  }

  /* Fallback if char spans exist from a cached DOM clone */
  .welcome__char {
    animation: cv-welcome-char-in-m 0.5s ease forwards !important;
    animation-delay: calc(var(--line-delay, 0s) + var(--ci, 0) * 0.02s) !important;
    filter: none !important;
    will-change: auto !important;
    background: none !important;
  }
  .welcome.is-leaving .welcome__char,
  .welcome.is-leaving .welcome__star {
    animation: cv-welcome-char-out-m 0.45s ease forwards !important;
    animation-delay: calc(var(--leave-delay, 0s) + var(--ci, 0) * 0.015s) !important;
    filter: none !important;
  }
  .welcome__mote { display: none !important; will-change: auto !important; }

  /* — Portal / contact: blur/blend dropped for scroll perf, replaced
     with STATIC depth so the section still feels crafted and alive.
     Everything here composites once (no animated blur, no backdrop
     read per frame); the galaxy canvas still provides the motion. — */
  .portal__stage::before {
    mix-blend-mode: normal !important;
    opacity: 0.85 !important;
    background: radial-gradient(circle at 50% 50%,
      rgba(255, 228, 170, 0.16) 0%,
      rgba(120, 80, 170, 0.16) 32%,
      rgba(70, 44, 120, 0.10) 56%,
      transparent 76%) !important;
  }
  .portal__link {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    will-change: auto !important;
    background:
      linear-gradient(180deg,
        rgba(32, 30, 26, 0.94) 0%,
        rgba(18, 17, 15, 0.96) 100%) !important;
    border: 1px solid color-mix(in srgb, var(--channel-glow) 42%, rgba(194, 164, 107, 0.38)) !important;
    border-radius: 14px !important;
    /* Resting glow — region-tinted outer halo so each of the six
       contact boxes is visibly lit even with no hover on touch. */
    box-shadow:
      inset 0 1px 0 rgba(255, 238, 205, 0.16),
      inset 0 0 20px color-mix(in srgb, var(--channel-glow) 14%, transparent),
      0 0 0 1px color-mix(in srgb, var(--channel-glow) 26%, transparent),
      0 0 18px color-mix(in srgb, var(--channel-glow) 30%, transparent),
      0 5px 16px rgba(0, 0, 0, 0.45) !important;
    overflow: hidden !important;
  }
  /* Static aura → a soft fixed halo seated behind the plate (no blur
     animation). Reusing ::before keeps the markup untouched. */
  .portal__link::before {
    filter: none !important;
    opacity: 0.55 !important;
    transform: none !important;
    inset: 0 !important;
    border-radius: 14px !important;
    background: radial-gradient(120% 140% at 12% 0%,
      color-mix(in srgb, var(--channel-glow) 28%, transparent) 0%,
      transparent 60%) !important;
    animation: none !important;
  }
  /* Crisp inner gold edge + a thin region-tinted accent bar at the
     left, so each card reads as a lit rune plate even at rest. */
  .portal__link::after {
    content: "" !important;
    position: absolute !important;
    inset: 0 !important;
    border-radius: 14px !important;
    box-shadow:
      inset 0 0 0 1px color-mix(in srgb, var(--channel-glow) 30%, transparent) !important;
    background:
      linear-gradient(90deg,
        color-mix(in srgb, var(--col-accent, var(--gold)) 90%, transparent) 0%,
        transparent 3px) !important;
    opacity: 0.9 !important;
    pointer-events: none !important;
    z-index: 0 !important;
  }
  .portal__link svg { color: color-mix(in srgb, var(--col-accent, var(--gold)) 80%, #fff 20%) !important; }
  .portal__link-label { color: #F3E4C4 !important; }
  /* Tap feedback only (no hover on touch): a quick press-in. */
  .portal__link:active {
    transform: scale(0.98) !important;
    border-color: color-mix(in srgb, var(--col-accent, var(--gold)) 70%, transparent) !important;
  }

  /* — Contracts / Codex parchment: no per-frame backdrop blend — */
  .contract__book::before,
  .contract__book::after,
  .codex__book::before,
  .codex__book::after {
    mix-blend-mode: normal !important;
    opacity: 0.45 !important;
  }
  .contract__book {
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4) !important;
  }

  /* — Ghost selection / tap highlight on touch — */
  html {
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
  }
  body {
    user-select: none;
    -webkit-user-select: none;
  }
  a,
  button,
  canvas,
  .hero__portrait,
  .hero__cta,
  .craft__node,
  .pillar,
  .contract__book,
  .contract__cta,
  .tree-hud,
  .tree-hud *,
  .stat,
  .nav,
  .nav * {
    -webkit-tap-highlight-color: transparent !important;
    -webkit-touch-callout: none;
    touch-action: manipulation;
  }
  .memories__lede,
  .memories__eyebrow,
  .section-head__lede,
  .pillar__desc,
  .footer,
  .footer * {
    user-select: text;
    -webkit-user-select: text;
  }

  /* — Act III singularity: drop expensive CSS compositing on mobile — */
  #memories[data-narrative-entered="true"] .memories__wave,
  #memories[data-narrative-entered="true"] .memories__head::before,
  #memories[data-narrative-entered="true"] .memories__head::after {
    animation: none !important;
  }
  .memories--big-bang::after {
    mix-blend-mode: normal !important;
    animation: act3-bigbang-flash-lite 3.2s cubic-bezier(.22, 1, .36, 1) forwards !important;
  }
  .memories--big-bang .memories__head::after {
    animation: act3-bigbang-shock-lite 3.2s cubic-bezier(.22, 1, .36, 1) forwards !important;
    box-shadow: 0 0 24px rgba(255, 231, 160, 0.35) !important;
  }
}
@keyframes act3-bigbang-flash-lite {
  0%, 34% { opacity: 0; transform: translate(-50%, -50%) scale(0); }
  42%     { opacity: 1; transform: translate(-50%, -50%) scale(0.55); }
  100%    { opacity: 0; transform: translate(-50%, -50%) scale(6.5); }
}
@keyframes act3-bigbang-shock-lite {
  0%, 34% { opacity: 0; transform: translate(-50%, -50%) scale(0.05); }
  42%     { opacity: 1; transform: translate(-50%, -50%) scale(0.4); }
  100%    { opacity: 0; transform: translate(-50%, -50%) scale(2.8); }
}
@keyframes cv-welcome-line-in-m {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes cv-welcome-line-out-m {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-8px); }
}
@keyframes cv-welcome-char-in-m {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes cv-welcome-char-out-m {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-8px); }
}

/* ============================================================
   MOBILE VISUAL POLISH  (static-only, no extra render cost)
   ------------------------------------------------------------
   De-clutters the floating overlays that, on phones, wandered
   over body copy and made the layout read as busy / "pitoresco":
     · Merlin docks to a single bottom-right corner (the JS still
       reassigns data-pos every ~30s, but every anchor now resolves
       to the same spot, so the companion stops drifting across the
       text mid-section).
     · The "Domínios" pull-tab collapses to a compact corner rune
       so it no longer clips the hero subtitle as it scrolls past.
     · The Memories intro gets a soft dark vignette so the crystal
       captions behind it stop bleeding through the prose.
   Placed last so source order wins over earlier mobile blocks.
   ============================================================ */
@media (max-width: 767px) {
  /* — Merlin · pin to one bottom-right corner — */
  .merlin,
  .merlin[data-pos="bottom-right"],
  .merlin[data-pos="bottom-left"],
  .merlin[data-pos="middle-right"],
  .merlin[data-pos="middle-left"],
  .merlin[data-pos="top-right"],
  .merlin[data-pos="top-left"] {
    top: auto;
    bottom: max(0.85rem, env(safe-area-inset-bottom));
    right: max(0.6rem, env(safe-area-inset-right));
    left: auto;
    align-items: flex-end;
  }
  .merlin .merlin__scroll { transform-origin: bottom right; }

  /* — Domínios · compact corner rune instead of a tall side-tab — */
  .domains {
    bottom: max(0.85rem, env(safe-area-inset-bottom));
    left: max(0.55rem, env(safe-area-inset-left));
  }
  .domains__handle {
    padding: 0.5rem;
    border-radius: 12px;
    gap: 0;
  }
  .domains__handle-rune { font-size: 1.05rem; }
  /* Keep the word for screen readers, drop it visually so the
     handle reads as a discreet sigil button. */
  .domains__handle-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  /* — Memories · seat the intro on a soft dark halo so the
       crystal captions behind it no longer collide with the text — */
  .memories__head {
    background: radial-gradient(ellipse 124% 102% at 50% 44%,
      rgba(6, 11, 12, 0.94) 0%,
      rgba(6, 11, 12, 0.86) 42%,
      rgba(6, 11, 12, 0.45) 68%,
      rgba(6, 11, 12, 0) 84%);
    border-radius: 26px;
  }

  /* — Evento do Destino · mobile compact — */
  .oracle-d30__card { padding: 1.35rem 1.15rem 1.2rem; }
  .oracle-d30__stage { width: 100%; height: 160px; }
  .oracle-d30__holo-num { font-size: 2rem; }
}

/* ============================================================
   EVENTO DO DESTINO · compact premium modal
   Optional gate → short D30 roll → elegant result
   ============================================================ */
.oracle-d30 {
  position: fixed;
  inset: 0;
  z-index: 4800;
  display: grid;
  place-items: center;
  padding: 1.25rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.35s ease, visibility 0.35s ease;
}
.oracle-d30.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.oracle-d30.is-open .oracle-d30__card {
  animation: oracle-card-enter 0.42s cubic-bezier(.22, 1, .36, 1) both;
}
@keyframes oracle-card-enter {
  from { opacity: 0; transform: scale(0.96) translateY(8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* Soft magical particles — desktop only (see mobile/reduced-motion below). */
.oracle-d30__particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  overflow: hidden;
}
.oracle-d30__particles::before {
  content: "";
  position: absolute;
  inset: -10%;
  background:
    radial-gradient(1.5px 1.5px at 18% 28%, rgba(255, 228, 170, 0.55), transparent),
    radial-gradient(1px 1px at 72% 18%, rgba(200, 175, 255, 0.45), transparent),
    radial-gradient(1.5px 1.5px at 42% 78%, rgba(255, 210, 140, 0.4), transparent),
    radial-gradient(1px 1px at 88% 62%, rgba(230, 200, 255, 0.35), transparent),
    radial-gradient(1px 1px at 8%  55%, rgba(255, 235, 190, 0.4), transparent);
  animation: oracle-particles-drift 14s ease-in-out infinite alternate;
  opacity: 0.55;
}
@keyframes oracle-particles-drift {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(2%, -1.5%) scale(1.02); }
}
body.oracle-open { overflow: hidden; }

/* Subtle scrim — not fullscreen theatre. */
.oracle-d30__scrim {
  position: absolute;
  inset: 0;
  background: rgba(6, 4, 2, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* Compact card — the candle-lit RPG library photo sits behind a warm,
   heavy overlay so text stays fully legible while hinting the ambience. */
.oracle-d30__card {
  position: relative;
  z-index: 2;
  width: min(94vw, 468px);
  max-height: min(90vh, 700px);
  overflow-y: auto;
  padding: 1.75rem 1.65rem 1.5rem;
  border-radius: 16px;
  border: 1px solid rgba(214, 178, 120, 0.22);
  background:
    linear-gradient(155deg, rgba(30, 20, 11, 0.9) 0%, rgba(16, 11, 5, 0.94) 100%),
    url("../assets/oracle/library-bg.png") center/cover no-repeat;
  box-shadow:
    0 24px 64px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(255, 220, 160, 0.04) inset;
  text-align: center;
}

.oracle-d30__dismiss {
  position: absolute;
  top: 0.65rem;
  right: 0.65rem;
  z-index: 5;
  width: 1.85rem;
  height: 1.85rem;
  border: 1px solid rgba(214, 178, 120, 0.25);
  border-radius: 50%;
  background: rgba(12, 8, 4, 0.5);
  color: rgba(235, 220, 195, 0.65);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.oracle-d30__dismiss:hover {
  border-color: rgba(214, 178, 120, 0.5);
  color: #f6e4bd;
}

/* ── Gate (choice) ── */
.oracle-d30__eyebrow {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(230, 196, 138, 0.7);
  margin: 0 0 0.55rem;
}
.oracle-d30__gate-title {
  font-family: "Cinzel", Georgia, serif;
  font-size: clamp(1.05rem, 3.5vw, 1.28rem);
  font-weight: 600;
  color: #f6e4bd;
  margin: 0 0 0.85rem;
  line-height: 1.35;
}
.oracle-d30__gate-body {
  font-size: 0.88rem;
  line-height: 1.55;
  color: rgba(235, 220, 195, 0.82);
  margin: 0 0 0.75rem;
}
.oracle-d30__gate-question {
  font-family: "Cinzel", Georgia, serif;
  font-size: 0.92rem;
  color: rgba(240, 210, 150, 0.88);
  margin: 0 0 1.15rem;
}

.oracle-d30__gate-actions {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

/* ── Buttons ── */
.oracle-d30__btn {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.7rem 1rem;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
  width: 100%;
}
.oracle-d30__btn--primary {
  color: #1a1008;
  background: linear-gradient(135deg, #f3d79a 0%, #cdaa6d 50%, #a07f44 100%);
  border: 1px solid rgba(255, 230, 180, 0.45);
  box-shadow: 0 4px 18px rgba(205, 170, 109, 0.25);
}
.oracle-d30__btn--primary:hover {
  box-shadow: 0 6px 24px rgba(243, 215, 154, 0.4);
}
.oracle-d30__btn--ghost {
  color: rgba(235, 220, 195, 0.78);
  background: transparent;
  border: 1px solid rgba(214, 178, 120, 0.28);
}
.oracle-d30__btn--ghost:hover {
  border-color: rgba(214, 178, 120, 0.5);
  color: #f6e4bd;
}

/* ── Roll stage (compact 3D die) ── */
.oracle-d30__stage {
  position: relative;
  width: 100%;
  height: 200px;
  margin: 0 auto 0.5rem;
}
.oracle-d30__canvas-wrap,
.oracle-d30__gl {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.45));
}

.oracle-d30__holo {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  z-index: 3;
}
.oracle-d30__holo-num {
  font-family: "Cinzel", serif;
  font-size: 2.4rem;
  font-weight: 700;
  color: #f6e4bd;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}
.oracle-d30[data-phase="result"] .oracle-d30__holo-num,
.oracle-d30[data-phase="saved"] .oracle-d30__holo-num {
  color: #ffe9b8;
}

.oracle-d30__rolling {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  color: rgba(230, 196, 138, 0.65);
  margin: 0.25rem 0 0.5rem;
}

/* ── Result panel ── */
.oracle-d30__result {
  margin-top: 0.75rem;
  padding: 1rem 0.85rem;
  border: 1px solid rgba(214, 178, 120, 0.2);
  border-radius: 10px;
  background: rgba(12, 8, 4, 0.45);
  text-align: center;
}
.oracle-d30__result-roll {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  color: rgba(230, 196, 138, 0.65);
  margin-bottom: 0.4rem;
}
.oracle-d30__result-roll b {
  color: #ffe9b8;
  font-size: 1rem;
}
.oracle-d30__result-title {
  font-family: "Cinzel", Georgia, serif;
  font-size: clamp(0.95rem, 3vw, 1.15rem);
  font-weight: 600;
  color: #f6e4bd;
  margin: 0 0 0.4rem;
}
.oracle-d30__result-copy {
  font-size: 0.84rem;
  line-height: 1.5;
  color: rgba(235, 220, 195, 0.8);
  margin-bottom: 0.45rem;
}
.oracle-d30__result-contract {
  font-size: 0.72rem;
  color: rgba(214, 188, 150, 0.55);
  margin-bottom: 0.7rem;
}

.oracle-d30__reopen-note {
  font-family: "Cinzel", Georgia, serif;
  font-size: 0.82rem;
  line-height: 1.45;
  color: rgba(240, 210, 150, 0.88);
  margin: 0 0 0.75rem;
  padding-bottom: 0.55rem;
  border-bottom: 1px solid rgba(214, 178, 120, 0.15);
}
.oracle-d30__notice {
  font-size: 0.78rem;
  line-height: 1.5;
  color: rgba(200, 220, 180, 0.75);
  margin: 0 0 0.65rem;
  padding: 0.5rem 0.6rem;
  border-radius: 8px;
  background: rgba(60, 80, 50, 0.18);
  border: 1px solid rgba(140, 180, 120, 0.15);
}
.oracle-d30__promo-code {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  color: rgba(230, 196, 138, 0.7);
  margin: 0 0 0.65rem;
}
.oracle-d30__promo-code code {
  display: inline-block;
  margin-left: 0.25rem;
  padding: 0.2rem 0.45rem;
  font-size: 0.72rem;
  color: #ffe9b8;
  background: rgba(205, 170, 109, 0.12);
  border: 1px solid rgba(214, 178, 120, 0.28);
  border-radius: 5px;
}

/* Legendary variant — subtly differentiated, still compact. */
.oracle-d30.is-legendary .oracle-d30__card {
  border-color: rgba(243, 215, 154, 0.35);
  box-shadow:
    0 24px 64px rgba(0, 0, 0, 0.55),
    0 0 32px rgba(243, 215, 154, 0.08);
}
.oracle-d30.is-legendary .oracle-d30__result {
  border-color: rgba(243, 215, 154, 0.28);
  background: rgba(28, 18, 6, 0.55);
}
.oracle-d30.is-legendary .oracle-d30__result-title {
  color: #ffe9b8;
}

.oracle-d30__countdown-label {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(230, 196, 138, 0.55);
  margin-bottom: 0.3rem;
}
.oracle-d30__timer {
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: 0.12rem;
  font-family: "JetBrains Mono", monospace;
}
.oracle-d30__timer span { display: flex; flex-direction: column; align-items: center; min-width: 2rem; }
.oracle-d30__timer b { font-size: 1rem; color: #ffd89a; }
.oracle-d30__timer i { font-size: 0.52rem; letter-spacing: 0.06em; color: rgba(230, 196, 138, 0.45); font-style: normal; }
.oracle-d30__sep { color: rgba(230, 196, 138, 0.3); font-size: 0.9rem; padding-bottom: 0.4rem; }

/* ── Rewards map · arcane codex table ── */
.oracle-d30__rewards {
  margin: 0.95rem auto 0;
  max-width: 320px;
  text-align: left;
  border: 1px solid rgba(214, 178, 120, 0.28);
  border-radius: 10px;
  background:
    linear-gradient(180deg, rgba(34, 24, 12, 0.55) 0%, rgba(20, 14, 7, 0.6) 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 220, 160, 0.05);
  overflow: hidden;
}
.oracle-d30__rewards-summary {
  list-style: none;
  cursor: pointer;
  padding: 0.6rem 0.85rem;
  font-family: "Cinzel", Georgia, serif;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: rgba(243, 215, 154, 0.92);
  text-align: center;
  position: relative;
  transition: color 0.2s ease;
}
.oracle-d30__rewards-summary::-webkit-details-marker { display: none; }
.oracle-d30__rewards-summary::after {
  content: "▾";
  margin-left: 0.4rem;
  font-size: 0.7rem;
  color: rgba(214, 178, 120, 0.6);
  transition: transform 0.25s ease;
  display: inline-block;
}
.oracle-d30__rewards[open] .oracle-d30__rewards-summary::after { transform: rotate(180deg); }
.oracle-d30__rewards-summary:hover { color: #f6e4bd; }

.oracle-d30__rewards-table {
  width: 100%;
  border-collapse: collapse;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.7rem;
}
.oracle-d30__rewards-table th {
  padding: 0.4rem 0.85rem;
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(230, 196, 138, 0.6);
  border-top: 1px solid rgba(214, 178, 120, 0.18);
  border-bottom: 1px solid rgba(214, 178, 120, 0.18);
  text-align: left;
}
.oracle-d30__rewards-table td {
  padding: 0.34rem 0.85rem;
  color: rgba(235, 220, 195, 0.82);
  border-bottom: 1px solid rgba(214, 178, 120, 0.08);
}
.oracle-d30__rewards-table tr td:last-child { color: rgba(255, 216, 154, 0.85); text-align: right; }
.oracle-d30__rewards-table tr:last-child td { border-bottom: none; }

.oracle-d30__rewards-legend td {
  color: #ffe9b8 !important;
  font-weight: 600;
  background: linear-gradient(90deg, rgba(243, 215, 154, 0.1) 0%, rgba(205, 170, 109, 0.06) 100%);
}
.oracle-d30__rewards-table tr.is-hit td {
  background: rgba(120, 200, 140, 0.14);
  color: #eaf6e0;
  box-shadow: inset 2px 0 0 rgba(150, 220, 160, 0.7);
}
.oracle-d30__rewards-legend.is-hit td {
  background: linear-gradient(90deg, rgba(255, 220, 140, 0.22) 0%, rgba(255, 200, 110, 0.12) 100%);
  box-shadow: inset 2px 0 0 rgba(255, 220, 140, 0.85);
}

.oracle-d30__actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.85rem;
}
.oracle-d30__btn--contact {
  box-shadow:
    0 4px 18px rgba(205, 170, 109, 0.3),
    0 0 24px rgba(243, 215, 154, 0.12);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
}
.oracle-d30__btn--contact:hover {
  box-shadow:
    0 6px 28px rgba(243, 215, 154, 0.45),
    0 0 36px rgba(243, 215, 154, 0.18);
}
.oracle-d30__channels {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.45rem;
  border-radius: 10px;
  background: rgba(8, 5, 2, 0.45);
  border: 1px solid rgba(214, 178, 120, 0.2);
}
.oracle-d30__btn--channel {
  display: block;
  text-decoration: none;
  text-align: center;
  color: rgba(235, 220, 195, 0.9);
  background: rgba(214, 178, 120, 0.08);
  border: 1px solid rgba(214, 178, 120, 0.25);
}
.oracle-d30__btn--channel:hover {
  background: rgba(214, 178, 120, 0.16);
  border-color: rgba(214, 178, 120, 0.45);
  color: #f6e4bd;
}

/* Contract badge */
.oracle-d30-badge {
  display: block;
  margin: 0.65rem 0 0.5rem;
  padding: 0.35rem 0.65rem;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(245, 228, 189, 0.92);
  background: linear-gradient(90deg, rgba(205, 170, 109, 0.18) 0%, rgba(160, 110, 50, 0.12) 100%);
  border: 1px solid rgba(214, 178, 120, 0.4);
  border-radius: 6px;
  text-align: center;
}
.contract--oracle .contract__book {
  box-shadow:
    0 0 28px rgba(205, 170, 109, 0.14),
    inset 0 0 0 1px rgba(214, 178, 120, 0.2);
}

/* ============================================================
   LEGENDARY LEVEL-UP CELEBRATION (roll 30)
   ------------------------------------------------------------
   RPG-style burst overlaying the card: golden rays sweep, two
   shock rings expand, sparks fly outward and a banner rises +
   settles. Driven by .is-playing (added/removed in dice30.js).
   ============================================================ */
.oracle-d30__levelup {
  position: absolute;
  inset: 0;
  z-index: 6;
  display: grid;
  place-items: center;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
}
.oracle-d30__levelup.is-playing {
  opacity: 1;
  visibility: visible;
}

/* Rotating golden god-rays behind the banner. */
.oracle-d30__levelup-rays {
  position: absolute;
  width: 280px;
  height: 280px;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    rgba(255, 223, 140, 0.0) 0deg,
    rgba(255, 223, 140, 0.35) 12deg,
    rgba(255, 223, 140, 0.0) 24deg,
    rgba(255, 223, 140, 0.0) 36deg,
    rgba(255, 223, 140, 0.3) 48deg,
    rgba(255, 223, 140, 0.0) 60deg
  );
  filter: blur(1px);
  opacity: 0;
  mix-blend-mode: screen;
}
.oracle-d30__levelup.is-playing .oracle-d30__levelup-rays {
  animation: oracle-lu-rays 3.2s ease-out forwards;
}
@keyframes oracle-lu-rays {
  0%   { opacity: 0; transform: scale(0.4) rotate(0deg); }
  18%  { opacity: 0.9; }
  100% { opacity: 0; transform: scale(1.25) rotate(160deg); }
}

/* Expanding shock rings. */
.oracle-d30__levelup-ring {
  position: absolute;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  border: 2px solid rgba(255, 233, 170, 0.9);
  box-shadow: 0 0 24px rgba(255, 220, 150, 0.6);
  opacity: 0;
}
.oracle-d30__levelup.is-playing .oracle-d30__levelup-ring {
  animation: oracle-lu-ring 1.1s cubic-bezier(.22, 1, .36, 1) forwards;
}
.oracle-d30__levelup.is-playing .oracle-d30__levelup-ring--2 {
  animation-delay: 0.22s;
}
@keyframes oracle-lu-ring {
  0%   { opacity: 0.9; transform: scale(0.3); }
  100% { opacity: 0;   transform: scale(3.4); }
}

/* Radial sparks — 12 little shards flung outward. */
.oracle-d30__levelup-sparks {
  position: absolute;
  width: 0;
  height: 0;
}
.oracle-d30__levelup-sparks i {
  position: absolute;
  width: 5px;
  height: 5px;
  margin: -2.5px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff3cf 0%, #ffcf76 60%, transparent 75%);
  opacity: 0;
}
.oracle-d30__levelup.is-playing .oracle-d30__levelup-sparks i {
  animation: oracle-lu-spark 1.2s ease-out forwards;
}
.oracle-d30__levelup-sparks i:nth-child(1)  { --lu-a: 0deg; }
.oracle-d30__levelup-sparks i:nth-child(2)  { --lu-a: 30deg; }
.oracle-d30__levelup-sparks i:nth-child(3)  { --lu-a: 60deg; }
.oracle-d30__levelup-sparks i:nth-child(4)  { --lu-a: 90deg; }
.oracle-d30__levelup-sparks i:nth-child(5)  { --lu-a: 120deg; }
.oracle-d30__levelup-sparks i:nth-child(6)  { --lu-a: 150deg; }
.oracle-d30__levelup-sparks i:nth-child(7)  { --lu-a: 180deg; }
.oracle-d30__levelup-sparks i:nth-child(8)  { --lu-a: 210deg; }
.oracle-d30__levelup-sparks i:nth-child(9)  { --lu-a: 240deg; }
.oracle-d30__levelup-sparks i:nth-child(10) { --lu-a: 270deg; }
.oracle-d30__levelup-sparks i:nth-child(11) { --lu-a: 300deg; }
.oracle-d30__levelup-sparks i:nth-child(12) { --lu-a: 330deg; }
.oracle-d30__levelup-sparks i:nth-child(even) { animation-duration: 1.45s; }
@keyframes oracle-lu-spark {
  0%   { opacity: 0; transform: rotate(var(--lu-a)) translateX(10px) scale(0.6); }
  20%  { opacity: 1; }
  100% { opacity: 0; transform: rotate(var(--lu-a)) translateX(135px) scale(1); }
}

/* The "LEVEL UP" banner rises, overshoots, then settles. */
.oracle-d30__levelup-text {
  position: relative;
  margin: 0;
  font-family: "Cinzel", Georgia, serif;
  font-weight: 700;
  font-size: clamp(1.3rem, 6vw, 2rem);
  letter-spacing: 0.06em;
  text-align: center;
  color: #fff3cf;
  text-shadow:
    0 0 10px rgba(255, 215, 130, 0.9),
    0 0 26px rgba(255, 190, 90, 0.6),
    0 2px 4px rgba(60, 30, 0, 0.7);
  opacity: 0;
}
.oracle-d30__levelup.is-playing .oracle-d30__levelup-text {
  animation: oracle-lu-text 3.2s cubic-bezier(.18, 1.2, .3, 1) forwards;
}
@keyframes oracle-lu-text {
  0%   { opacity: 0; transform: translateY(26px) scale(0.7); }
  14%  { opacity: 1; transform: translateY(-6px) scale(1.12); }
  26%  { transform: translateY(0) scale(1); }
  82%  { opacity: 1; transform: translateY(0) scale(1); }
  100% { opacity: 0; transform: translateY(-10px) scale(1.02); }
}

@media (hover: none) and (pointer: coarse), (max-width: 767px) {
  .oracle-d30__scrim { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .oracle-d30__particles { display: none; }
  .oracle-d30.is-open .oracle-d30__card { animation: none; }
  /* Keep the celebration but lighten it: drop the rotating ray cone
     (the heaviest layer) on small/touch devices. */
  .oracle-d30__levelup-rays { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .oracle-d30,
  .oracle-d30__scrim {
    transition: opacity 0.2s ease !important;
  }
  .oracle-d30__particles { display: none; }
  .oracle-d30.is-open .oracle-d30__card { animation: none; }
  /* Sound still plays via JS; the visual burst is suppressed. */
  .oracle-d30__levelup { display: none; }
}
