/* ==========================================================================
   VAEL — the being in the corner of the sky

   A keyed film of a small creature made of galaxies, floating over the page
   with nothing behind him. He is scenery with a will: js/vael.js moves him,
   this file decides what moving looks like.

   Two rules the rest of the site already lives by apply here too.
     · He is under the grain (z-index 80), so he is filmed with the page
       rather than pasted on top of it. His console is above it, because a
       control has to read as a control.
     · Nothing lands. Every journey is a long coast with no overshoot and no
       settle — this is vacuum, and he has no weight to put down.

   The whole layer is anchored to the inline end of the viewport, so he stands
   at the right of an English page and at the left of an Arabic one, and every
   movement js/vael.js sends him on is signed to match.
   ========================================================================== */

.vael {
  /* A coast: leaves slowly, arrives slower, never overshoots. */
  --vael-ease: cubic-bezier(0.36, 0, 0.18, 1);
  --vael-travel: 2.4s;

  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;
}

/* Browsers that cannot decode the alpha in the WebM get the MP4, where he is
   left on black. Screening the entire layer drops that black against the void
   ground and leaves the same silhouette. It has to sit here, on the outermost
   element, because anything with a transform below it would isolate the blend
   from the page it is supposed to blend with. */
.vael.is-flat {
  mix-blend-mode: screen;
}

/* ── The body ─────────────────────────────────────────────────────────── */

.vael__figure {
  --x: 0px;
  --y: 0px;
  --s: 1;
  --sx: 1;
  --sy: 1;
  --tilt: 0deg;

  position: absolute;
  inset-block-end: clamp(4.5rem, 11vh, 8.5rem);
  inset-inline-end: clamp(0.9rem, 5vw, 4.5rem);
  inline-size: clamp(122px, 15vw, 232px);
  transform: translate3d(var(--x), var(--y), 0)
    scale(calc(var(--s) * var(--sx)), calc(var(--s) * var(--sy))) rotate(var(--tilt));
  transform-origin: 50% 62%;
  opacity: 0;
  filter: blur(10px);
  transition: transform var(--vael-travel) var(--vael-ease),
    opacity 1.1s var(--ease), filter 1.1s var(--ease);
  will-change: transform, opacity;
}

.vael.is-here .vael__figure {
  opacity: 1;
  filter: blur(0);
}

/* Arriving and leaving are the same move played in opposite directions: a
   point of light that widens into a body, and closes back into one.

   That is the layer doing it, and it is only needed where there is no film of
   him doing it himself. Once assets/vael/takes.json has an arrival and a
   departure, js/vael.js marks the layer and the vortex takes over — two things
   widening at once would read as him arriving twice. */
.vael:not(.is-here):not(.has-entrance) .vael__figure {
  --s: 0.42;
}

/* He is going. The layer stays lit until the last frame of the departure —
   gone() takes it away — but nothing about him is touchable on the way out. */
.vael.is-leaving .vael__poke {
  pointer-events: none;
}

.vael.is-leaving .vael__glow {
  opacity: 0;
  transform: scale(1.3);
  transition: opacity 3.4s var(--ease), transform 4s var(--ease);
}

/* A slow spatial drift laid over the float already in the film, on its own
   element so it never fights the transform js/vael.js writes. Two periods
   that do not divide into each other, so the pattern never visibly repeats. */
.vael__float {
  display: block;
  animation: vael-adrift 19s ease-in-out infinite;
}

@keyframes vael-adrift {
  0%,
  100% {
    transform: translate3d(0, 0, 0) rotate(0deg);
  }
  27% {
    transform: translate3d(-7px, -13px, 0) rotate(-0.9deg);
  }
  61% {
    transform: translate3d(6px, 7px, 0) rotate(0.8deg);
  }
  84% {
    transform: translate3d(-3px, -5px, 0) rotate(-0.3deg);
  }
}

/* He is a light source, so the page gets a little of him — and it leaves him
   where his light does. This box is inset -18% above and -12% below, so it is
   130% of his height starting 18% above his head; his eyes are 21.7% down the
   plate, which is (21.7 + 18) / 130 = 30.5% down this. */
.vael__glow {
  position: absolute;
  inset: -18% -34% -12%;
  background: radial-gradient(
    46% 40% at 50% 30.5%,
    rgba(178, 91, 240, 0.34),
    rgba(109, 58, 212, 0.14) 48%,
    transparent 74%
  );
  filter: blur(16px);
  opacity: 0.85;
  transition: opacity 1s var(--ease), transform 1s var(--ease);
  pointer-events: none;
}

/* The film itself. One layer per take, crossfaded — a take that has finished
   holds its last frame while the next one comes up under it, so there is never
   a frame of nothing. */
.vael__poke {
  position: relative;
  display: block;
  inline-size: 100%;
  aspect-ratio: 440 / 660;
  background: none;
  border: 0;
  padding: 0;
  pointer-events: auto;
  cursor: pointer;
  /* A press-and-hold on him is a hand on him, and nothing else. Without these
     a phone answers it with the menu it keeps for films — copy, save, download
     — and he is a creature, not a file. The menu itself is refused in
     js/main.js, which is the half of this that Android needs. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* While he is out, a touch that starts on him is his: the page underneath
   must not take it away and scroll with it half way through carrying him.
   Only while he is out — the corner is the page's again the moment he goes,
   and `body` is `touch-action: pan-y pinch-zoom` everywhere else. */
.vael.is-here .vael__poke {
  touch-action: none;
}

.vael.is-held .vael__poke {
  cursor: grabbing;
}

.vael__poke:focus-visible {
  outline: 1px solid var(--violet-bright);
  outline-offset: 6px;
  border-radius: 12px;
}

.vael__stage {
  position: absolute;
  inset: 0;
  display: block;
}

.vael__take {
  position: absolute;
  inset: 0;
  display: block;
  opacity: 0;
  /* Symmetric, so the dissolve passes through the half-and-half point — the
     one moment two takes are both visible — as quickly as it can. */
  transition: opacity 0.8s cubic-bezier(0.45, 0, 0.55, 1);
}

.vael__take.is-current {
  opacity: 1;
}

/* A take that is not being dissolved away but replaced outright. The arrival
   is the only thing that does this: he is not in the first second of that film
   and the take underneath is him standing, so a crossfade would show him
   arriving after he was already there. */
.vael__take.is-cut {
  transition: none;
}

/* The arrival and the departure are the only takes with something other than
   Vael on them, and a vortex is four times his width. They are cut to the same
   framing 2.6 times as wide (scripts/vael-media.mjs), so the slot that holds
   them hangs off both sides of the stage by the same amount — he stays exactly
   where the other takes have him, and the sky he comes out of is not clipped
   to his shoulders. Nothing here is touchable: the button is still his own
   height and width, not the galaxy's. */
.vael__take--wide {
  inset-block: 0;
  inset-inline: calc((1 - var(--vael-wide, 1)) * 50%);
  pointer-events: none;
}

.vael__take video,
.vael__take img,
img.vael__take {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  display: block;
}

/* ── Changing take ────────────────────────────────────────────────────────
   The takes are cut to one framing, so he does not move or resize across a
   switch — but they are separate renders, and his arms and hem never agree.
   Sharpness is what gives that away, so it is taken out for the length of the
   crossover and his own light comes up through the blur. What reads is a being
   gathering himself, not one film becoming another. */

.vael.is-shifting .vael__poke {
  animation: vael-shift 0.8s cubic-bezier(0.45, 0, 0.55, 1);
}

@keyframes vael-shift {
  0%,
  100% {
    filter: blur(0);
  }
  50% {
    filter: blur(2.1px);
  }
}

.vael.is-shifting .vael__flare {
  opacity: 0.62;
  transition: opacity 0.4s var(--ease);
}

.vael.is-shifting .vael__glow {
  opacity: 1;
  transform: scale(1.08);
}

/* The light he reads a wall by, and the only light on this site that comes
   from a place rather than from everywhere: his two eyes.

   One element carrying two gradients, at the exact fractions his eyes sit at
   on the plate every take is cut to — 42.5% and 57.4% across, 21.7% down, the
   same numbers assets/vael/observer.json holds for the depths. Screened, so
   what is under them is lit rather than covered. */
.vael__eyes {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      ellipse 9% 6.4% at 42.5% 21.7%,
      rgba(255, 253, 255, 0.95),
      rgba(206, 168, 255, 0.42) 38%,
      rgba(178, 91, 240, 0.14) 62%,
      transparent 78%
    ),
    radial-gradient(
      ellipse 9% 6.4% at 57.4% 21.7%,
      rgba(255, 253, 255, 0.95),
      rgba(206, 168, 255, 0.42) 38%,
      rgba(178, 91, 240, 0.14) 62%,
      transparent 78%
    );
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  pointer-events: none;
}

.vael.is-lit .vael__eyes {
  opacity: 1;
}

/* And he carries a little more of himself while he is lit. */
.vael.is-lit .vael__glow {
  opacity: 1;
  transform: scale(1.06);
}

/* His own light answering something — the halo the two lamps above throw
   when they come up hard. It sits on the same two points they do, not on the
   top of his head: everything luminous about him has one source, and that
   source is his eyes.

   Placed by gradient rather than by inset, which is the only way to hold a
   point on the plate — `inset-inline-start` mirrors in Arabic, and a bloom
   that mirrors leaves his face. The radii are elliptical because the box is
   440 x 660: 22% across and two thirds of that down reads as a circle. */
.vael__flare {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      ellipse 22% 14.7% at 42.5% 21.7%,
      rgba(236, 222, 255, 0.52),
      rgba(178, 91, 240, 0.24) 40%,
      transparent 70%
    ),
    radial-gradient(
      ellipse 22% 14.7% at 57.4% 21.7%,
      rgba(236, 222, 255, 0.52),
      rgba(178, 91, 240, 0.24) 40%,
      transparent 70%
    );
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.75s var(--ease);
  pointer-events: none;
}

/* A ring leaving him, once, on the beat of a reaction. It leaves from the
   same place the light does. `left` and not `inset-inline-start`: the plate is
   never mirrored, so a logical inset would put the ring beside him in Arabic. */
.vael__ring {
  position: absolute;
  left: 50%;
  inset-block-start: 21.7%;
  inline-size: 58%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border: 1px solid rgba(217, 184, 255, 0.5);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}

.vael.is-pulsing .vael__ring {
  animation: vael-ripple 1.6s var(--ease);
}

@keyframes vael-ripple {
  0% {
    opacity: 0;
    scale: 0.34;
  }
  18% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
    scale: 2.3;
  }
}

/* ── Moods ────────────────────────────────────────────────────────────── */

/* Greeting: he comes forward and brightens. */
.vael.is-greeting .vael__flare {
  opacity: 1;
}
.vael.is-greeting .vael__glow {
  opacity: 1;
  transform: scale(1.14);
}

/* Held: he is being carried, not travelling. js/vael.js writes every frame of
   this one, so the drift he does on his own is stilled for the length of it —
   two hands on him at once is one too many — and he brightens where he is
   touched. It freezes where it stands and resumes from there, so neither
   taking hold of him nor letting go is a jump. */
.vael.is-held .vael__float {
  animation-play-state: paused;
}

.vael.is-held .vael__glow {
  opacity: 1;
  transform: scale(1.12);
}

.vael.is-held .vael__flare {
  opacity: 0.72;
}

/* Resting: the light in him goes down, not out. */
.vael.is-resting .vael__glow {
  opacity: 0.42;
  transform: scale(0.94);
}
.vael.is-resting .vael__figure {
  filter: saturate(0.82) brightness(0.86);
}

/* Warping: stretched into the streak the whole site uses for a jump, then
   gone. The transition is short and sharp on the way out — this is the one
   move that is allowed to be fast, because it is not travel, it is leaving. */
.vael.is-warping .vael__figure {
  --sx: 0.16;
  --sy: 1.75;
  opacity: 0;
  filter: blur(7px);
  transition: transform 0.6s cubic-bezier(0.7, 0, 0.84, 0), opacity 0.55s ease-in,
    filter 0.55s ease-in;
}

/* Placed with no transition at all: the jump itself must not be seen. */
.vael.is-elsewhere .vael__figure {
  transition: none;
}

/* Poked: a small recoil, and his light answers. */
.vael.is-pulsing .vael__flare {
  opacity: 0.9;
}

/* Arriving: the only light in the corner is the film's own.

   The layer carries three lights of its own — the bloom he casts on the page,
   the flare on his head and the ring that leaves him — and all three are wrong
   over an arrival. They would be lit before there is anybody there to be
   lighting: a glow around a vortex he has not gathered out of yet.

   Cut rather than faded, because the layer is fading up underneath at the same
   moment and a glow fading out through a figure fading in is still a glow. It
   comes back on the handover into the idle, which is when he actually starts
   giving off light. `is-busy` also covers the departure, so it is qualified:
   leaving already takes his light with him.

   Last in this section on purpose — it has to outrank the moods above it. */
.vael.is-busy:not(.is-leaving) .vael__glow,
.vael.is-busy:not(.is-leaving) .vael__flare {
  opacity: 0;
  transition: none;
}

.vael.is-busy:not(.is-leaving) .vael__ring {
  animation: none;
}

/* ── The console ──────────────────────────────────────────────────────────
   A rail of keys at the opposite corner from Vael, so a hand on the controls
   is never over him. Above the grain, unlike him: it is instrumentation, not
   scenery. */

.vael-console {
  position: fixed;
  inset-block-end: clamp(0.9rem, 3.5vh, 2.2rem);
  inset-inline-start: clamp(0.9rem, 4vw, 3rem);
  z-index: 92;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  font-family: var(--font-sans);
  max-inline-size: min(30rem, calc(100vw - 1.8rem));
}

html[lang='ar'] .vael-console {
  font-family: var(--font-ar);
}

/* What he is doing, in the same voice as the read-out under the orrery. It
   only exists once he does: before he is called, the first screen is left as
   it was — one claim, the instrument, and one more button. */
.vael-console__read {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease), color 0.5s var(--ease);
  padding-inline-start: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper-48);
}

html[lang='ar'] .vael-console__read {
  font-family: var(--font-ar);
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.72rem;
}

.vael-console__read::before {
  content: '';
  inline-size: 5px;
  block-size: 5px;
  border-radius: 50%;
  background: var(--paper-32);
  flex: none;
  transition: background-color 0.5s var(--ease), box-shadow 0.5s var(--ease);
}

.vael-console.is-here .vael-console__read {
  opacity: 1;
  transform: none;
  color: var(--paper-64);
}

.vael-console.is-here .vael-console__read::before {
  background: var(--violet);
  box-shadow: 0 0 10px rgba(178, 91, 240, 0.8);
}

.vael-console__moves {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
}

.vael-rail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: rgba(9, 6, 22, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.vael-key {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.52rem 0.95rem;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--paper-48);
  font-family: inherit;
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.35s var(--ease), border-color 0.35s var(--ease),
    background-color 0.35s var(--ease), box-shadow 0.45s var(--ease);
}

.vael-key:hover {
  color: var(--paper);
  border-color: rgba(178, 91, 240, 0.5);
  box-shadow: 0 0 22px rgba(178, 91, 240, 0.22);
}

.vael-key:focus-visible {
  outline: 1px solid var(--violet-bright);
  outline-offset: 2px;
}

.vael-key:active {
  transform: scale(0.97);
}

.vael-key[aria-pressed='true'] {
  color: var(--paper);
  border-color: rgba(178, 91, 240, 0.62);
  background: rgba(178, 91, 240, 0.16);
}

/* The hail key carries his eyes, which is the only mark he has. */
.vael-key--hail {
  color: var(--paper-64);
  border-color: var(--paper-16);
}

/* While a film of him arriving or leaving is running, the console is his and
   not the visitor's: the key that started it cannot be pressed again until the
   last frame, and neither can he. */
.vael-key[disabled] {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
}

.vael.is-busy .vael__poke {
  pointer-events: none;
}

.vael-key__eyes {
  display: inline-flex;
  gap: 3px;
  flex: none;
  color: var(--violet-bright);
  transition: filter 0.4s var(--ease), opacity 0.4s var(--ease);
  opacity: 0.75;
}

.vael-key--hail:hover .vael-key__eyes,
.vael-key--hail[aria-pressed='true'] .vael-key__eyes {
  opacity: 1;
  filter: drop-shadow(0 0 6px rgba(178, 91, 240, 0.9));
}

.vael-console__moves {
  opacity: 0;
  transform: translateY(7px);
  pointer-events: none;
  transition: opacity 0.55s var(--ease), transform 0.65s cubic-bezier(0.36, 0, 0.18, 1);
}

.vael-console.is-here .vael-console__moves {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* ── Small screens ────────────────────────────────────────────────────── */

@media (max-width: 720px) {
  .vael__figure {
    inset-block-end: clamp(7.5rem, 20vh, 12rem);
  }

  .vael-key {
    padding: 0.48rem 0.8rem;
    font-size: 0.72rem;
  }
}

/* ── Reduced motion ───────────────────────────────────────────────────────
   He stays — he is a still image then, lit and floating in place, because a
   picture of someone standing in space is not motion. What stops is travel:
   the buttons still work, they simply put him where they were going to take
   him. */

@media (prefers-reduced-motion: reduce) {
  .vael {
    --vael-travel: 0.001s;
  }

  .vael__float,
  .vael.is-pulsing .vael__ring {
    animation: none;
  }

  .vael__figure,
  .vael.is-warping .vael__figure {
    transition: opacity 0.4s linear;
  }

  .vael:not(.is-here) .vael__figure {
    --s: 1;
  }

  .vael-console__moves {
    transition: opacity 0.3s linear;
    transform: none;
  }
}

/* ==========================================================================
   THE INSCRIPTIONS — the walls he reads

   Lines that are on the page and not painted. js/tomb.js carves them into the
   margins, gaps, and open fields inside sections, at zero opacity, and Vael's light is the only thing
   on this site that brings them up: the pool of light is a mask, so the edge
   of it cuts across the letters rather than fading a whole sentence in like a
   tooltip.

   Everything here is ornament in the strictest sense — aria-hidden, inert,
   unselectable — and it is built wherever the light can be carried, which
   since Vael can be picked up and dragged means a phone as well.
   ========================================================================== */

.tomb {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: 70; /* over the page, under him (80) and under the grain (90) */
  inline-size: 100%;
  /* No height: the carvings inside are placed in document coordinates, and a
     layer as tall as the page is a layer the page has to grow to hold. */
  block-size: 0;
  pointer-events: none;
  user-select: none;
  contain: layout style;
}

/* His light on the wall. Moved with a transform and nothing else — while he
   is carrying it the page under it is never repainted. */
.tomb__lamp {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  /* REACH in js/tomb.js is 230px; the translated box is centred by moving
     back one REACH, so its diameter must be exactly twice that distance. */
  inline-size: 460px;
  block-size: 460px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(217, 184, 255, 0.13) 0%,
    rgba(178, 91, 240, 0.1) 34%,
    rgba(109, 58, 212, 0.05) 58%,
    transparent 72%
  );
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  will-change: transform;
}

.tomb.is-lit .tomb__lamp {
  opacity: 1;
}

/* ── The carvings ──────────────────────────────────────────────────────── */

.tomb__ink {
  --lit: 0;
  --mx: 50%;
  --my: 50%;

  position: absolute;
  display: block;
  inline-size: max-content;
  max-inline-size: 22rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  line-height: 1.5;
  text-transform: uppercase;
  color: rgba(217, 184, 255, 0.88);
  text-shadow: 0 0 18px rgba(178, 91, 240, 0.5);
  white-space: nowrap;

  /* The pool of light, in this line's own coordinates. Nothing outside it
     exists — including the parts of this sentence he has not reached yet. */
  -webkit-mask-image: radial-gradient(
    circle var(--tomb-reach, 230px) at var(--mx) var(--my),
    #000 0%,
    rgba(0, 0, 0, 0.62) 52%,
    transparent 78%
  );
  mask-image: radial-gradient(
    circle var(--tomb-reach, 230px) at var(--mx) var(--my),
    #000 0%,
    rgba(0, 0, 0, 0.62) 52%,
    transparent 78%
  );
  opacity: var(--lit);
  transform: translate(-50%, -50%);
  transition: opacity 0.28s linear;
}

/* A margin carving runs with the wall it is scratched into. */
.tomb__ink--margin {
  writing-mode: vertical-rl;
  letter-spacing: 0.42em;
  transform: translate(-50%, calc(-50% + 0.21em));
  font-size: 0.56rem;
  color: rgba(217, 184, 255, 0.72);
}

/* Interior inscriptions are horizontal projections rather than gutter
   scratches. A faint backing keeps them readable when Vael carries the light
   across an illustration or a normal paragraph, while the mask still makes
   every part outside his pool of light completely absent. */
.tomb__ink--field {
  padding: 0.2rem 0.4rem 0.22rem 0.55rem;
  border-inline-start: 1px solid rgba(217, 184, 255, 0.48);
  background: linear-gradient(90deg, rgba(178, 91, 240, 0.11), transparent 82%);
  color: rgba(235, 220, 255, 0.98);
  text-shadow: 0 0 9px rgba(243, 240, 255, 0.72), 0 0 24px rgba(178, 91, 240, 0.72);
}

/* Arabic inscriptions use the site's Arabic face and natural joining. The
   signal name and number codes remain in their original display/mono faces. */
html[lang='ar'] .tomb__ink--line {
  direction: rtl;
  font-family: var(--font-ar);
  letter-spacing: 0.02em;
  line-height: 1.8;
  text-transform: none;
}

html[lang='ar'] .tomb__ink--line.tomb__ink--margin {
  letter-spacing: 0.02em;
}

/* The name of the thing under the site. Set the way the door sets it. */
.tomb__ink--mark {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.6vw, 2.1rem);
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: none;
  color: rgba(243, 240, 255, 0.94);
  text-shadow: 0 0 26px rgba(178, 91, 240, 0.55), 0 0 62px rgba(127, 212, 255, 0.22);
}

.tomb__ink--mark i {
  font-style: normal;
  color: var(--violet);
}

/* A number out in the gutter is a small scratch like any other line; it is
   only in a band, where there is room, that it is set as a number. */
.tomb__ink--code.tomb__ink--margin,
.tomb__ink--key.tomb__ink--margin {
  font-size: 0.66rem;
  letter-spacing: 0.44em;
  transform: translate(-50%, calc(-50% + 0.22em));
}

/* The number, and the key — which is the only one of these worth carrying
   away. Neither is localised: they are things you type, not quantities. */
.tomb__ink--code,
.tomb__ink--key {
  font-size: clamp(1.1rem, 2vw, 1.6rem);
  letter-spacing: 0.62em;
  /* Tracking is added after the last glyph, so the box is wider than the text
     on one side only. Half of it back, and the number sits where it looks
     centred rather than where it measures centred. */
  transform: translate(calc(-50% + 0.31em), -50%);
  color: rgba(243, 240, 255, 0.9);
  text-shadow: 0 0 24px rgba(178, 91, 240, 0.6);
}

/* The key is cut deeper than the decoy numbers around it: it is the one thing
   on these walls that does something, and somebody sweeping a light across a
   page in the dark has to be able to tell it apart from a date. */
.tomb__ink--key {
  color: rgba(249, 246, 255, 0.98);
  text-shadow: 0 0 18px rgba(178, 91, 240, 0.85), 0 0 46px rgba(127, 212, 255, 0.4);
}

@media (prefers-reduced-motion: reduce) {
  .tomb__lamp {
    transition-duration: 0.3s;
  }

  .tomb__ink {
    transition: none;
  }
}
