/* --------------------------------------------------------------------------
   Chrome only. Everything in the story itself is drawn on the canvas.
   -------------------------------------------------------------------------- */

/* If you receive the final display font as a file, drop it in assets/fonts/,
   uncomment this, and set FONTS.display = "'Invite Display', ..." in config.js.

@font-face {
  font-family: 'Invite Display';
  src: url('../assets/fonts/display.woff2') format('woff2');
  font-weight: 400 900;
  font-display: swap;
}
*/

:root {
  --cream: #f3efe6;
  --ink: #241d18;
  --marigold: #e9a72c;
  --chilli: #b8362c;
}

* { box-sizing: border-box; }

/* The `hidden` attribute must actually win.
   The browser's own sheet says [hidden] { display: none }, but that is only
   (0,1,0) specific, so ANY rule here that sets `display` on an id or class
   silently beats it and the element stays on screen with hidden="" set.
   That is exactly what put REPLAY and END AR on screen from page load:
   #ending-ui declares `display: flex` (1,0,0) and .ui-row declares it too
   (same weight, later in the file), so both outranked [hidden] while the
   JS below went on believing the attribute was doing its job.
   All the show/hide logic in main.js drives `.hidden`, so make it
   authoritative once, here, rather than patching each element. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  font-family: 'Baloo 2', 'Trebuchet MS', system-ui, sans-serif;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
  /* Without this, a real touch drag (unlike a mouse drag on desktop) can be
     claimed mid-gesture by the browser's own touch handling — edge-swipe
     back/forward navigation, pull-to-refresh, overscroll bounce — which
     fires pointercancel and kills the pointermove stream the airport drag
     in main.js (initDrag) depends on. There is nothing here to scroll or
     zoom, so disabling every native touch gesture is safe. */
  touch-action: none;
  -ms-touch-action: none;
}

/* Only the root element carries a background colour, and this matters.
   AR.js injects the live camera as <video id="arjs-video"> into <body>
   with an inline z-index:-2. A negative z-index paints above the root's
   background but BELOW body's own background box, so any opaque
   background on <body> covers the camera feed completely — the camera
   runs and permission is granted, yet the screen stays solid black.
   Preview mode sets its own body background below (higher specificity)
   and never creates a video, so it is unaffected. */
html { background: #141210; }
body { background: transparent; }

/* The canvas lives off-screen while it is only a texture source. */
#stage {
  position: fixed;
  left: -10000px;
  top: 0;
}

/* Preview mode (?preview=1) shows the same canvas full-bleed, no camera. */
body.preview { background: var(--cream); }

body.preview #stage {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: auto;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
  image-rendering: auto;
}

/* AR.js injects the video + canvas; keep them behind the overlay. */
#ar-root { position: fixed; inset: 0; }
.a-enter-vr, .a-enter-ar, .a-orientation-modal { display: none !important; }

#overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: end center;
  padding: 0 20px calc(28px + env(safe-area-inset-bottom));
  pointer-events: none;
  z-index: 10;
}

#overlay > div {
  pointer-events: auto;
  max-width: 22rem;
  text-align: center;
  color: var(--cream);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .55);
}

#loader {
  place-self: center;
  color: var(--ink);
}

body:not(.preview) #loader { color: var(--cream); }

#loader p { margin: 14px 0 0; font-size: 1rem; letter-spacing: .01em; }

.spinner {
  width: 34px;
  height: 34px;
  margin: 0 auto;
  border: 3px solid rgba(233, 167, 44, .28);
  border-top-color: var(--marigold);
  border-radius: 50%;
  animation: spin 900ms linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.hint-title {
  margin: 0 0 6px;
  font-size: 1.18rem;
  font-weight: 800;
}

.hint-sub {
  margin: 0;
  font-size: .92rem;
  font-weight: 600;
  opacity: .85;
  line-height: 1.45;
}

#hint { animation: float-up 420ms ease-out both; }
#hint-sub { white-space: pre-line; }

/* Pre-story screen only: opaque from its first frame, including rotation. */
#overlay > #hint.start-card {
  position: fixed;
  inset: 0;
  max-width: none;
  padding: max(20px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right))
           max(20px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: var(--marigold);
  color: var(--ink);
  text-shadow: none;
  animation: none;
}
#hint.start-card .hint-title {
  max-width: 24ch;
  margin: 0;
  font-size: clamp(1.7rem, 6vh, 3rem);
  line-height: 1.1;
}
#hint.start-card .hint-sub { max-width: 38ch; opacity: 1; }
#hint.start-card #hint-volume { font-size: .8rem; }
#btn-begin:disabled { opacity: .6; cursor: default; }

@keyframes float-up {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

#preview-btn {
  margin-top: 14px;
  padding: 11px 20px;
  font: inherit;
  font-weight: 800;
  color: #2a211a;
  background: var(--marigold);
  border: 0;
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
}

#preview-btn:active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.4s; }
  #hint { animation: none; }
}

/* ==========================================================================
   DRAG TO TRAVEL — screen UI
   A normal fixed-position DOM card, deliberately not part of the AR world:
   no marker transform, no canvas, no A-Frame entity. It stays put on the
   glass while the film moves with the card on the table.
   ========================================================================== */

#travel {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  /* clear of the home indicator / browser chrome on every handset */
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  width: min(92vw, 27rem);
  padding: 14px 18px 12px;
  background: #fbf8f1;
  border-radius: 22px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
  /* the overlay above is pointer-events:none; this card opts back in */
  pointer-events: auto;
  z-index: 20;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;            /* the drag owns the gesture */
  /* NOT the shared float-up used by #hint. That one ends on
     `transform: none`, and animation-fill-mode:both keeps the final
     keyframe applied for good — CSS animations outrank normal
     declarations, so it wiped out the translateX(-50%) above and left the
     card's LEFT EDGE sitting at screen centre, hanging off the right of
     the phone. Any keyframes this element uses must carry the centring
     translate through every step. */
  animation: travel-in 300ms ease-out both;
}

/* #overlay > div caps its children at 22rem for the hint paragraph, and
   that leaked onto this card. It has to be beaten on specificity — a plain
   `#travel { max-width: none }` is (1,0,0) and loses to (1,0,1). */
#overlay > #travel { max-width: none; text-shadow: none; }

@keyframes travel-in {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to   { opacity: 1; transform: translateX(-50%); }
}

.travel-title {
  margin: 0 0 12px;
  text-align: center;
  font-size: .95rem;
  font-weight: 800;
  letter-spacing: .08em;
  color: var(--ink);
}

.travel-arrow { margin-left: .15em; }
.travel-context { margin-bottom: 6px; font-size: .82rem; }

/* the track ------------------------------------------------------------- */
.travel-track {
  position: relative;
  height: 40px;
  margin: 0 6px;
}

.travel-line,
.travel-fill {
  position: absolute;
  top: 50%;
  height: 3px;
  margin-top: -1.5px;
  border-radius: 2px;
}

.travel-line {
  left: 0; right: 0;
  background: repeating-linear-gradient(to right,
    rgba(36, 29, 24, .28) 0 7px, transparent 7px 14px);
}

/* solid marigold behind the journey already travelled */
.travel-fill {
  left: 0;
  width: var(--travel-progress, 0%);
  background: var(--marigold);
  transition: width 260ms ease-out;
}

.travel-dots i {
  position: absolute;
  left: var(--stop);
  top: 50%;
  width: 11px; height: 11px;
  margin: -5.5px 0 0 -5.5px;
  border-radius: 50%;
  background: #d8d2c6;
  transition: background 200ms ease-out, transform 200ms ease-out;
}
.travel-dots i.done { background: var(--marigold); }
.travel-dots i.next { background: var(--chilli); transform: scale(1.25); }

/* the draggable plane ---------------------------------------------------- */
.travel-plane {
  position: absolute;
  top: 50%;
  left: var(--travel-progress, 0%);
  width: 46px;
  height: auto;
  margin-top: -23px;
  margin-left: -23px;
  cursor: grab;
  touch-action: none;
  -webkit-user-drag: none;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .25));
  transition: left 300ms cubic-bezier(.3, .9, .35, 1);
}
/* while the finger is down the plane must track it with no easing lag */
#travel.dragging .travel-plane { transition: none; cursor: grabbing; }

/* dimmed and inert between legs, while the film flies to the next stop */
#travel:not(.ready) .travel-plane { opacity: .45; }
#travel:not(.ready) { opacity: .82; }

/* labels ----------------------------------------------------------------- */
.travel-labels {
  display: flex;
  justify-content: space-between;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
  font-size: .62rem;
  font-weight: 800;
  letter-spacing: .06em;
  color: #9a9186;
}
.travel-labels li { flex: 1; text-align: center; }
.travel-labels li:first-child { text-align: left; }
.travel-labels li:last-child { text-align: right; }
.travel-labels li.done { color: var(--marigold); }
.travel-labels li.next { color: var(--ink); }

/* Preview is a desktop dev view; the same card works there unchanged. */
@media (max-height: 460px) {
  #travel { bottom: calc(8px + env(safe-area-inset-bottom, 0px)); padding: 9px 14px 8px; }
  .travel-track { height: 32px; }
  .travel-plane { width: 38px; margin-top: -19px; margin-left: -19px; }
}

/* Landscape: bottom text and a narrow right-edge downward drag rail.
   Keep the transparent screen-space wrapper out of the pointer hit area. */
@media (orientation: landscape) {
  #travel {
    --travel-rail-height: min(50vh, 240px, calc(100vh - 160px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)));
    /* Explicit viewport bounds avoid shrink-to-content sizing in #overlay's
       end-aligned grid. Children below are fixed to the screen themselves. */
    inset: 0 auto auto 0;
    width: 100vw;
    width: 100dvw;
    height: 100vh;
    height: 100dvh;
    margin: 0;
    padding: 0;
    background: transparent;
    border-radius: 0;
    box-shadow: none;
    transform: none;
    pointer-events: none;
    animation-name: travel-in-landscape;
  }
  #travel .travel-copy {
    position: fixed;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%);
    width: max-content;
    max-width: calc(100% - 2 * max(24px, env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px)));
    padding: 6px 12px;
    background: #fff;
    pointer-events: auto;
  }
  #travel .travel-copy, #travel .travel-copy * {
    text-shadow: none;
    filter: none;
    box-shadow: none;
    outline: none;
    -webkit-text-stroke: 0;
  }
  #travel .travel-title { margin-bottom: 4px; line-height: 1.2; }
  #travel .travel-context { margin-bottom: 3px; }
  #travel .travel-title:last-child { margin-bottom: 0; }
  #travel .travel-track, #travel .travel-labels {
    position: fixed;
    top: calc((100vh - var(--travel-rail-height) + env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) / 2 + 8px);
    top: calc((100dvh - var(--travel-rail-height) + env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) / 2 + 8px);
    bottom: auto;
  }
  #travel .travel-track {
    right: calc(72px + env(safe-area-inset-right, 0px));
    width: 44px;
    height: var(--travel-rail-height);
    margin: 0;
    pointer-events: auto;
  }
  #travel .travel-line, #travel .travel-fill {
    top: 0;
    left: 50%;
    right: auto;
    width: 3px;
    margin: 0 0 0 -1.5px;
  }
  #travel .travel-line {
    height: 100%;
    background: repeating-linear-gradient(to bottom,
      rgba(36, 29, 24, .28) 0 7px, transparent 7px 14px);
  }
  #travel .travel-fill {
    height: var(--travel-progress, 0%);
    transition: height 260ms ease-out;
  }
  #travel .travel-dots i { left: 50%; top: var(--stop); }
  #travel .travel-plane {
    top: var(--travel-progress, 0%);
    left: 50%;
    width: 38px;
    height: 48px;
    margin: -48px 0 0 -19px;
    filter: none;
    transition: top 300ms cubic-bezier(.3, .9, .35, 1);
  }
  #travel.dragging .travel-plane { transition: none; }
  #travel .travel-labels {
    right: calc(8px + env(safe-area-inset-right, 0px));
    width: 64px;
    height: var(--travel-rail-height);
    margin: 0;
    display: block;
  }
  #travel .travel-labels li {
    position: absolute;
    top: var(--stop);
    transform: translateY(-50%);
    text-align: left;
  }
  @supports (height: 100dvh) {
    #travel {
      --travel-rail-height: min(50dvh, 240px, calc(100dvh - 160px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)));
    }
  }
}

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

/* ==========================================================================
   ENDING CONTROLS — screen UI
   Same footing as #travel: fixed to the viewport, never part of the AR world.
   ========================================================================== */

#ending-ui {
  position: fixed;
  left: 50%;
  bottom: calc(26px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  width: min(92vw, 27rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  pointer-events: auto;
  z-index: 20;
}
/* the hint card's 22rem cap is meant for the paragraph, not for these */
#overlay > #ending-ui { max-width: none; }

.ui-row {
  display: flex;
  justify-content: center;
  gap: 12px;
  width: 100%;
}

/* WHITE ONLY. No border, no stroke, no outline, no coloured edge — the
   shadow does the lifting, so nothing draws a line around the button. */
.ui-btn {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  border-width: 0;
  border-style: none;
  outline: 0;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .26);
  background: #ffffff;
  color: var(--ink);
  font: inherit;
  font-weight: 800;
  font-size: .92rem;
  letter-spacing: .08em;
  /* comfortably past the 44px minimum touch target */
  min-height: 52px;
  padding: 15px 30px;
  border-radius: 999px;
  text-shadow: none;
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.ui-btn:focus,
.ui-btn:focus-visible { outline: 0; box-shadow: 0 8px 22px rgba(0, 0, 0, .26); }
.ui-btn:active { transform: translateY(1px); }
.ui-row .ui-btn { flex: 1; max-width: 12rem; }

/* NOT travel-in — that one ends on translateX(-50%), which centres a
   fixed-position card but would shove this flex child half its width to the
   left. This one touches opacity and Y only. */
@keyframes ui-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
#btn-kiss, #ending-final { animation: ui-in 280ms ease-out both; }
