/* Mawli, coming soon.
   Same room as the main site, one screen instead of a scroll. The tokens,
   the veil, the grain and the photograph treatment are lifted from
   ../css/app.css so the two read as one brand; anything scroll-driven is
   gone, and the grade breathes on a timer instead. */

:root {
  /* Mid-scroll of the main site's palette: past the daylight, well before the
     dark end. See DESIGN.md, "Colour - a function of scroll progress". */
  --d-bg:   oklch(0.28 0.055 45);
  --d-glow: oklch(0.44 0.085 55);
  --vig: color-mix(in oklch, var(--d-bg) 76%, var(--d-glow));

  --brass:      oklch(0.78 0.14 72);
  --brass-text: oklch(0.875 0.125 80);

  --ink:   oklch(0.97 0.008 80);
  --ink-2: oklch(0.88 0.014 78);
  --ink-3: oklch(0.83 0.018 76);

  --rule: color-mix(in oklch, var(--ink) 20%, transparent);

  --display: "Bodoni Moda", "Didot", "Bodoni MT", "Hoefler Text", Georgia, serif;
  --body: "Archivo", ui-sans-serif, system-ui, sans-serif;

  --gutter: clamp(1.25rem, 5vw, 4rem);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-out-expo:  cubic-bezier(0.16, 1, 0.3, 1);

  --z-grain: 3;
  --z-copy: 4;

  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--d-bg);
  color: var(--ink);
  font: 400 clamp(0.9375rem, 0.9rem + 0.25vw, 1.0625rem)/1.65 var(--body);
  -webkit-font-smoothing: antialiased;
  overflow: hidden; /* one screen, nothing to scroll to */
}

a { color: inherit; }

/* ---------- the room ---------- */

#gl {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  display: block;
  z-index: 0;
  /* Painted before the first frame lands, so the page never flashes white. */
  background: var(--d-bg);
}

/* A radial scrim between the light and the copy. */
.veil {
  position: fixed; inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(115% 88% at 50% 52%,
    oklch(0.115 0.022 42 / var(--veil, 0.30)) 0%,
    oklch(0.115 0.022 42 / calc(var(--veil, 0.30) * 0.55)) 52%,
    transparent 82%);
}

.grain {
  position: fixed; inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.32;
  mix-blend-mode: overlay;
  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='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Fallback only. The real carving is composited inside the shader, so this is
   visible by default and removed once that layer is actually running. Without
   it the page is a black rectangle wherever WebGL is refused. */
.still {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
  opacity: 0.42;
  filter: grayscale(0.45) saturate(0.6) brightness(0.52) contrast(1.06);
}
body.has-water .still { display: none; }

/* ---------- the copy ---------- */

.stage {
  position: relative;
  z-index: var(--z-copy);
  min-height: 100svh;
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  padding: clamp(4rem, 12vh, 7rem) var(--gutter) clamp(6rem, 16vh, 9rem);
}

.eyebrow {
  margin: 0;
  font-size: 0.6875rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--brass-text);
}

.display {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1;
  margin: 0;
}

/* The mark is a poster, past the usual display ceiling on purpose.
   opsz is pinned rather than automatic: `auto` feeds the used font-size to the
   axis, so at this size it clamps to the 96 master, whose hairlines land on
   roughly one device pixel and break up under the grain. See DESIGN.md. */
.mark {
  margin-top: clamp(0.75rem, 2.5vh, 1.5rem);
  font-size: clamp(3.5rem, 15vw, 11rem);
  line-height: 0.86;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  font-optical-sizing: none;
  font-variation-settings: "opsz" 32;
  -webkit-font-smoothing: auto;
}

/* ---------- the mark comes up out of the dark ----------
   Each letter rises behind its own mask rather than the word fading in. It is
   the carving's move: the site brings him toward you instead of dissolving him
   up, and the type here does the same thing. MAWLI has no descenders, so a
   mask that cuts at the baseline costs nothing. The spans are written by JS,
   so with no script the h1 is simply a word. */
.mark__l {
  display: inline-block;
  overflow: hidden;
  /* Room for the cap and the hairlines inside a 0.86 line box. */
  padding-block: 0.10em;
  margin-block: -0.10em;
}
.mark__i {
  display: inline-block;
  animation: markRise 1.15s var(--ease-out-expo) backwards;
  animation-delay: calc(0.18s + var(--i, 0) * 0.085s);
  /* Written by the render loop as the ember passes: 0 cold, 1 lit. */
  color: color-mix(in oklch, var(--brass-text) calc(var(--warm, 0) * 100%), var(--ink));
  text-shadow: 0 0 calc(var(--warm, 0) * 22px)
               oklch(0.78 0.14 72 / calc(var(--warm, 0) * 0.5));
}
@keyframes markRise {
  from { transform: translateY(105%); }
  to   { transform: translateY(0); }
}

/* The rest arrives after the mark has settled, not with it. */
@keyframes riseIn {
  from { opacity: 0; transform: translateY(0.6rem); }
  to   { opacity: 1; transform: none; }
}
@keyframes trackIn {
  from { opacity: 0; letter-spacing: 0.5em; }
  to   { opacity: 1; letter-spacing: 0.22em; }
}
.eyebrow { animation: trackIn 1.4s var(--ease-out-expo) backwards; }
.line    { animation: riseIn 1s var(--ease-out-quart) backwards 0.75s; }
.where   { animation: riseIn 1s var(--ease-out-quart) backwards 0.90s; }
.hours   { animation: riseIn 1s var(--ease-out-quart) backwards 1.00s; }
.cta     { animation: riseIn 1s var(--ease-out-quart) backwards 1.14s; }

.line {
  margin: clamp(1.25rem, 3.5vh, 2rem) 0 0;
  max-width: 44ch;
  text-wrap: balance;
  color: var(--ink-2);
}

/* Where and when, unlabelled and quiet. `address` is the right element for the
   page's own contact details; browsers italicise it, which this does not want. */
.where {
  margin: clamp(1.5rem, 4vh, 2.25rem) 0 0;
  /* Broken by hand, one part per line, the way an address is written. Left to
     wrap it split the road name at "et rue / Hassania" on a phone; no measure
     fixes that at every width, and explicit breaks never wrap wrong. */
  max-width: 40ch;
  font-style: normal;
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--ink-2);
}
.hours {
  margin: 0.55rem 0 0;
  font-size: 0.875rem;
  color: var(--ink-3);
}

/* The one thing to press. It gets the brass fill because it is the only
   action on the page; everything else is information. */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: clamp(1.75rem, 4.5vh, 2.75rem);
  /* Tall enough to clear the 44px touch target: at 0.85rem it measured 43. */
  padding: 0.95rem 1.6rem;
  background: var(--brass);
  color: oklch(0.16 0.03 60);
  font: 500 0.875rem/1 var(--body);
  letter-spacing: 0.04em;
  text-decoration: none;
  transition: background-color 220ms var(--ease-out-quart),
              translate 220ms var(--ease-out-quart);
}
.cta:hover,
.cta:focus-visible { background: oklch(0.85 0.15 72); translate: 0 -2px; }
.cta:active { translate: 0 0; }
.cta__mark { width: 1.15em; height: 1.15em; flex: none; }

/* ---------- the signature ---------- */

/* A credit, not a second brand: it sits on the bottom rule, quiet until you
   look at it. The studio name takes the Didone so it reads as a signature
   rather than as another line of interface text. */
.sign {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-copy);
  padding: 0 var(--gutter) clamp(1.25rem, 3.5vh, 2rem);
  display: flex;
  justify-content: center;
}
.sign a {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
  padding-top: clamp(0.875rem, 2vh, 1.25rem);
  border-top: 1px solid var(--rule);
  min-width: min(20rem, 60vw);
  justify-content: center;
  transition: border-color 260ms var(--ease-out-quart);
  /* The rule draws itself outward from the centre, so the credit signs rather
     than simply appears. */
  animation: signIn 1.2s var(--ease-out-expo) backwards 1.3s;
}
@keyframes signIn {
  from { opacity: 0; clip-path: inset(0 50% 0 50%); }
  to   { opacity: 1; clip-path: inset(0 0 0 0); }
}
.sign a:hover,
.sign a:focus-visible { border-top-color: var(--brass); }

.sign__by {
  font-size: 0.625rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.sign__name {
  font-family: var(--display);
  font-optical-sizing: auto;
  font-size: 1rem;
  letter-spacing: 0.01em;
  color: var(--ink-2);
  transition: color 260ms var(--ease-out-quart);
}
.sign a:hover .sign__name,
.sign a:focus-visible .sign__name { color: var(--brass-text); }

:focus-visible { outline: 2px solid var(--brass); outline-offset: 4px; }

/* ---------- narrow ---------- */

@media (max-width: 30rem) {
  .sign a { min-width: 100%; }
}

/* ---------- reduced motion ---------- */

/* The WebGL loop never starts. The still carries the carving instead. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  #gl { display: none; }
  body {
    background:
      radial-gradient(120% 90% at 50% 40%,
        oklch(0.36 0.075 52) 0%,
        oklch(0.26 0.05 45) 46%,
        oklch(0.15 0.028 42) 100%)
      fixed;
  }
}
