/* ===============================================================
   SARVUN - splash
   Obsidian, platinum, struck gold. One screen, no scroll.
   =============================================================== */

/* -- tokens ---------------------------------------------------- */
:root{
  --obsidian:   #07070a;
  --obsidian-2: #0b0b11;
  --platinum:   #c6cad1;
  --platinum-2: #7e838c;
  --platinum-3: #4a4e57;
  --gold:       #c9a45c;
  --gold-hi:    #f4e6c4;
  --gold-lo:    #7d5f2b;

  /* the metal ramp: the dark "horizon" band at 49-56% is what reads as metal */
  --metal: linear-gradient(176deg,
    #fffaf0 0%, #f2dfb4 13%, #d3ae68 31%,
    #9c7a3a 49%, #7a5c29 56%,
    #c9a45c 68%, #f4e6c4 85%, #ab8a49 100%);

  --ls-word: .155em;
  --pad: clamp(14px, 2.1vw, 32px);

  /* live pointer state, written by main.js */
  --spot: 300px;
  --wake: 0;            /* 0 before the first pointer move, 1 after */

  --ease-out: cubic-bezier(.16,1,.3,1);
}

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

html,body{height:100%;margin:0}
html{background:var(--obsidian)}

body{
  min-height:100%;
  overflow:hidden;                      /* it is a splash - nothing to scroll to */
  background:
    radial-gradient(120% 90% at 50% 6%, #14141c 0%, #0a0a10 42%, var(--obsidian) 78%),
    var(--obsidian);
  color:var(--platinum);
  font-family:'Jost', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-weight:300;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

img{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;margin:0}

::selection{background:rgba(201,164,92,.26);color:#fff}

/* Parallax layers. main.js writes `transform` on these directly rather than
   going through an inherited custom property on :root - a per-frame custom
   property change on the root invalidates style for the whole document. */
.par{will-change:transform}

/* -- atmosphere ------------------------------------------------ */
.atmos{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.atmos > *{position:absolute}

/* slow conic shaft of light behind everything.
   The stops are wide and soft on purpose - a filter:blur() here would mean
   re-blurring a multi-thousand-pixel layer on every frame of the rotation. */
.atmos__sweep{
  top:50%;left:50%;width:104vmax;height:104vmax;
  margin:-52vmax 0 0 -52vmax;
  background:conic-gradient(from 0deg,
    rgba(201,164,92,0) 0deg,    rgba(201,164,92,.05) 34deg,
    rgba(201,164,92,.07) 52deg, rgba(201,164,92,0) 96deg,
    rgba(198,202,209,0) 140deg, rgba(198,202,209,.038) 178deg,
    rgba(198,202,209,0) 216deg, rgba(201,164,92,0) 266deg,
    rgba(201,164,92,.05) 306deg, rgba(201,164,92,0) 348deg,
    rgba(201,164,92,0) 360deg);
  opacity:.8;
  animation:spin 96s linear infinite;
}
@keyframes spin{to{transform:rotate(1turn)}}

/* pool of warm light that tracks the cursor.
   Static gradient, fixed size, moved by transform only - see main.js. */
.lamp{
  top:0;left:0;
  width:86vmax;height:86vmax;
  margin:-43vmax 0 0 -43vmax;
  background:radial-gradient(circle closest-side,
    rgba(201,164,92,.13) 0%, rgba(201,164,92,.05) 36%,
    rgba(201,164,92,.014) 60%, transparent 76%);
  opacity:calc(.4 + var(--wake) * .6);
  transition:opacity 1.4s ease;
  will-change:transform;
}

/* real marble, monochrome - the blur is baked into the file, and it is
   scaled far past recognition so it reads as stone grain, not a subject */
.atmos__marble{
  --o:.15;                 /* single source of truth: the fade-in reads it too */
  inset:-14%;
  background:url("../img/marble.webp") 42% 30% / 240% auto no-repeat;
  mix-blend-mode:soft-light;
  opacity:var(--o);
}

.atmos__dust{inset:0;width:100%;height:100%;opacity:.9}

/* keep the top gentle - the helmet crest lives up there */
.atmos__vignette{
  inset:0;
  background:
    radial-gradient(128% 92% at 50% 40%, transparent 46%, rgba(3,3,6,.5) 78%, rgba(2,2,4,.86) 100%),
    linear-gradient(180deg, rgba(2,2,5,.26) 0%, transparent 12%, transparent 70%, rgba(2,2,5,.66) 100%);
}

/* fine film grain, static (cheap) */
.atmos__grain{
  inset:-50%;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity:.055;
  mix-blend-mode:overlay;
}

/* -- the bust -------------------------------------------------- */
.bust{position:fixed;inset:0;z-index:1;pointer-events:none}

.bust__frame{
  position:absolute;inset:0;
  display:flex;justify-content:center;align-items:flex-start;
  padding-top:2vh;
}

.bust__img{
  flex:none;width:auto;
  /* the global img{max-width:100%} would clamp width while height stays put,
     which distorts the aspect on narrow viewports - size purely by height */
  max-width:none;
  height:min(78vh, 68vw);
  /* the file's own alpha mattes the subject; this only dissolves the
     shoulders so the wordmark can rise out of them */
  -webkit-mask-image:linear-gradient(180deg, transparent 0%, #000 4%, #000 50%, transparent 84%);
          mask-image:linear-gradient(180deg, transparent 0%, #000 4%, #000 50%, transparent 84%);
}

/* Dim base copy. The file carries a baked alpha matte, so it composites with
   plain source-over - no blend mode, and so no dependence on which ancestor
   happens to form a stacking context. */
.bust__img:not(.bust__img--lit){
  opacity:.55;
}

/* the lens: a circle of bright marble that follows the cursor.
   Mask is static (rasterised once); only `transform` changes per frame. */
.lens{
  position:absolute;top:0;left:0;
  width:calc(var(--spot) * 2);height:calc(var(--spot) * 2);
  margin:calc(var(--spot) * -1) 0 0 calc(var(--spot) * -1);
  -webkit-mask-image:radial-gradient(circle closest-side,
    #000 0%, rgba(0,0,0,.72) 42%, rgba(0,0,0,.24) 66%, transparent 82%);
          mask-image:radial-gradient(circle closest-side,
    #000 0%, rgba(0,0,0,.72) 42%, rgba(0,0,0,.24) 66%, transparent 82%);
  will-change:transform;
}
/* counter-translated so the bright copy stays registered with the base copy */
.lens__inner{
  position:absolute;top:0;left:0;
  width:100vw;height:100vh;height:100dvh;
  will-change:transform;
}
.bust__img--lit{
  opacity:calc(.24 + var(--wake) * .58);
  transition:opacity .9s ease;
}

/* A soft scrim between the bust and the type, so the small copy never has to
   compete with lit marble. A fixed full-viewport layer rather than an oversized
   pseudo-element on .core - the latter adds scroll overflow to the document. */
.scrim{
  position:fixed;inset:0;z-index:2;pointer-events:none;
  background:radial-gradient(ellipse 42% 26% at 50% 82%,
    rgba(4,4,8,.84) 0%, rgba(4,4,8,.62) 40%, rgba(4,4,8,.26) 66%, transparent 84%);
}

/* -- stage ----------------------------------------------------- */
.stage{
  position:relative;z-index:3;
  height:100vh;height:100dvh;
  display:grid;grid-template-rows:auto 1fr auto;
  padding:var(--pad) var(--pad) max(var(--pad), env(safe-area-inset-bottom));
}

.chrome{display:flex;align-items:center;justify-content:space-between;gap:1rem}

.chrome__meta{
  font-size:clamp(.56rem,.82vw,.7rem);
  font-weight:300;
  letter-spacing:.34em;
  text-transform:uppercase;
  color:var(--platinum-2);
}
.chrome__meta--dim{color:var(--platinum-3)}

/* laurel + sigma monogram */
.mark{
  position:relative;display:grid;place-items:center;
  width:clamp(38px,4.4vw,58px);aspect-ratio:1;
  color:var(--gold);
}
.mark__laurel{
  position:absolute;inset:0;
  background:currentColor;
  -webkit-mask:url("../img/laurel.svg") center/contain no-repeat;
          mask:url("../img/laurel.svg") center/contain no-repeat;
  opacity:.62;
  animation:markBreathe 9s ease-in-out infinite;
}
.mark__sigma{
  font-family:'Cormorant Garamond', Georgia, serif;
  font-size:clamp(15px,1.65vw,21px);
  line-height:1;
  background-image:var(--metal);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
@keyframes markBreathe{
  0%,100%{opacity:.5;transform:scale(1)}
  50%    {opacity:.78;transform:scale(1.035)}
}

/* -- core ------------------------------------------------------ */
.core{
  position:relative;
  align-self:end;justify-self:center;
  width:100%;max-width:min(92vw,1180px);
  text-align:center;
  padding-bottom:clamp(4px,1.6vh,20px);
}


/* eyebrow: the Greek mark between two hairlines */
.eyebrow{
  display:flex;align-items:center;justify-content:center;
  gap:clamp(10px,1.4vw,20px);
  margin:0 0 clamp(12px,1.9vh,26px);
}
.eyebrow__rule{
  display:block;height:1px;width:clamp(28px,7vw,120px);
  background:linear-gradient(90deg, transparent, rgba(201,164,92,.55));
}
.eyebrow__rule:last-child{
  background:linear-gradient(90deg, rgba(201,164,92,.55), transparent);
}
.eyebrow__word{
  font-family:'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  font-size:clamp(.66rem,1.1vw,.9rem);
  letter-spacing:.5em;
  margin-right:-.5em;                   /* cancel trailing tracking */
  color:var(--gold);
  opacity:.9;
}

/* the wordmark */
.wordmark{
  position:relative;
  margin:0;
  font-family:'Cinzel', 'Cormorant Garamond', Georgia, serif;
  font-weight:500;
  font-size:clamp(2.1rem, min(15vw, 19vh), 13rem);
  line-height:.98;
  letter-spacing:var(--ls-word);
  margin-right:calc(var(--ls-word) * -1);
  filter:drop-shadow(0 3px 26px rgba(201,164,92,.20));
}

.wordmark .l{
  display:inline-block;
  background-image:var(--metal);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
  /* per-letter cursor magnetism, amplitude set by JS */
  transform:translate3d(0, calc(var(--ly,0) * 1px), 0);
  transition:transform .5s var(--ease-out);
}

/* continuous sheen sweeping the whole word */
.wordmark::after{
  content:attr(data-text);
  position:absolute;left:0;top:0;width:100%;
  /* warm and restrained - a white peak would break the gold for a beat */
  background-image:linear-gradient(102deg,
    transparent 42%, rgba(255,243,209,.62) 50%, transparent 58%);
  background-size:250% 100%;
  background-repeat:no-repeat;
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
  pointer-events:none;
  opacity:0;
  animation:sheen 8.5s cubic-bezier(.45,.05,.4,1) 2.9s infinite;
}
@keyframes sheen{
  0%   {background-position:-70% 0; opacity:0}
  6%   {opacity:.95}
  34%  {background-position:170% 0; opacity:.95}
  42%  {background-position:170% 0; opacity:0}
  100% {background-position:170% 0; opacity:0}
}

/* rule + tagline */
.tagline{
  position:relative;
  margin:clamp(14px,2.3vh,30px) 0 0;
  font-size:clamp(.6rem,.95vw,.8rem);
  font-weight:300;
  letter-spacing:.42em;
  text-transform:uppercase;
  color:var(--platinum-2);
}
.tagline::before{
  content:'';position:absolute;left:50%;top:calc(-1 * clamp(9px,1.4vh,18px));
  width:clamp(120px,26vw,340px);height:1px;transform:translateX(-50%);
  background:linear-gradient(90deg, transparent, rgba(198,202,209,.28) 22%,
             rgba(201,164,92,.6) 50%, rgba(198,202,209,.28) 78%, transparent);
}
.tagline span{display:inline-block;margin-right:-.42em}

/* -- actions --------------------------------------------------- */
.actions{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(10px,1.3vw,18px);
  margin-top:clamp(20px,3.4vh,42px);
}

.btn{
  position:relative;isolation:isolate;overflow:hidden;
  display:inline-flex;align-items:center;gap:.85em;
  padding:.92em 1.65em;
  border:1px solid rgba(198,202,209,.17);
  border-radius:1px;
  background:rgba(255,255,255,.014);
  font-size:clamp(.56rem,.86vw,.72rem);
  font-weight:300;letter-spacing:.26em;text-transform:uppercase;
  color:var(--platinum-2);
  text-decoration:none;
  cursor:pointer;
  transition:color .45s ease, border-color .45s ease, background .45s ease,
             transform .45s var(--ease-out);
}
.btn__label{position:relative;z-index:1;margin-right:-.26em}

/* light wiping across on hover */
.btn::before{
  content:'';position:absolute;inset:0;z-index:0;
  background:linear-gradient(100deg, transparent 12%,
    rgba(201,164,92,.20) 48%, transparent 84%);
  transform:translateX(-105%);
  transition:transform .85s cubic-bezier(.22,1,.36,1);
}
.btn:hover::before,.btn:focus-visible::before{transform:translateX(105%)}

.btn:hover,.btn:focus-visible{
  color:var(--gold-hi);
  border-color:rgba(201,164,92,.5);
  background:rgba(201,164,92,.05);
  transform:translateY(-2px);
}
.btn:focus-visible{outline:1px solid rgba(201,164,92,.75);outline-offset:3px}
.btn:active{transform:translateY(0)}

.btn--gold{color:var(--gold);border-color:rgba(201,164,92,.34)}

/* corner brackets - a struck-seal detail on the primary action */
.btn--gold::after{
  content:'';position:absolute;inset:3px;z-index:0;pointer-events:none;
  background:
    linear-gradient(var(--gold),var(--gold)) left  top    /1px 8px no-repeat,
    linear-gradient(var(--gold),var(--gold)) left  top    /8px 1px no-repeat,
    linear-gradient(var(--gold),var(--gold)) right top    /1px 8px no-repeat,
    linear-gradient(var(--gold),var(--gold)) right top    /8px 1px no-repeat,
    linear-gradient(var(--gold),var(--gold)) left  bottom /1px 8px no-repeat,
    linear-gradient(var(--gold),var(--gold)) left  bottom /8px 1px no-repeat,
    linear-gradient(var(--gold),var(--gold)) right bottom /1px 8px no-repeat,
    linear-gradient(var(--gold),var(--gold)) right bottom /8px 1px no-repeat;
  opacity:0;
  transition:opacity .45s ease, inset .45s var(--ease-out);
}
.btn--gold:hover::after,.btn--gold:focus-visible::after{opacity:.55;inset:5px}

.btn__hint{
  position:relative;z-index:1;
  font-size:.82em;letter-spacing:.2em;
  color:var(--platinum-3);
  max-width:0;opacity:0;overflow:hidden;white-space:nowrap;
  transition:max-width .5s var(--ease-out), opacity .4s ease, color .4s ease;
}
.btn:hover .btn__hint,.btn:focus-visible .btn__hint{
  max-width:5em;opacity:1;color:var(--gold-lo);
}
.btn.is-copied .btn__hint{color:var(--gold-hi);opacity:1;max-width:5em}

/* -- custom cursor --------------------------------------------- */
.cursor{
  position:fixed;left:0;top:0;z-index:60;pointer-events:none;
  opacity:0;transition:opacity .5s ease;
}
html.has-cursor .cursor{opacity:1}
html.has-cursor,html.has-cursor *{cursor:none !important}

.cursor__ring,.cursor__dot{
  position:absolute;border-radius:50%;transform:translate3d(-50%,-50%,0);
}
.cursor__ring{
  width:34px;height:34px;
  border:1px solid rgba(201,164,92,.55);
  box-shadow:0 0 18px rgba(201,164,92,.18), inset 0 0 12px rgba(201,164,92,.07);
  transition:width .35s var(--ease-out), height .35s var(--ease-out),
             border-color .35s ease, opacity .35s ease;
}
.cursor__dot{
  width:3px;height:3px;background:var(--gold-hi);
  box-shadow:0 0 8px rgba(244,230,196,.8);
}
html.is-hot .cursor__ring{width:60px;height:60px;border-color:rgba(244,230,196,.85)}
html.is-hot .cursor__dot{opacity:.35}

/* -- toast ----------------------------------------------------- */
.toast{
  position:fixed;left:50%;bottom:clamp(58px,9vh,96px);z-index:70;
  margin:0;padding:.75em 1.5em;
  transform:translate(-50%,14px);
  border:1px solid rgba(201,164,92,.32);
  background:rgba(10,10,14,.86);
  backdrop-filter:blur(10px);
  font-size:clamp(.56rem,.8vw,.7rem);
  letter-spacing:.28em;text-transform:uppercase;
  color:var(--gold-hi);
  opacity:0;pointer-events:none;
  transition:opacity .45s ease, transform .55s var(--ease-out);
}
.toast.is-on{opacity:1;transform:translate(-50%,0)}

/* === entrance =================================================
   The resting state below is fully visible. `.is-armed` (set by the inline
   script in <head>, before first paint) hides only what is about to animate;
   `.is-settled` restores the resting state unconditionally when the entrance
   is over. Nothing is ever left stranded behind an animation that did not run.
   ============================================================== */
html.is-armed [data-reveal],
html.is-armed .wordmark .l,
html.is-armed .bust__frame,
html.is-armed .atmos__marble{opacity:0}

html.is-ready [data-reveal]{
  animation:rise 1.5s var(--ease-out) both;
  animation-delay:calc(.16s + var(--reveal-i,0) * .085s);
}
html.is-ready .wordmark .l{
  animation:strike 1.65s var(--ease-out) both;
  animation-delay:calc(.42s + var(--i) * .105s);
}
html.is-ready .bust__frame{animation:emerge 2.6s ease-out both}
html.is-ready .atmos__marble{animation:emergeTo 3.4s ease-out both}

html.is-settled [data-reveal],
html.is-settled .wordmark .l,
html.is-settled .bust__frame{animation:none;opacity:1}
html.is-settled .atmos__marble{animation:none;opacity:var(--o)}

@keyframes rise{
  from{opacity:0;transform:translate3d(0,14px,0);filter:blur(5px)}
  to  {opacity:1;transform:none;filter:none}
}
@keyframes strike{
  0%  {opacity:0;transform:translate3d(0,42px,0) scale(1.14);filter:blur(13px)}
  55% {opacity:1}
  100%{opacity:1;transform:none;filter:none}
}
@keyframes emerge{from{opacity:0}to{opacity:1}}
/* for layers whose resting opacity is not 1 - keyframes must not clobber it */
@keyframes emergeTo{from{opacity:0}to{opacity:var(--o)}}

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

/* Portrait of any size - phone through tablet. Keyed to aspect rather than
   width: an 820x1120 tablet needs the bust centred just as a phone does, or
   a dead band opens up between it and the wordmark. */
@media (max-aspect-ratio:4/5){
  .bust__frame{align-items:center;padding-top:0}
  /* The subject sits inside roughly the middle 60% of the file, and the rest
     of the frame is transparent, so the box may exceed the viewport width -
     only empty margin bleeds off the sides. */
  .bust__img{height:min(70vh,140vw)}
}

/* narrow: tighten the type and stack the actions */
@media (max-width:760px){
  .chrome__meta{letter-spacing:.26em}
  .actions{gap:10px}
  .btn{padding:.95em 1.4em;letter-spacing:.2em}
  .toast{bottom:clamp(70px,12vh,110px)}
}

@media (max-width:420px){
  .actions{flex-direction:column;align-items:stretch}
  .btn{justify-content:center}
  .eyebrow__rule{width:clamp(20px,10vw,60px)}
}

/* Short AND wide only. Without the aspect guard a small phone (320x568)
   would match on height alone and get the landscape sizing, shrinking the
   bust to a fraction of its intended size. */
@media (max-height:620px) and (min-aspect-ratio:1/1){
  .bust__img{height:min(62vh,52vw)}
  .tagline{margin-top:clamp(10px,1.8vh,18px)}
  .actions{margin-top:clamp(12px,2.2vh,24px)}
  .eyebrow{margin-bottom:clamp(8px,1.2vh,14px)}
}
@media (max-height:460px) and (min-aspect-ratio:1/1){
  .bust__img{height:min(52vh,42vw)}
  .tagline{display:none}
  .mark{width:clamp(30px,3.6vw,42px)}
}

/* -- accessibility --------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .atmos__sweep{animation:none;opacity:.45}
  .mark__laurel{animation:none;opacity:.62}
  .wordmark::after{display:none}
  .atmos__dust{display:none}
  .par{transform:none !important}
  /* no cursor lens: show one evenly lit copy instead */
  .lens{display:none}
  .bust__img:not(.bust__img--lit){opacity:.66}
}

@media (prefers-contrast:more){
  .chrome__meta,.tagline{color:#d8dce2}
  .btn{border-color:rgba(198,202,209,.5);color:#d8dce2}
  .bust__img:not(.bust__img--lit){opacity:.34}
}
