/* The closing screen. Without JS (and with reduced motion) it is simply
   crimson with white text. end.js arms it ([data-armed]): the section becomes
   a runway (.end-run) with the stage pinned on screen, and the crimson arrives
   as the room behind Headroom's door (.end-room), zoomed by the scroll; the
   words come in on red once the icon is nearly home ([data-in]). */

.end { position: relative; z-index: 1; padding-top: 0; padding-bottom: 0; }
.end-stage {
  position: relative;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column; align-items: center;
  padding-top: max(120px, 16vh); padding-bottom: 40px;
}
.end-stage > .h2, .end-stage > .join-note { width: 100%; }
.end .end-icon { margin-top: auto; }
.end .h2 { text-wrap: balance; }
.end .join-note { margin-bottom: 96px; }
.end .foot { width: 100%; margin-top: auto; }

/* not armed: the section itself is crimson, edge to edge (the shadow paints
   past the column without widening the page; the clip keeps it to the section) */
.end:not([data-armed]) {
  background: var(--crimson);
  box-shadow: 0 0 0 100vmax var(--crimson);
  clip-path: inset(0 -100vmax);
}

/* armed: the stage is the large screen tall (toolbars hidden) and holds still
   while the runway scrolls; its content keeps to the small screen, so nothing
   sits under a toolbar that slides back in */
.end[data-armed] .end-stage {
  position: sticky; top: 0;
  min-height: 100vh; min-height: 100lvh;
  padding-bottom: 40px; padding-bottom: calc(40px + 100lvh - 100svh);
}
.end-run { height: 110vh; height: 110svh; }

/* the room: full-bleed, reaching a screen above the stage so the start of the
   move can cover what is still on screen above it; clipped to itself, so the
   page never grows */
.end-room {
  position: absolute; z-index: -1;
  top: -100vh; top: -100lvh;
  left: calc(50% - 50vw); width: 100vw;
  height: calc(100% + 100vh); height: calc(100% + 100lvh);
  overflow: hidden; pointer-events: none; visibility: hidden;
}
.end-room[data-on] { visibility: visible; }
.end:not([data-armed]) .end-room { display: none; }
/* the wall is hit-testable, so the menubar sees #join wherever it is red */
.end-room-wall { fill: var(--crimson); pointer-events: visiblePainted; }
.end-room-light { fill: var(--bg); visibility: hidden; }
.end-room-light[data-on] { visibility: inherit; }
.end .end-icon[data-away] { opacity: 0; }

/* the words wait on the paper side of the door, then arrive on red */
.end[data-armed] .end-stage > :not(.end-room):not(.end-icon) {
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity 0.35s ease, transform 0.6s var(--out);
}
.end[data-armed] .end-stage[data-in] > :not(.end-room):not(.end-icon) { opacity: 1; transform: none; pointer-events: auto; }
.end[data-armed] .end-stage[data-in] > .lvl { transition-delay: 0.06s; }
.end[data-armed] .end-stage[data-in] > .join-note { transition-delay: 0.1s; }
.end[data-armed] .end-stage[data-in] > .foot { transition-delay: 0.14s; }
.end-stage[data-snap], .end-stage[data-snap] * { transition: none !important; }

/* a link to #join lands on the finished screen, past the runway */
#join { scroll-margin-top: -110vh; scroll-margin-top: -110svh; }

/* colour flips are one-off transitions, never per frame */
.end .end-icon { position: relative; transition: box-shadow 0.5s var(--out), outline-color 0.5s var(--out); outline: 1px solid transparent; outline-offset: -1px; }
.end .h2, .end .join-note, .end .lvl-tag, .end .done-mark, .end .foot, .end .foot a { transition: color 0.45s var(--out), border-color 0.45s var(--out); }
.end .join, .end .join button { transition: box-shadow 0.45s var(--out), background-color 0.45s var(--out), transform 0.2s var(--out), opacity 0.2s; }
.end .end-icon[data-red] { outline-color: rgba(255, 255, 255, 0.22); box-shadow: 0 30px 60px -22px rgba(40, 0, 8, 0.7); }
.end .h2[data-red] { color: #fff; }
.end .lvl[data-red] .join { box-shadow: 0 18px 40px -18px rgba(40, 0, 8, 0.6); }
.end .lvl[data-red] .join:focus-within { box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.4), 0 18px 40px -18px rgba(40, 0, 8, 0.6); }
.end .lvl[data-red] .join button { background: var(--crimson); }
.end .join-note[data-red] { color: rgba(255, 255, 255, 0.78); }
.end .join-note[data-red][data-tone="error"] { color: #fff; font-weight: 600; }
.end .lvl[data-red] .done-mark { color: #fff; }
.end .lvl[data-red] .lvl-tag { color: rgba(255, 255, 255, 0.78); }
.end .foot[data-red] { color: rgba(255, 255, 255, 0.72); border-top-color: rgba(255, 255, 255, 0.24); }
.end .foot[data-red] a { color: #fff; }
.end .foot[data-red] a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 560px) {
  .end-stage { padding-top: max(96px, 13vh); }
  .end .join-note { margin-bottom: 72px; }
  .end .join input { padding-left: 14px; font-size: 16px; }
  .end .join button { padding: 0 18px; font-size: 15px; }
  .lvl .done-mark { font-size: 18px; }
}

/* ---------- Level 0: the form is the first level ----------
   end.js sets .lvl[data-state] to "pending" while the write is in flight and
   "done" once it lands; [data-still] means it was already cleared on arrival. */

.lvl { width: min(100%, 460px); margin: 40px auto 0; }
.lvl-tag { display: grid; font: 500 12px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.lvl-tag > span { grid-area: 1 / 1; transition: opacity 0.3s var(--out), transform 0.4s var(--out); }
.lvl-off { opacity: 0; transform: translateY(6px); }
.lvl-slot { position: relative; height: 56px; margin-top: 16px; }

.lvl .join { transition: box-shadow 0.45s var(--out), opacity 0.22s ease, transform 0.32s var(--out); }

.lvl-seal {
  position: absolute; left: 50%; top: 0; width: 56px; height: 56px; margin-left: -28px;
  border-radius: 50%; background: var(--crimson); color: #fff;
  opacity: 0; transform: scale(0.4); pointer-events: none;
  transition: opacity 0.18s ease, transform 0.5s var(--spring), background-color 0.45s var(--out), color 0.45s var(--out);
}
.lvl[data-red] .lvl-seal { background: #fff; color: var(--crimson); box-shadow: 0 18px 40px -18px rgba(40, 0, 8, 0.6); }
.lvl-seal svg { position: absolute; inset: 0; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.lvl-arc { stroke-width: 2.5; stroke-dasharray: 52 100; transform-origin: 28px 28px; transition: opacity 0.16s ease; }
.lvl-chk { stroke-width: 3.6; stroke-dasharray: 26 30; stroke-dashoffset: 26; opacity: 0; }

/* in flight: the field steps back, the seal comes forward and spins */
.lvl[data-state] .join { opacity: 0; transform: scale(0.92); pointer-events: none; }
.lvl[data-state] .lvl-seal { opacity: 1; transform: none; }
.lvl[data-state="pending"] .lvl-arc { animation: lvl-spin 0.8s linear infinite; }

/* cleared: the spinner gives way to the check, the seal settles once */
.lvl[data-state="done"] .lvl-arc { opacity: 0; }
.lvl[data-state="done"] .lvl-chk { transition: stroke-dashoffset 0.38s cubic-bezier(0.65, 0, 0.35, 1) 0.12s, opacity 0s 0.12s; stroke-dashoffset: 0; opacity: 1; }
/* then it steps left to make room for the line beside it (--tw: that line's width, from end.js) */
.lvl[data-state="done"] .lvl-seal { transform: translateX(calc((var(--tw, 0px) + 14px) / -2)); transition: opacity 0.18s ease, transform 0.55s var(--out) 0.62s, background-color 0.45s var(--out), color 0.45s var(--out); }
.lvl[data-state="done"] .lvl-seal { animation: lvl-settle 0.5s var(--out) 0.36s; }
.lvl[data-state="done"] .lvl-on { opacity: 0; transform: translateY(-6px); }
.lvl[data-state="done"] .lvl-off { opacity: 1; transform: none; transition-delay: 0.3s; }
.lvl .done-mark {
  position: absolute; left: 50%; top: 0; margin: 0; white-space: nowrap;
  line-height: 56px; transform: translateX(calc(35px - 50%));
}
.lvl .done-mark:focus { outline: none; }
.lvl[data-state="done"] .done-mark { animation: lvl-rise 0.45s var(--out) 0.72s both; }

.lvl[data-still] *, .lvl[data-still] .done-mark { transition: none !important; animation: none !important; }

@keyframes lvl-spin { to { transform: rotate(360deg); } }
@keyframes lvl-settle { 40% { scale: 1.08; } }
@keyframes lvl-rise { from { opacity: 0; transform: translateX(calc(23px - 50%)); } }

@media (prefers-reduced-motion: reduce) {
  /* a spinner still spins, slower */
  .lvl[data-state="pending"] .lvl-arc { animation-duration: 1.6s !important; animation-iteration-count: infinite !important; }
}

/* ---------- me: the other apps fan out from behind Headroom, once ---------- */
.icons[data-arm] .ic { animation: none; }
.icons[data-arm]:not([data-in]) .ic { opacity: 0; }
.icons[data-arm]:not([data-in]) .ic-hr { opacity: 0; transform: scale(0.82); }
.icons[data-in] .ic-hr { animation: me-pop 0.6s var(--spring) both; }
.icons[data-in] .ic-1 { animation: me-fan-1 0.75s var(--spring) 0.18s both; }
.icons[data-in] .ic-2 { animation: me-fan-2 0.75s var(--spring) 0.24s both; }
.icons[data-in] .ic-3 { animation: me-fan-3 0.75s var(--spring) 0.30s both; }
.icons[data-in] .ic-4 { animation: me-fan-4 0.75s var(--spring) 0.36s both; }
.icons[data-done] .ic { animation: none; }
@keyframes me-pop { from { opacity: 0; transform: scale(0.82); } }
@keyframes me-fan-1 { from { opacity: 0; transform: translate(70%, 62%) scale(0.86); } 20% { opacity: 1; } }
@keyframes me-fan-2 { from { opacity: 0; transform: translate(-72%, 72%) scale(0.86); } 20% { opacity: 1; } }
@keyframes me-fan-3 { from { opacity: 0; transform: translate(82%, -56%) scale(0.86); } 20% { opacity: 1; } }
@keyframes me-fan-4 { from { opacity: 0; transform: translate(-78%, -50%) scale(0.86); } 20% { opacity: 1; } }
