:root {
  color-scheme: dark;
  --bg: #000000;
  --ink: #f5f5f7;
  --ink-dim: rgba(245, 245, 247, 0.62);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  min-height: 100%;
}

html {
  scrollbar-width: none;
  overscroll-behavior-y: none;
}

html::-webkit-scrollbar {
  display: none;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Scroll runway, touch devices only: every visual element is fixed, but the
   document itself can scroll ~160px, so a single swipe collapses the mobile
   browser's bottom toolbar and the terrain claims the reclaimed area (the
   per-frame canvas guard follows the grown viewport). svh keeps the runway
   relative to the smallest viewport, so it still exists after the toolbar
   collapses. overscroll-behavior is already set on html for all devices.
   Desktop keeps a zero-scroll document. */
@media (hover: none) and (pointer: coarse) {
  body {
    min-height: calc(100svh + 160px);
  }
}

/* ---------- Background: voxel topography grid ---------- */

/* The visible size comes from JS (window.innerWidth/innerHeight, the only
   source that follows the mobile toolbar on every browser generation);
   the CSS 100% below is just the pre-JS fallback. width/height are then
   mirrored to the bitmap per frame — see voxel-background.js */
#voxel-bg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  display: block;
}

/* ---------- Stage: hello perfectly centered ---------- */

/* Fixed like the canvas so the wordmark stays centered in the visible
   viewport while the scroll runway moves the document behind it */
.stage {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 20px;
}

/* ---------- Hand-drawn wordmark ---------- */

/* Fluorescent bloom: stacked white halos. The terrain light pool underneath
   (see voxel-background.js) is the wordmark's reflection on the background */
#hello-svg {
  height: clamp(96px, 22vw, 168px);
  max-width: 92vw;
  overflow: visible;
  filter:
    drop-shadow(0 0 4px rgba(255, 255, 255, 0.85))
    drop-shadow(0 0 14px rgba(255, 255, 255, 0.5))
    drop-shadow(0 0 38px rgba(255, 255, 255, 0.32));
}

/* Replicates motion's pathLength 0 -> 1: dashoffset runs from full length to 0.
   main.js writes every path's dasharray/dashoffset inline before any paint,
   so no base rule is needed here. */
#hello-svg path.drawing {
  animation:
    draw-path var(--dur) var(--ease) var(--delay) both,
    fade-in var(--op-dur) linear var(--op-delay) both;
}

@keyframes draw-path {
  from {
    stroke-dashoffset: var(--len);
  }
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ---------- Live clock below the wordmark ---------- */

.clock {
  position: fixed;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: calc(max(28px, env(safe-area-inset-bottom)) + 30px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.7s ease,
    transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none; /* decorative overlay, never captures the pointer */
}

body.done .clock {
  opacity: 1;
  transform: none;
}

.clock-time {
  font-size: clamp(22px, 3.6vw, 34px);
  font-weight: 600;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums; /* stop digit jitter every second */
  color: var(--ink);
  text-shadow:
    0 0 4px rgba(255, 255, 255, 0.85),
    0 0 14px rgba(255, 255, 255, 0.5),
    0 0 38px rgba(255, 255, 255, 0.32);
}

.clock-date {
  color: var(--ink-dim);
  font-size: 12px;
  letter-spacing: 0.14em;
}

/* Short landscape viewports (phones rotated sideways, short windows): the
   bottom-anchored text stack would collide with the centered wordmark, so
   the wordmark scales with the viewport height and the clock anchors just
   under it instead of to the bottom edge. 32vh at the 480px boundary ≈ the
   base clamp maximum, so the wordmark barely changes when crossing it. */
@media (max-height: 480px) {
  #hello-svg {
    height: clamp(80px, 32vh, 168px);
  }

  .clock {
    bottom: auto;
    top: calc(50% + clamp(40px, 16vh, 84px) + 24px);
    gap: 4px;
  }

  .clock-time {
    font-size: clamp(18px, 5vh, 28px);
  }

  .clock-date {
    font-size: 10px;
  }

  .bottom {
    bottom: max(10px, env(safe-area-inset-bottom));
  }

  .credit {
    font-size: 10px;
  }
}

/* ---------- Bottom zone: signature + fullscreen control ---------- */

/* Wide invisible hover pad around the signature so the control is easy to
   reach; only interactive once the drawing has finished */
.bottom {
  position: fixed;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: max(16px, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 14px 32px 10px;
  opacity: 0;
  transition: opacity 0.7s ease;
}

body.done .bottom {
  opacity: 1;
}

body:not(.done) .bottom {
  pointer-events: none;
}

.credit {
  color: var(--ink-dim);
  font-size: 12px;
  letter-spacing: 0.08em;
  opacity: 0.75;
  transition: opacity 0.25s ease;
}

.bottom:hover .credit,
.bottom:focus-within .credit {
  opacity: 1;
}

/* Fullscreen control — hover to reveal; the fill animation ports the
   OriginButton reference: a circle grows from the pointer position to a
   diameter of 2x the farthest corner distance, inverting the label */
.fs-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 26px;
  overflow: hidden;
  border: 0.5px solid rgba(245, 245, 247, 0.22);
  border-radius: 12px;
  background: rgba(10, 10, 12, 0.55);
  color: var(--ink);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  cursor: pointer;
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition:
    opacity 0.25s ease,
    transform 0.25s ease,
    color 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.25s ease;
}

.bottom:hover .fs-btn,
.bottom:focus-within .fs-btn {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.fs-btn:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.6);
  outline-offset: 2px;
}

.fs-fill {
  position: absolute;
  left: var(--ox, 50%);
  top: var(--oy, 50%);
  width: var(--size, 0);
  height: var(--size, 0);
  border-radius: 999px;
  background: var(--ink);
  transform: translate(-50%, -50%) scale(0);
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
}

.fs-btn.is-filling {
  color: #000;
  border-color: var(--ink);
}

.fs-btn.is-filling .fs-fill {
  transform: translate(-50%, -50%) scale(1);
}

/* .bottom prefix keeps this at the same specificity as the hover reveal rule */
.bottom .fs-btn:active {
  transform: scale(0.985);
}

.fs-label {
  position: relative;
  z-index: 1;
}

.noscript-fallback {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(40px, 9vw, 72px);
  font-weight: 700;
}

/* Reduced motion: show the finished state immediately */
@media (prefers-reduced-motion: reduce) {
  .clock {
    transition: none;
  }
  .credit {
    transition: none;
  }
  #hello-svg path.drawing {
    animation: none;
  }
}
