/* Land of Ancients — landofancients.com
   One page. A full-bleed hero carrying the wordmark, and one band below it explaining
   what the game is. Everything is dark; the only saturated colour on the page is the
   gold of the type and the amber of the relic, which is what makes them read as precious.

   Fonts are self-hosted subsets — see get_fonts.py. Images are generated — see
   make_assets.py. Neither is hand-edited. */

/* ---------- fonts ---------------------------------------------------------------- */

@font-face {
  font-family: 'Cinzel';
  src: url('../fonts/Cinzel.woff2') format('woff2-variations'),
       url('../fonts/Cinzel.woff2') format('woff2');
  font-weight: 400 900;
  font-display: block;          /* the wordmark is the page — never flash a fallback for it */
  font-style: normal;
}
@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter.woff2') format('woff2-variations'),
       url('../fonts/Inter.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;           /* small copy can afford to swap */
  font-style: normal;
}

/* ---------- tokens --------------------------------------------------------------- */

:root {
  --ink:      #0a0c0f;
  --ink-2:    #0d1116;
  --ink-3:    #12171f;
  --gold:     #d6ad6a;
  --gold-hi:  #f5dba0;
  --amber:    #e8982e;
  --text:     #e7e9ed;
  --muted:    #969ca7;
  --dim:      #6d747f;
  --line:     rgba(214, 173, 106, .22);
  --wrap:     1140px;
  --display:  'Cinzel', 'Trajan Pro', Georgia, 'Times New Roman', serif;
  --body:     'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
}

/* ---------- base ----------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--gold); text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--gold-hi);
  outline-offset: 3px;
  border-radius: 2px;
}

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; }

/* ---------- hero ----------------------------------------------------------------- */

.hero {
  position: relative;
  /* svh, so the fold is not cut off by a mobile browser's collapsing address bar.
     dvh would resize the hero every time that bar moves, which reflows the wordmark
     mid-scroll; svh picks the small height once and stays there. */
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  /* minmax(0, 1fr), NOT the implicit `auto` track. An auto track sizes to its item's
     MAX-CONTENT and is allowed to overflow its container, so on a phone the single-line
     max-content width of the wordmark blew the track out to ~600px and the title was
     clipped off the right edge — width:100% on the item does not help, because 100%
     then resolves against the oversized track. minmax(0, 1fr) caps the track instead. */
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: 96px 24px 120px;
  overflow: hidden;
  isolation: isolate;
}

.hero-bg {
  position: absolute;
  /* Inset NEGATIVE, so the slow scale below never exposes an edge. */
  inset: -3%;
  z-index: -3;
  background-image: url('../img/hero.jpg'), url('../img/hero-tiny.jpg');
  background-size: cover;
  background-position: 58% 50%;
  background-repeat: no-repeat;
  transform: scale(1.02);
  animation: drift 48s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes drift {
  from { transform: scale(1.02) translate3d(0, 0, 0); }
  to   { transform: scale(1.11) translate3d(-1.2%, -1%, 0); }
}

/* The scrim. Two gradients: a radial one that pools darkness behind the type, and a
   linear one that seals the top and fades the bottom into the section below, so the
   hero and the dark band under it read as one surface with no visible seam. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(118% 86% at 50% 44%,
      rgba(7, 9, 12, .20) 0%, rgba(7, 9, 12, .58) 46%, rgba(7, 9, 12, .88) 100%),
    linear-gradient(180deg,
      rgba(7, 9, 12, .74) 0%, rgba(7, 9, 12, .26) 26%,
      rgba(7, 9, 12, .48) 64%, var(--ink) 100%);
}

/* ⚠ width/height 100% are REQUIRED, not belt-and-braces. <canvas> is a REPLACED
   element, so for an absolutely positioned one `width: auto` resolves to the intrinsic
   size and the `right`/`bottom` halves of `inset: 0` are simply dropped — the canvas
   lays out at its default 300x150 in the corner and the embers draw into a postage
   stamp. Measured: getBoundingClientRect() was exactly 300x150 with inset:0 alone. */
.motes {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

/* Film grain. Without it a heavily darkened JPEG gradient bands visibly on wide
   gradients like the sky above; the noise breaks the bands up. */
.grain {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .11;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
}

/* width:100% IS LOAD-BEARING. `place-items: center` on the grid makes this item size to
   its CONTENT, and max-content for the wordmark is wider than a phone - so without it the
   title does not wrap, it overflows and is clipped off the right edge. The max-width
   still caps the column on desktop. */
.hero-inner { width: 100%; max-width: 1120px; text-align: center; }

.eyebrow {
  /* Top of the stack now that there is no mark above it — the extra breathing room
     that used to sit under the emblem moves here so the block stays optically centred. */
  margin: 0 0 clamp(18px, 2.6vw, 26px);
  font-size: clamp(.6rem, 1.5vw, .74rem);
  font-weight: 500;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: #a9afba;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .85);
  /* The tracking above adds a trailing gap after the last letter that visually
     un-centres the line; pushing the line over by the same amount re-centres it. */
  text-indent: .34em;
}
.eyebrow i {
  display: inline-block;
  width: 3px; height: 3px;
  margin: 0 .95em .18em;
  background: var(--gold);
  transform: rotate(45deg);
  opacity: .75;
}

.wordmark {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  /* Topped out so "LAND OF ANCIENTS" sets on ONE line inside .hero-inner at desktop
     widths — at 8vw it broke after "OF", which reads as an accident rather than a
     decision. Below ~700px it wraps to two lines on purpose and that looks right. */
  font-size: clamp(1.95rem, 6.4vw, 5.6rem);
  line-height: 1.08;
  letter-spacing: .1em;
  text-indent: .1em;                 /* same trailing-space correction as .eyebrow */
  text-transform: uppercase;
  color: var(--gold-hi);
  filter: drop-shadow(0 4px 34px rgba(0, 0, 0, .75));
}

/* Gilding: light off the top bevel, shadow in the counters. Gated, because without
   background-clip the transparent fill would erase the wordmark entirely. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .wordmark {
    background-image: linear-gradient(178deg,
      #fdf3d8 0%, #f6e0ad 30%, #dcb475 58%, #bd9152 82%, #a97f45 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: clamp(26px, 3.4vw, 40px) auto clamp(22px, 2.8vw, 30px);
  max-width: 380px;
}
.rule i {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold));
  opacity: .8;
}
.rule i:last-child { background: linear-gradient(90deg, var(--gold), transparent); }
.rule span {
  width: 7px; height: 7px;
  background: var(--gold-hi);
  transform: rotate(45deg);
  box-shadow: 0 0 12px rgba(232, 152, 46, .55);
}

.soon {
  margin: 0;
  font-size: clamp(.92rem, 2.4vw, 1.28rem);
  font-weight: 400;
  letter-spacing: .46em;
  text-indent: .46em;
  text-transform: uppercase;
  color: #eef0f4;
  /* The valley behind this line is the brightest part of the photograph. Without a
     shadow the thin, widely tracked caps sit right on top of the lit river and lose. */
  text-shadow: 0 2px 22px rgba(0, 0, 0, .92), 0 0 6px rgba(0, 0, 0, .6);
}

.register {
  margin: clamp(26px, 3.2vw, 38px) 0 0;
  font-size: clamp(.78rem, 1.8vw, .88rem);
  letter-spacing: .04em;
  color: #b3b9c3;
  text-shadow: 0 1px 16px rgba(0, 0, 0, .9);
}
.register a {
  color: var(--gold);
  border-bottom: 1px solid rgba(214, 173, 106, .38);
  padding-bottom: 1px;
  transition: color .25s ease, border-color .25s ease;
  white-space: nowrap;
}
.register a:hover { color: var(--gold-hi); border-bottom-color: var(--gold-hi); }

.cue {
  position: absolute;
  left: 50%;
  bottom: clamp(22px, 4vh, 46px);
  translate: -50% 0;
  width: 42px; height: 42px;
  display: grid;
  place-items: center;
  color: var(--gold);
  opacity: .5;
  transition: opacity .25s ease;
}
.cue:hover { opacity: 1; }
.cue svg {
  width: 22px; height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  animation: bob 2.6s ease-in-out infinite;
}
@keyframes bob {
  0%, 100% { transform: translateY(-3px); }
  50%      { transform: translateY(3px); }
}

/* ---------- the band below the fold ---------------------------------------------- */

.realm {
  position: relative;
  /* Contains the relic's glow, which is an absolutely positioned box inset -14% and so
     is WIDER than the figure it sits behind. On a phone that pushed the document's
     scrollWidth 24px past the viewport — invisible, because body clips the overflow,
     but real: measured 414px of scroll width in a 390px viewport. Clipping it here
     costs nothing, as the glow is a soft radial that fades out before the edge anyway. */
  overflow: hidden;
  padding: clamp(76px, 10vw, 148px) 24px clamp(66px, 8vw, 120px);
  background:
    radial-gradient(90% 60% at 22% 30%, rgba(232, 152, 46, .07) 0%, transparent 62%),
    linear-gradient(180deg, var(--ink) 0%, var(--ink-2) 55%, var(--ink) 100%);
}

.realm .wrap {
  display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  gap: clamp(40px, 6vw, 90px);
  align-items: center;
}

.relic { margin: 0; position: relative; }
.relic::before {
  content: '';
  position: absolute;
  inset: -14%;
  background: radial-gradient(closest-side, rgba(232, 152, 46, .22), transparent 72%);
  filter: blur(14px);
  z-index: 0;
}
.relic img {
  position: relative;
  z-index: 1;
  width: 100%;
  border-radius: 4px;
  border: 1px solid var(--line);
  box-shadow: 0 26px 70px rgba(0, 0, 0, .62);
}

.kicker {
  margin: 0 0 14px;
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--gold);
  opacity: .85;
}

.realm h2 {
  margin: 0 0 22px;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.7rem, 4.1vw, 2.9rem);
  line-height: 1.16;
  letter-spacing: .035em;
  color: var(--gold-hi);
}

.lead {
  margin: 0 0 clamp(30px, 4vw, 42px);
  font-size: clamp(.95rem, 1.5vw, 1.06rem);
  color: var(--muted);
  max-width: 58ch;
}

.pillars {
  list-style: none;
  margin: 0 0 clamp(32px, 4vw, 44px);
  padding: 0;
  display: grid;
  gap: 26px;
}
.pillars li { position: relative; padding-left: 26px; }
.pillars li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .62em;
  width: 7px; height: 7px;
  background: var(--gold);
  transform: rotate(45deg);
}
.pillars h3 {
  margin: 0 0 6px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.02rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text);
}
.pillars p {
  margin: 0;
  font-size: .93rem;
  color: var(--dim);
  max-width: 54ch;
}

.cta { margin: 0; }
.btn {
  display: inline-block;
  padding: 14px 30px;
  font-size: .76rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold-hi);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(214, 173, 106, .10), rgba(214, 173, 106, .03));
  transition: border-color .25s ease, background .25s ease, color .25s ease,
              transform .25s ease;
}
.btn:hover {
  color: #1a1207;
  border-color: var(--gold-hi);
  background: linear-gradient(180deg, var(--gold-hi), var(--gold));
  transform: translateY(-1px);
}

/* ---------- footer --------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid rgba(255, 255, 255, .06);
  padding: clamp(38px, 5vw, 56px) 24px clamp(34px, 4vw, 46px);
  background: var(--ink);
  text-align: center;
}
/* The Elemental Legion wordmark, linked back to the studio. Sized by the LINK rather
   than the image so the tap target and the artwork are the same box. */
.site-footer .el-logo {
  display: inline-block;
  /* Sized off the "LEGION" lettering inside the bolt, not off the wordmark. That text is
     tiny relative to the 800px artwork, and below ~200px it stops being readable and the
     mark just looks like an orange smudge. Elemental Legion's own header runs it at ~229px
     wide (height:30px); a footer signature carries a little more. */
  width: clamp(200px, 28vw, 288px);
  margin: 0 auto 20px;
  opacity: .9;
  transition: opacity .25s ease;
}
.site-footer .el-logo:hover,
.site-footer .el-logo:focus-visible { opacity: 1; }
.site-footer .el-logo img { width: 100%; height: auto; }
.site-footer .by {
  margin: 0 0 12px;
  font-size: .86rem;
  color: var(--muted);
}
.site-footer .by a {
  border-bottom: 1px solid rgba(214, 173, 106, .35);
  transition: color .25s ease, border-color .25s ease;
}
.site-footer .by a:hover { color: var(--gold-hi); border-bottom-color: var(--gold-hi); }
.site-footer .legal {
  margin: 0 auto;
  max-width: 74ch;
  font-size: .7rem;
  line-height: 1.7;
  color: #5b626c;
}

/* ---------- entrance ------------------------------------------------------------- */

/* ⚠ THE HIDDEN STATE IS GATED ON `.js`, WHICH IS THE WHOLE POINT. `.reveal` on its own
   does nothing: an element is only hidden once the inline bootstrap in <head> has put
   `js` on <html>. Write it the other way round — hide by default, reveal from script —
   and any load where the JS 404s or is blocked shows a page that is entirely blank.
   The bootstrap is inline and synchronous, so there is no flash of the un-hidden state. */
.js .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .9s cubic-bezier(.22, .61, .36, 1) var(--d, 0ms),
              transform .9s cubic-bezier(.22, .61, .36, 1) var(--d, 0ms);
}
/* `.in` is added to a SECTION — the hero on load, the band below when it scrolls up. */
.js .in .reveal { opacity: 1; transform: none; }

/* ---------- responsive ----------------------------------------------------------- */

@media (max-width: 900px) {
  .realm .wrap { grid-template-columns: 1fr; }
  .relic { max-width: 420px; margin-inline: auto; }
  .realm-copy { text-align: center; }
  .lead, .pillars p { margin-inline: auto; }
  .pillars li { padding-left: 0; padding-top: 20px; }
  .pillars li::before { left: 50%; top: 0; translate: -50% 0; }
}

@media (max-width: 720px) {
  .hero-bg {
    background-image: url('../img/hero-mobile.jpg'), url('../img/hero-tiny.jpg');
    background-position: 50% 42%;
  }
  .hero { padding: 80px 20px 104px; }
  .eyebrow i { margin: 0 .6em .18em; }
}

@media (max-width: 420px) {
  /* Three tracked words will not fit one phone line; stacking beats a ragged wrap. */
  .eyebrow i { display: block; margin: 8px auto; }
  .eyebrow { line-height: 1.9; }
}

/* ---------- motion / contrast preferences ---------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero-bg { animation: none; transform: scale(1.02); }
  .cue svg { animation: none; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  * { transition-duration: .01ms !important; }
}

@media (prefers-contrast: more) {
  .hero::after {
    background:
      radial-gradient(118% 86% at 50% 44%,
        rgba(7, 9, 12, .55) 0%, rgba(7, 9, 12, .80) 46%, rgba(7, 9, 12, .95) 100%),
      linear-gradient(180deg, rgba(7, 9, 12, .85) 0%, rgba(7, 9, 12, .55) 26%,
        rgba(7, 9, 12, .70) 64%, var(--ink) 100%);
  }
  .eyebrow, .pillars p { color: #c6ccd5; }
}
