<script setup lang="ts">
const { session, restore } = useDngAuth()
const entering = ref(false)
const introSeen = useCookie<string>('dng-first-visit-intro', {
  default: () => '',
  maxAge: 60 * 60 * 24 * 365,
  sameSite: 'lax',
})
const showFirstVisitIntro = ref(introSeen.value !== 'complete')

let introTimer: number | undefined

function finishFirstVisitIntro() {
  showFirstVisitIntro.value = false
  if (introTimer) clearTimeout(introTimer)
  window.removeEventListener('keydown', handleIntroKeydown)
}

function handleIntroKeydown(event: KeyboardEvent) {
  if (event.key === 'Escape') finishFirstVisitIntro()
}

onMounted(() => {
  void restore()
  if (!showFirstVisitIntro.value) return

  // Mark the visit immediately so refreshing or leaving mid-animation cannot
  // trap someone in the intro. The animation state stays local to this page.
  introSeen.value = 'complete'

  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
    finishFirstVisitIntro()
    return
  }

  window.addEventListener('keydown', handleIntroKeydown)
  introTimer = window.setTimeout(finishFirstVisitIntro, 3400)
})

onBeforeUnmount(() => {
  if (introTimer) clearTimeout(introTimer)
  window.removeEventListener('keydown', handleIntroKeydown)
})

async function enterAlpha() {
  if (entering.value) return
  entering.value = true
  try {
    await restore()
    await navigateTo(session.value ? '/dashboard' : '/auth/sign-up')
  } finally {
    entering.value = false
  }
}
</script>

<template>
  <div class="landing noise" :class="{ 'landing--introducing': showFirstVisitIntro }">
    <div v-if="showFirstVisitIntro" class="first-visit-intro" role="dialog" aria-modal="true" aria-labelledby="intro-title">
      <p id="intro-title" class="sr-only">Welcome to Dungeons &amp; Ground</p>
      <div class="intro-grid" aria-hidden="true" />
      <div class="intro-lockup" aria-hidden="true">
        <svg class="intro-wordmark" viewBox="0 0 1120 300" role="img">
          <g class="intro-outline">
            <text x="560" y="122" text-anchor="middle">DUNGEONS</text>
            <text x="560" y="242" text-anchor="middle">&amp; GROUND</text>
          </g>
          <g class="intro-fill">
            <text x="560" y="122" text-anchor="middle">DUNGEONS</text>
            <text x="560" y="242" text-anchor="middle">&amp; GROUND</text>
          </g>
        </svg>
        <span class="intro-rule" />
      </div>
      <button class="intro-skip" type="button" @click="finishFirstVisitIntro">SKIP INTRO <span aria-hidden="true">↗</span></button>
    </div>

    <header class="landing-nav">
      <AppMark />
      <span class="alpha-tag">PRIVATE ALPHA</span>
    </header>

    <main class="hero">
      <section class="hero-copy">
        <p class="eyebrow"><span /> ASYNC AI-POWERED TTRPG</p>
        <h1>STORIES THAT<br><em>WAIT FOR NO ONE.</em></h1>
        <p class="lede">Build an original universe with an AI coauthor. Gather real players and persistent AI companions. Take your turn when life allows—the Groundkeeper remembers everything.</p>
        <div class="hero-actions">
          <button class="btn btn-acid" :disabled="entering" @click="enterAlpha">{{ entering ? 'OPENING…' : session ? 'OPEN DASHBOARD' : 'ENTER THE ALPHA' }} <span>↗</span></button>
          <a href="#how" class="btn btn-ghost">SEE HOW IT WORKS</a>
        </div>
        <div class="trust-row">
          <span>PRIVATE WORLDS</span><i />
          <span>SERVER-OWNED DICE</span><i />
          <span>13+ ADVENTURES</span>
        </div>
      </section>

      <section class="signal-card" aria-label="Live campaign preview">
        <div class="signal-top"><span>LIVE SIGNAL / CAMPAIGN 04</span><b>ROUND 17</b></div>
        <div class="orbit" aria-hidden="true"><i /><i /><i /><span>D&G</span></div>
        <div class="transmission">
          <small>GROUNDKEEPER</small>
          <p>“The voice in the relay is yours—three days from now. It tells you not to open the archive.”</p>
        </div>
        <div class="party-status"><span><b>3</b> HUMANS READY</span><span><b>1</b> AI COMPANION THINKING</span></div>
      </section>
    </main>

    <section id="how" class="how-grid">
      <article><b>01</b><h2>DESCRIBE THE IMPOSSIBLE</h2><p>A coauthor asks sharp questions, then turns your idea into a playable private world.</p></article>
      <article><b>02</b><h2>ASSEMBLE YOUR PARTY</h2><p>Invite friends, add AI companions, and decide who can step in when someone is away.</p></article>
      <article><b>03</b><h2>ACT ON YOUR TIME</h2><p>The Groundkeeper resolves each shared round only when the party is ready.</p></article>
      <aside class="account-card"><b>ACCOUNT REQUIRED</b><h2>KEEP YOUR WORLDS.</h2><p>Register with your name, email, and password. Continue on any device and recover access when needed.</p><div><NuxtLink to="/auth/sign-up">CREATE ACCOUNT →</NuxtLink><NuxtLink to="/auth/sign-in">SIGN IN</NuxtLink></div></aside>
    </section>
  </div>
</template>

<style scoped>
.landing{min-height:100vh;overflow:hidden}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.first-visit-intro{position:fixed;inset:0;z-index:1000;display:grid;place-items:center;overflow:hidden;background:#080808;animation:intro-curtain-away 1.15s cubic-bezier(.76,0,.24,1) 2.15s both;will-change:clip-path,opacity}.intro-grid{position:absolute;inset:-20%;background-image:linear-gradient(rgba(217,247,95,.045) 1px,transparent 1px),linear-gradient(90deg,rgba(217,247,95,.045) 1px,transparent 1px);background-size:clamp(34px,5vw,72px) clamp(34px,5vw,72px);mask-image:radial-gradient(circle at center,#000 0%,transparent 67%);opacity:0;transform:scale(1.08);animation:intro-grid-in 2.2s ease-out both}.intro-lockup{position:relative;width:min(82vw,980px);transform:scale(1.14);animation:intro-lockup-settle 2.1s cubic-bezier(.16,1,.3,1) both;will-change:transform,filter}.intro-wordmark{display:block;width:100%;overflow:visible}.intro-wordmark text{font:600 96px var(--display);letter-spacing:-.065em}.intro-outline text{fill:transparent;stroke:var(--acid);stroke-width:1.35;stroke-dasharray:1450;stroke-dashoffset:1450;paint-order:stroke;animation:intro-outline-draw 1.55s cubic-bezier(.65,0,.35,1) .08s forwards}.intro-fill text{fill:var(--ink);stroke:transparent;opacity:0;animation:intro-fill-in .75s cubic-bezier(.22,1,.36,1) 1.2s forwards}.intro-rule{position:absolute;left:50%;bottom:0;width:min(240px,32vw);height:1px;background:var(--acid);box-shadow:0 0 18px rgba(217,247,95,.7);transform:translateX(-50%) scaleX(0);animation:intro-rule-grow 1.25s cubic-bezier(.16,1,.3,1) .35s forwards}.intro-skip{position:absolute;right:clamp(20px,4vw,58px);bottom:clamp(20px,4vw,48px);padding:10px 0;border:0;background:transparent;color:var(--muted);font:500 9px var(--mono);letter-spacing:.16em;opacity:0;animation:intro-skip-in .45s ease-out .55s forwards}.intro-skip span{margin-left:8px;color:var(--acid)}.landing--introducing>.landing-nav,.landing--introducing>.hero,.landing--introducing>.how-grid{animation:homepage-reveal 1.15s cubic-bezier(.16,1,.3,1) 2.1s both;will-change:transform,opacity,filter}@keyframes intro-outline-draw{0%{stroke-dashoffset:1450;opacity:0}12%{opacity:1}100%{stroke-dashoffset:0;opacity:1}}@keyframes intro-fill-in{0%{opacity:0}100%{opacity:1}}@keyframes intro-lockup-settle{0%{transform:scale(1.14);filter:blur(5px)}18%{filter:blur(0)}100%{transform:scale(1);filter:blur(0)}}@keyframes intro-rule-grow{to{transform:translateX(-50%) scaleX(1)}}@keyframes intro-grid-in{0%{opacity:0;transform:scale(1.08)}55%{opacity:.8}100%{opacity:.35;transform:scale(1)}}@keyframes intro-skip-in{to{opacity:1}}@keyframes intro-curtain-away{0%{clip-path:inset(0 0 0 0);opacity:1}75%{opacity:1}100%{clip-path:inset(0 0 100% 0);opacity:.12;visibility:hidden}}@keyframes homepage-reveal{0%{opacity:0;transform:translateY(18px) scale(.995);filter:blur(7px)}100%{opacity:1;transform:translateY(0) scale(1);filter:blur(0)}}.landing-nav{height:90px;padding:0 clamp(22px,6vw,90px);display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line)}.alpha-tag{font:500 9px var(--mono);letter-spacing:.18em;border:1px solid var(--line);padding:10px 14px;color:var(--muted)}.hero{min-height:680px;padding:72px clamp(22px,6vw,90px) 60px;display:grid;grid-template-columns:minmax(0,1.15fr) minmax(360px,.85fr);gap:7vw;align-items:center}.eyebrow{font:500 10px var(--mono);letter-spacing:.22em;color:var(--muted)}.eyebrow span{display:inline-block;width:26px;height:1px;background:var(--acid);vertical-align:middle;margin-right:10px}.hero h1{margin:22px 0 28px;font:600 clamp(52px,6.6vw,108px)/.91 var(--display);letter-spacing:-.07em}.hero h1 em{font-style:normal;color:transparent;-webkit-text-stroke:1px var(--acid)}.lede{max-width:650px;font-size:clamp(16px,1.5vw,20px);line-height:1.7;color:#b9b9b2}.hero-actions{display:flex;gap:12px;margin-top:38px}.btn{min-height:52px;padding:0 22px;border:1px solid var(--line);font:600 10px var(--mono);letter-spacing:.13em;text-decoration:none;display:inline-flex;align-items:center;justify-content:center;gap:20px}.btn:disabled{opacity:.7;cursor:wait}.btn-acid{border-color:var(--acid);background:var(--acid);color:#080808}.btn-ghost{color:var(--ink);background:transparent}.trust-row{display:flex;align-items:center;gap:14px;margin-top:42px;font:500 8px var(--mono);letter-spacing:.16em;color:var(--muted)}.trust-row i{width:3px;height:3px;background:var(--acid);border-radius:50%}.signal-card{position:relative;min-height:510px;border:1px solid var(--line);background:linear-gradient(145deg,#111 0%,#090909 60%);box-shadow:0 40px 120px #000;padding:22px;clip-path:polygon(0 0,calc(100% - 20px) 0,100% 20px,100% 100%,20px 100%,0 calc(100% - 20px))}.signal-top,.party-status{display:flex;justify-content:space-between;font:500 8px var(--mono);letter-spacing:.13em;color:var(--muted)}.signal-top b{color:var(--acid)}.orbit{position:relative;width:245px;height:245px;margin:48px auto 30px;border:1px solid #2b2b29;border-radius:50%;display:grid;place-items:center}.orbit:before,.orbit:after{content:"";position:absolute;border:1px solid #262624;border-radius:50%;inset:28px}.orbit:after{inset:61px;border-color:var(--acid-dim)}.orbit i{position:absolute;width:7px;height:7px;border-radius:50%;background:var(--acid);box-shadow:0 0 18px var(--acid)}.orbit i:nth-child(1){top:23px;left:52px}.orbit i:nth-child(2){right:-3px;top:113px}.orbit i:nth-child(3){bottom:20px;left:85px}.orbit span{font:600 28px var(--display);color:var(--acid)}.transmission{border-left:2px solid var(--acid);padding:8px 18px;margin:0 12px 34px}.transmission small{font:500 8px var(--mono);letter-spacing:.18em;color:var(--acid)}.transmission p{font:500 15px/1.6 var(--body);color:#d6d6d0}.party-status{padding:18px 12px 0;border-top:1px solid var(--line)}.party-status b{color:var(--acid)}.how-grid{display:grid;grid-template-columns:repeat(3,1fr) 1.2fr;border-top:1px solid var(--line)}.how-grid article,.account-card{min-height:215px;padding:34px;border-right:1px solid var(--line)}.how-grid article>b,.account-card>b{font:500 9px var(--mono);color:var(--acid)}.how-grid h2{margin:34px 0 12px;font:600 13px var(--display);letter-spacing:-.03em}.how-grid p{font-size:12px;line-height:1.6;color:var(--muted)}.account-card{display:flex;flex-direction:column}.account-card h2{margin-top:25px}.account-card div{display:flex;gap:14px;margin-top:auto}.account-card a{color:var(--muted);font:600 8px var(--mono);text-decoration:none}.account-card a:first-child{color:var(--acid)}@media(max-width:950px){.hero{grid-template-columns:1fr}.signal-card{max-width:620px}.how-grid{grid-template-columns:1fr 1fr}}@media(max-width:620px){.intro-lockup{width:92vw}.intro-wordmark text{font-size:82px}.intro-skip{right:20px;bottom:18px}.alpha-tag{display:none}.hero{padding-top:50px}.hero h1{font-size:48px}.hero-actions{flex-direction:column}.trust-row{flex-wrap:wrap}.signal-card{min-height:470px}.how-grid{grid-template-columns:1fr}.how-grid article,.account-card{border-bottom:1px solid var(--line)}}@media(prefers-reduced-motion:reduce){.first-visit-intro{display:none}.landing--introducing>.landing-nav,.landing--introducing>.hero,.landing--introducing>.how-grid{animation:none;opacity:1;transform:none;filter:none}}
</style>
