/* ============================================================
   Gjallarhorn — teaser
   Palette pulled from the emblem: brass, violet banner, void.
   ============================================================ */

:root{
  --void:        #07050e;
  --void-2:      #0d0a1c;
  --violet:      #4a2f7a;
  --violet-lit:  #7b5bc4;
  --brass:       #d9a441;
  --brass-lit:   #f2d18a;
  --crimson:     #7c2230;
  --ink:         #cfc6de;
  --ink-dim:     #8b83a3;

  --serif:  "Cormorant Garamond", "Iowan Old Style", Georgia, serif;
  --display:"Cinzel", "Trajan Pro", var(--serif);

  --gutter: clamp(1.25rem, 5vw, 4rem);
}

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

html,body{ height:100%; }

body{
  margin:0;
  background:var(--void);
  color:var(--ink);
  font-family:var(--serif);
  font-size:clamp(16px,1.05vw + 13px,20px);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow:hidden;
  display:grid;
  grid-template-rows:1fr auto;
}

/* ---------------- background stack ---------------- */

.void{ position:fixed; inset:0; z-index:0; overflow:hidden; }
.layer{ position:absolute; inset:-4%; background-repeat:no-repeat; }

/* base gradient — always present, so the page never looks broken
   before the wallpaper art is dropped in. */
.sky{
  background:
    radial-gradient(120% 80% at 50% 108%, rgba(122,74,168,.30), transparent 62%),
    radial-gradient(90%  70% at 50% -18%, rgba(60,42,120,.42),  transparent 66%),
    linear-gradient(180deg, #05040b 0%, var(--void-2) 46%, #120a1c 100%);
}

/* slow-turning aurora / godlight */
.aurora{
  background:
    conic-gradient(from 200deg at 50% 120%,
      transparent 0deg,
      rgba(123,91,196,.16) 40deg,
      transparent 90deg,
      rgba(217,164,65,.10) 150deg,
      transparent 220deg);
  filter:blur(40px);
  mix-blend-mode:screen;
  animation:turn 90s linear infinite;
  opacity:.35;
}
@keyframes turn{ to{ transform:rotate(360deg); } }

/* ── WALLPAPER SLOTS ─────────────────────────────────────────
   Drop art here and it layers in automatically. Both are
   optional; missing files just fall through to the gradient.
   horizon → distant sky / mountains / floating island (2560×1440)
   ruins   → foreground silhouette, transparent PNG (2560×1200)
   ──────────────────────────────────────────────────────────── */
.horizon{
  /* Content negotiation happens in the browser: it picks the first type
     it can decode and fetches ONLY that one. The bare url() above the
     image-set() is the fallback for engines too old to parse it.
       avif 137 KB  ·  webp 350 KB  ·  jpg 1323 KB
     Regenerate with the ffmpeg commands in assets/bg/README.md. */
  background-image:url("/assets/bg/horizon.jpg");
  background-image:image-set(
      url("/assets/bg/horizon.avif") type("image/avif"),
      url("/assets/bg/horizon.webp") type("image/webp"),
      url("/assets/bg/horizon.jpg")  type("image/jpeg"));
  opacity:0;
  transition:opacity 1.6s ease;
  background-size:cover;
  background-position:50% 42%;   /* keeps the crown and the horizon band both in frame */
  /* the art is already lit — pull it down into the void rather than
     blending it, so the blacks stay black and the gold stays gold. */
  filter:brightness(.58) saturate(.88) contrast(1.06);
}
.art-ready .horizon{ opacity:1; }

/* Foreground silhouette slot. The current horizon art carries its own
   platform, so this is off. Re-enable only if the art is swapped for
   one with an empty base. */
.ruins{ display:none; }

/* drifting ground fog */
.mist{
  inset:auto -20% -10% -20%;
  height:60%;
  background:
    radial-gradient(60% 100% at 20% 100%, rgba(150,130,200,.13), transparent 70%),
    radial-gradient(70% 100% at 78% 100%, rgba(120,100,180,.11), transparent 70%);
  filter:blur(26px);
  opacity:.75;
  animation:drift 46s ease-in-out infinite alternate;
}
@keyframes drift{ from{ transform:translateX(-4%); } to{ transform:translateX(4%); } }

#embers{ position:absolute; inset:0; width:100%; height:100%; }

/* Scrim — the reading surface. Two jobs: kill the sunset band's
   luminance behind the copy, and sink the edges into the void so the
   photo has no visible border. */
.vignette{
  position:absolute; inset:0;
  background:
    /* pool of shade behind the emblem + headline */
    radial-gradient(46% 42% at 50% 44%, rgba(6,4,14,.82) 0%, rgba(6,4,14,.45) 55%, transparent 78%),
    /* top and bottom falloff */
    linear-gradient(180deg, rgba(5,4,11,.80) 0%, transparent 26%, transparent 58%, rgba(5,3,12,.92) 100%),
    /* edge vignette */
    radial-gradient(84% 70% at 50% 46%, transparent 42%, rgba(3,2,8,.80) 100%);
}

/* film grain — pure CSS, no asset */
.grain{
  position:absolute; inset:-100%;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/>\
<feColorMatrix type='saturate' values='0'/></filter>\
<rect width='140' height='140' filter='url(%23n)' opacity='.42'/></svg>");
  opacity:.05;
  mix-blend-mode:overlay;
  animation:shift .7s steps(3) infinite;
  pointer-events:none;
}
@keyframes shift{
  0%  { transform:translate(0,0); }
  33% { transform:translate(-2%,1%); }
  66% { transform:translate(1%,-2%); }
}

/* ---------------- content ---------------- */

main{
  position:relative; z-index:1;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:1.6rem;
  padding:var(--gutter);
  text-align:center;
  animation:rise 1.9s cubic-bezier(.16,1,.3,1) both;
}
@keyframes rise{
  from{ opacity:0; transform:translateY(18px); filter:blur(6px); }
  to  { opacity:1; transform:none;             filter:none; }
}

/* the emblem */
.crest{
  position:relative;
  width:clamp(110px,16vh,170px);
  aspect-ratio:1;
  display:grid; place-items:center;
  animation:breathe 7s ease-in-out infinite;
}
@keyframes breathe{
  0%,100%{ transform:translateY(0)     scale(1); }
  50%    { transform:translateY(-7px)  scale(1.015); }
}
.crest img{
  position:relative;
  width:100%; height:100%;
  object-fit:contain;
  /* tight dark rim first, then the warm bloom — reads cleanly against
     the tree trunk instead of dissolving into it. */
  filter:drop-shadow(0 0 2px rgba(4,2,10,.95))
         drop-shadow(0 0 30px rgba(217,164,65,.38))
         drop-shadow(0 16px 38px rgba(0,0,0,.85));
}
.halo{
  position:absolute; inset:-38%;
  background:radial-gradient(circle, rgba(217,164,65,.20) 0%, rgba(123,91,196,.14) 38%, transparent 68%);
  filter:blur(8px);
  animation:flare 7s ease-in-out infinite;
}
@keyframes flare{ 0%,100%{opacity:.55;} 50%{opacity:1;} }

/* ornamental divider */
.rule{
  display:flex; align-items:center; gap:.85rem;
  width:min(320px,62vw);
  opacity:.7;
}
.rule span{
  flex:1; height:1px;
  background:linear-gradient(90deg,transparent,rgba(217,164,65,.55));
}
.rule span:last-child{ transform:scaleX(-1); }
.rule i{
  width:5px; height:5px;
  background:var(--brass);
  transform:rotate(45deg);
  box-shadow:0 0 10px rgba(217,164,65,.8);
}

h1{
  margin:0;
  font-family:var(--display);
  font-weight:400;
  font-size:clamp(1.5rem,4.4vw,3.15rem);
  line-height:1.18;
  letter-spacing:.06em;
  text-transform:uppercase;
  background:linear-gradient(180deg,#fff6e2 0%,var(--brass-lit) 46%,#a8762a 100%);
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  text-shadow:0 0 46px rgba(217,164,65,.18);
}

.lede{
  margin:0;
  max-width:34ch;
  font-size:clamp(1rem,1.5vw,1.25rem);
  font-weight:300;
  font-style:italic;
  color:var(--ink);
  opacity:.82;
}

.stamp{
  margin:.2rem 0 0;
  font-family:var(--display);
  font-size:.62rem;
  letter-spacing:.42em;
  text-transform:uppercase;
  color:var(--ink-dim);
  opacity:.7;
}

/* ---------------- actions ---------------- */

.links{ display:flex; align-items:center; gap:1.4rem; flex-wrap:wrap; justify-content:center; margin-top:.4rem; }

.btn{
  position:relative;
  display:inline-block;
  padding:.72em 2.1em;
  font-family:var(--display);
  font-size:.72rem;
  letter-spacing:.24em;
  text-transform:uppercase;
  text-decoration:none;
  color:var(--brass-lit);
  border:1px solid rgba(217,164,65,.34);
  background:linear-gradient(180deg, rgba(74,47,122,.30), rgba(10,7,20,.55));
  backdrop-filter:blur(3px);
  transition:color .35s, border-color .35s, box-shadow .45s, transform .35s;
}
/* corner ticks */
.btn::before,.btn::after{
  content:""; position:absolute; width:7px; height:7px;
  border:1px solid rgba(217,164,65,.7);
  transition:inset .35s, opacity .35s;
  opacity:.55;
}
.btn::before{ top:-1px; left:-1px;  border-right:0; border-bottom:0; }
.btn::after { bottom:-1px; right:-1px; border-left:0;  border-top:0; }
.btn:hover{
  color:#fff6e2;
  border-color:rgba(217,164,65,.75);
  box-shadow:0 0 30px rgba(217,164,65,.18), inset 0 0 22px rgba(123,91,196,.22);
  transform:translateY(-1px);
}
.btn:hover::before,.btn:hover::after{ opacity:1; }

.ghost{
  font-family:var(--display);
  font-size:.68rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ink-dim); text-decoration:none;
  border-bottom:1px solid transparent;
  transition:color .3s, border-color .3s;
}
.ghost:hover{ color:var(--brass); border-color:rgba(217,164,65,.4); }

/* transient "soon" feedback */
.btn.said{ pointer-events:none; color:var(--ink-dim); border-color:rgba(139,131,163,.3); }

/* ---------------- footer ---------------- */

footer{
  position:relative; z-index:1;
  padding:0 var(--gutter) calc(var(--gutter) * .7);
  display:flex; align-items:center; justify-content:center; gap:.6em;
  font-family:var(--display);
  font-size:.58rem; letter-spacing:.34em; text-transform:uppercase;
  color:var(--ink-dim); opacity:.45;
}
.pulse{
  width:5px; height:5px; border-radius:50%;
  background:var(--brass);
  box-shadow:0 0 8px var(--brass);
  animation:beat 3.2s ease-in-out infinite;
}
@keyframes beat{ 0%,100%{opacity:.25;} 50%{opacity:1;} }

/* ---------------- responsive / a11y ---------------- */

@media (max-width:600px){
  main{ gap:1.25rem; }
  .lede br{ display:none; }
  footer{ letter-spacing:.22em; }
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation:none !important; transition-duration:.01ms !important; }
  main{ opacity:1; }
}
