/* kahloon.com.au v3 prototype — engraved brass on near-black. Palette source of truth: /assets SVGs. */

:root {
  --bg: #0E0D0B;
  --bg-deep: #0A0908;
  --bg-warm: #141210;
  --bone: #E7E0D2;
  --stone: #958F81;
  --brass: #A98F5F;
  --brass-bright: #C9A96A;
  --gleam: #F4E6C2;
  --lapis: #4E6FA8;
  --lapis-bright: #5F7FBE;
  --track: 0.42em;
  --serif: "Palatino Linotype", Palatino, "Book Antiqua", "Iowan Old Style", Georgia, serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

body {
  /* the #ground vignette and warm halo, approximated: hidden at rest under the opaque #ground,
     it is what shows wherever the canvas does not reach while a relayout is pending */
  background:
    linear-gradient(rgba(128, 128, 128, 0.039), rgba(128, 128, 128, 0.039)),   /* the grain's mean */
    radial-gradient(circle calc(min(42vw, 30vh) * 1.9) at 50% 60%, rgba(201, 169, 106, 0.035) 47.4%, rgba(201, 169, 106, 0)),
    radial-gradient(circle 85vmax at 50% 56%, #16130F, #0E0D0B 45%, #090807) var(--bg);
  color: var(--bone);
  font-family: var(--mono);
  -webkit-font-smoothing: antialiased;
}

/* the first painted frame, before any JS: one brass point at the instrument centre (C = 50%, 60%).
   It sits above the canvases, so the canvas's own prick (drawn beneath it from frame 0) takes over
   seamlessly when JS sets body.live after its first frame; with no JS it stays: the point alone is
   the no-JS composition. */
body::before {
  content: '';
  position: fixed;
  z-index: 1;
  left: 50%;
  top: 60vh;
  top: 60dvh;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: #C9A96A;
  box-shadow: 0 0 14px 3px rgba(201, 169, 106, 0.3);
  pointer-events: none;
  transition: opacity 0.6s;
}
body.live::before { opacity: 0; }

/* ---------- the sky layers (created by js/instrument.js, back to front: ground, deep, field) ---------- */

/* the vignette, halo and grain, painted once per layout; JS pins its box like #field's */
#ground {
  position: fixed;
  z-index: 0;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: block;
  transform-origin: 0 0;
  pointer-events: none;
}

/* the deep field: a square larger than the viewport, centred on the pivot (JS sets its box),
   turned by the compositor alone. Its backing store is 0.75 css px per px: the upscale is its softness. */
.sky-deep {
  position: fixed;
  z-index: 0;
  display: block;
  opacity: 0;
  will-change: transform, opacity;
  pointer-events: none;
}

/* ---------- the instrument ---------- */

#field {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  transform-origin: 0 0;   /* JS pins the box to the laid-out size and maps it during a pending relayout */
  touch-action: manipulation;
  cursor: crosshair;
  outline: none;
}

/* F6: the grip over the instrument (JS clips it to a 1.25R disc; clip-path clips hit-testing too).
   One finger on it turns the rete instead of panning; a pinch still zooms. JS sets the cursor. */
.grip {
  position: fixed;
  inset: 0;
  z-index: 1;
  background: transparent;
  touch-action: pinch-zoom;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  cursor: crosshair;
}

#field { -webkit-tap-highlight-color: transparent; }

/* #24: 0.7 keeps the 1px hairline at about 4.4-4.7:1 against the ground and halo (3:1 is the minimum) */
#field:focus-visible {
  outline: 1px solid rgba(201, 169, 106, 0.7);
  outline-offset: -8px;
}
/* F6: focus given by a press on the grip is a pointer's focus: no ring (JS clears data-pf on blur) */
#field[data-pf]:focus-visible { outline: none; }

/* ---------- identity ---------- */

.identity {
  position: fixed;
  z-index: 2;
  left: 0;
  right: 0;
  top: clamp(36px, 9vh, 110px);
  text-align: center;
  pointer-events: none;
  user-select: none;
  /* landscape guard: JS sets --wm-scale (0.7..1) only when the block would touch the suspension ring */
  transform: scale(var(--wm-scale, 1));
  transform-origin: top center;
}

/* Letter-spacing adds space after the last letter too, which pushes a tracked
   wordmark left of centre. Pad the left by the same amount to re-centre it. */
.wordmark {
  margin: 0;
  padding-left: var(--track);
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.9rem, 4.4vw, 3.4rem);
  line-height: 1.1;
  letter-spacing: var(--track);
  white-space: nowrap;
  font-kerning: none;
}

.wordmark span {
  display: inline-block;
  color: transparent;
  background: linear-gradient(105deg,
      var(--bone) 0 42%, var(--gleam) 47.5%, #FFF6DE 50%, var(--gleam) 52.5%, var(--bone) 58% 100%)
    100% 0 / 400% 100% no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  text-shadow: 0 0 24px rgba(201, 169, 106, 0.10);
  animation:
    letter 1.9s cubic-bezier(0.22, 1, 0.36, 1) calc(1.1s + var(--d) * 0.11s) both,
    gleam 2.4s cubic-bezier(0.45, 0, 0.25, 1) calc(2.9s + var(--i) * 0.07s) both;
}

/* letters settle from the centre outward, like a reading coming into focus */
.wordmark span:nth-child(1) { --i: 0; --d: 3; }
.wordmark span:nth-child(2) { --i: 1; --d: 2; }
.wordmark span:nth-child(3) { --i: 2; --d: 1; }
.wordmark span:nth-child(4) { --i: 3; --d: 0; }
.wordmark span:nth-child(5) { --i: 4; --d: 1; }
.wordmark span:nth-child(6) { --i: 5; --d: 2; }
.wordmark span:nth-child(7) { --i: 6; --d: 3; }

/* a minted star sends one more gleam across the wordmark (class toggled by JS). F8: it travels the way the
   star flew: ga / gb left to right, gr right to left (the last letter first). Each is also written under
   .first, which would otherwise re-time it with the entrance's centre-out delays (.first .wordmark span);
   these stay above .first:not(.seated), which must keep winning before the seat */
.wordmark.ga span, .first .wordmark.ga span { animation: gleam-a 2.4s cubic-bezier(0.45, 0, 0.25, 1) calc(var(--i) * 0.07s) both; }
.wordmark.gb span, .first .wordmark.gb span { animation: gleam-b 2.4s cubic-bezier(0.45, 0, 0.25, 1) calc(var(--i) * 0.07s) both; }
.wordmark.gr span, .first .wordmark.gr span { animation: gleam-r 2.4s cubic-bezier(0.45, 0, 0.25, 1) calc((6 - var(--i)) * 0.07s) both; }

@keyframes letter {
  from { opacity: 0; transform: translateY(0.22em); filter: blur(7px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes gleam {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}
@keyframes gleam-a { from { background-position: 100% 0; } to { background-position: 0 0; } }
@keyframes gleam-b { from { background-position: 100% 0; } to { background-position: 0 0; } }
@keyframes gleam-r { from { background-position: 0 0; } to { background-position: 100% 0; } }

.line {
  margin: 1.7em 0 0;
  padding-left: 0.16em;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  color: var(--stone);
  animation: settle 2.2s cubic-bezier(0.22, 1, 0.36, 1) 2.2s both;
}

@keyframes settle {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* first visit: the wordmark waits for the instrument to seat (classes set by JS). Until body.seated
   it has no animation at all and opacity 0, so nothing can run early (the animations may have
   started before JS added .first); at the seat they start fresh, timed from that moment. With no
   JS, .first is never added; JS also sets .seated after 5 s if the entrance has stalled. */
.first .wordmark span {
  animation-delay: calc(var(--d) * 0.11s), calc(1.8s + var(--i) * 0.07s);
}
.first .line { animation-delay: 1.0s; }
.first:not(.seated) .wordmark span,
.first:not(.seated) .line {
  animation: none;
  opacity: 0;
}

/* ---------- engravings ---------- */

.hint {
  position: fixed;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: max(clamp(16px, 3vh, 34px), env(safe-area-inset-bottom, 0px));
  margin: 0;
  padding-left: 0.34em;
  text-align: center;
  font-size: 0.62rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--stone);
  opacity: 0;
  transition: opacity 1.6s ease;
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
}
.hint.show { opacity: 0.9; }   /* #24: about 4.8:1 on the halo and grain under it (AA 4.5), still below the line */
.hint.gone { opacity: 0; transition-duration: 0.9s; }

.engraving {
  position: fixed;
  z-index: 2;
  margin: 0;
  font-size: 0.6rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--stone);
  opacity: 0.55;
  pointer-events: none;
  user-select: none;
}

.local {
  right: clamp(28px, 5vw, 80px);
  bottom: max(22px, env(safe-area-inset-bottom, 22px));
  font-variant-numeric: tabular-nums;
  opacity: 0;                 /* engraved in last (JS sets .on: after the hint on a first visit) */
  transition: opacity 1.8s;
}
.local.on { opacity: 0.55; }

/* ---------- mobile ---------- */

@media (max-width: 720px) {
  :root { --track: 0.34em; }
  .wordmark { font-size: clamp(1.4rem, 7.6vw, 2.1rem); }
  .line { font-size: 0.66rem; }
  .local { display: none; }
}

/* ---------- landscape phones: keep the wordmark block clear of the suspension ring ---------- */

@media (max-height: 520px) {
  .identity { top: clamp(14px, 9vh, 110px); }
  .wordmark { font-size: clamp(1.2rem, 6.4vh, 2.2rem); }
  .line { margin-top: .8em; font-size: .6rem; }
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  /* finish the entrance at once instead of removing it: an animation that is removed and
     re-added replays from opacity 0, so switching reduced motion off mid-visit would blank
     the wordmark. A finished animation only re-times, and stays finished. */
  .wordmark span, .wordmark.ga span, .wordmark.gb span, .wordmark.gr span, .line {
    animation-duration: 1ms !important;
    animation-delay: -60s !important;
  }
  .wordmark span { background-position: 0 0; }
  .hint { transition: opacity 0.3s ease; }
}
