/* The story page: a fixed stage, scroll as the playhead, one card per chapter, point tags, hotspot
   rings and the roadmap. Tokens (orange, blues, ink, type) come from shell.css; provisional brand, see DESIGN.md. */
:root { --roadmap-h: 84px; --stage-ground: #dfe6ee; accent-color: var(--vessco-orange); }
* { box-sizing: border-box; }
html, body { margin: 0; }
body.story { background: var(--stage-ground); color: var(--ink-2); font: 400 16px/1.6 var(--text); -webkit-font-smoothing: antialiased; }
button, a { font: inherit; color: inherit; }
.story :focus-visible { outline: 2px solid var(--vessco-blue); outline-offset: 3px; }

.boot {
  position: fixed; inset: 0; z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.5rem;
  padding: 0 var(--gutter); background: var(--paper); color: var(--muted); font: 600 1rem var(--text); letter-spacing: .04em;
  transition: opacity .4s ease;
}
.boot.is-hidden { opacity: 0; pointer-events: none; }
/* The loading lockup: Vessco, a hairline, "with", Local AI. Sizes are in --u so the whole lockup scales as
   one on a phone. The Local AI logo's own image draws the wordmark (its squares cut away); the squares are
   drawn in the logo's own units (17 square, 22 pitch) at the same place, so they can move. */
.boot { --u: 1px; --ease: cubic-bezier(.16, 1, .3, 1); }
.boot__lockup { display: flex; align-items: center; gap: calc(18 * var(--u)); }
.boot__vessco { flex: none; display: block; width: calc(210 * var(--u)); height: calc(56 * var(--u)); margin: 0 calc(-36 * var(--u)) 0 calc(-38 * var(--u)); }
.boot__rule { flex: none; width: 1px; height: calc(44 * var(--u)); background: #c9ced5; }
.boot__with { color: var(--muted); font: 500 calc(17 * var(--u)) / 1 var(--text); letter-spacing: .01em; }
/* At half the logo file's size, which a 2x screen draws pixel for pixel. */
.boot__lai { position: relative; flex: none; top: calc(5 * var(--u)); width: calc(168 * var(--u)); height: calc(60 * var(--u)); margin: 0 calc(-10 * var(--u)) 0 calc(-8 * var(--u)); }
.boot__word { display: block; width: 100%; height: 100%; clip-path: inset(0 0 0 calc(30 * var(--u))); }
.boot__squares { position: absolute; left: calc(7.5 * var(--u)); top: calc(17.5 * var(--u)); width: calc(19.5 * var(--u)); height: calc(19.5 * var(--u)); overflow: visible; }
.boot__sq { transform-box: fill-box; transform-origin: center; }
.boot__bar { width: calc(330 * var(--u)); max-width: 80vw; height: 2px; background: var(--rule); overflow: hidden; }

/* The moment the two marks meet. */
.boot__vessco { animation: boot-wipe .9s var(--ease) .1s both; }
.boot__rule { animation: boot-draw .5s var(--ease) .55s both; }
.boot__word { animation: boot-word .8s var(--ease) .7s both; }
.boot__sq--1 { animation: boot-settle .5s cubic-bezier(.3, 1.35, .5, 1) .7s both; }
.boot__sq--2 { animation: boot-settle .5s cubic-bezier(.3, 1.35, .5, 1) .78s both; }
.boot__sq--3 { animation: boot-settle .5s cubic-bezier(.3, 1.35, .5, 1) .86s both; }
.boot__sq--join { animation: boot-join 1.1s cubic-bezier(.55, 0, .2, 1) 1s both; }
.boot__with { animation: boot-fade .5s ease-out 1.75s both; }
.boot__bar, .boot__text { animation: boot-fade .5s ease-out 1.6s both; }
@keyframes boot-wipe { from { clip-path: inset(0 100% 0 0); transform: translateX(calc(-10 * var(--u))); } to { clip-path: inset(0 0 0 0); transform: none; } }
@keyframes boot-draw { from { transform: scaleY(0); } to { transform: none; } }
@keyframes boot-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes boot-word { from { clip-path: inset(0 100% 0 calc(36 * var(--u))); } to { clip-path: inset(0 0 0 calc(36 * var(--u))); } }
@keyframes boot-settle { from { opacity: 0; transform: scale(.35); } to { opacity: 1; transform: none; } }
/* From just past the Vessco wordmark (about 190 logo units to the left), across the hairline and the empty
   space where "with" then appears, into the last corner of the grid. */
@keyframes boot-join { 0% { opacity: 0; transform: translateX(-190px) scale(.6); } 15% { opacity: 1; } 100% { opacity: 1; transform: none; } }
.boot.is-calm *, .boot.is-failed .boot__lockup * { animation: none !important; }
@media (max-width: 520px) { .boot { --u: .66px; } .boot__with { font-size: 12px; } }
.boot__bar i { display: block; height: 100%; width: 38%; background: var(--vessco-orange); animation: boot-slide 1.4s ease-in-out infinite; }
.boot.is-determinate .boot__bar i { width: var(--p, 0%); animation: none; transition: width .3s ease; }
.boot.is-calm, .boot.is-calm .boot__bar i { animation: none; transition: none; }
.boot.is-failed .boot__bar i { animation: none; width: 0; }
.boot__text { text-align: center; }
/* A chapter still loading after the story started: a small status over the last drawn frame. */
.mh-wait { position: absolute; left: 50%; top: 50%; z-index: 3; transform: translate(-50%, -50%); display: grid; gap: 10px; justify-items: center; padding: 16px 22px; background: rgba(255, 255, 255, .92); color: var(--ink); font: 600 .95rem var(--text); box-shadow: 0 6px 24px rgba(0, 0, 0, .12); }
.mh-wait[hidden] { display: none; }
.mh-wait__bar { width: 180px; height: 3px; background: var(--rule); overflow: hidden; }
.mh-wait__bar i { display: block; height: 100%; width: 0; background: var(--vessco-orange); transition: width .3s ease; }
@keyframes boot-slide { from { transform: translateX(-100%); } to { transform: translateX(263%); } }

/* Stage */
.mh-stage { position: fixed; inset: 0; z-index: 1; overflow: hidden; background: var(--stage-ground); }
.mh-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: 0; transition: opacity .9s ease; }
.mh-stage.is-live .mh-canvas { opacity: 1; }
.mh-posters { position: absolute; inset: 0; display: none; }
.mh-stage.is-stills .mh-posters { display: block; }
.mh-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .25s linear; }
.mh-poster.is-missing { visibility: hidden; }
.mh-track { position: relative; z-index: 0; pointer-events: none; }

/* Story cards: white, an orange top bar, text in ink. */
.mh-copy-layer { position: fixed; inset: 0; z-index: 12; pointer-events: none; }
.mh-card {
  position: absolute; top: calc(50% - var(--roadmap-h) / 2 + 24px);
  width: min(440px, calc(100vw - 2 * var(--gutter)));
  max-height: calc(100vh - 150px - var(--roadmap-h));
  transform: translateY(calc(-50% + var(--rise, 0px)));
  opacity: 0; pointer-events: none;
  background: var(--paper); color: var(--ink-2);
  box-shadow: 0 24px 60px -22px rgba(20, 30, 50, .55);
  border-top: 6px solid var(--vessco-orange);
}
.mh-card.is-active { pointer-events: auto; }
.mh-card[data-position="left"] { left: var(--gutter); }
.mh-card[data-position="right"] { right: var(--gutter); }
.mh-card__inner { padding: clamp(22px, 2.6vw, 34px); overflow: auto; max-height: inherit; scrollbar-width: thin; }
.mh-card h1, .mh-card h2 {
  margin: 0; color: var(--ink); font: 700 clamp(1.65rem, 2.3vw, 2.15rem)/1.1 var(--display);
  letter-spacing: -.012em; text-wrap: balance;
}
.mh-card h1 { font-size: clamp(2rem, 3vw, 2.7rem); }
.mh-card__when { margin: 10px 0 0; color: var(--vessco-blue); font: 600 .9rem/1.3 var(--text); letter-spacing: .04em; }
.mh-card__lede { margin: 16px 0 0; font-size: 1rem; line-height: 1.6; color: var(--ink-2); max-width: 60ch; }
.mh-list, .mh-caps { margin-top: 20px; }
.mh-list h3, .mh-caps h3 { margin: 0 0 8px; color: var(--muted); font: 600 .8rem var(--text); letter-spacing: .06em; text-transform: uppercase; }
.mh-list ul, .mh-caps ul { margin: 0; padding: 0; list-style: none; }
.mh-list li { display: flex; gap: 10px; padding: 8px 0; border-top: 1px solid var(--rule); color: var(--ink); font-weight: 500; line-height: 1.4; }
.mh-list li svg { flex: none; width: 18px; height: 18px; margin-top: 1px; color: var(--vessco-blue); }
/* The capability buttons are the way to a panel when the live stage is not running. */
.mh-caps { display: none; }
.mh-stage.is-stills ~ .mh-copy-layer .mh-caps { display: block; }
.mh-caps li { border-top: 1px solid var(--rule); }
.mh-caps button {
  display: block; width: 100%; min-height: 44px; padding: 8px 0; background: none; border: 0; cursor: pointer; text-align: left;
  color: var(--vessco-blue); font: 600 .95rem/1.3 var(--text); text-decoration: underline; text-underline-offset: 4px;
}

/* Point tags: pinned to objects on the plant. */
.mh-tags { position: fixed; inset: 0; z-index: 10; pointer-events: none; }
.mh-tags__lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.mh-tags__lines path { fill: none; stroke: var(--vessco-blue); stroke-width: 1.5; }
.mh-tags__lines circle { fill: var(--vessco-orange); stroke: #fff; stroke-width: 2; }
.mh-tag { position: absolute; left: 0; top: 0; opacity: 0; will-change: transform, opacity; }
.mh-tag span {
  display: block; width: max-content; max-width: 260px; padding: 6px 12px; transform: translate(0, -50%);
  background: rgba(255, 255, 255, .96); border: 1px solid var(--vessco-blue); border-left-width: 4px; color: var(--ink);
  font: 600 .9rem/1.25 var(--text); letter-spacing: .01em;
}
.mh-tag[data-side="left"] span { transform: translate(-100%, -50%); }

/* Hotspots: an orange ring over a clickable object. Quiet until hovered or focused. */
.mh-hotspots { position: fixed; inset: 0; z-index: 11; pointer-events: none; }
/* The button holds still (its box is the hit area and what tests measure); the ring inside it breathes. */
.mh-hotspot {
  position: absolute; left: 0; top: 0; width: 30px; height: 30px; margin: -15px 0 0 -15px; padding: 0;
  border: 0; border-radius: 50%; background: none; cursor: pointer; pointer-events: auto;
}
.mh-hotspot[hidden] { display: none; }
.mh-hotspot::before { content: ""; position: absolute; inset: -8px; border-radius: 50%; }
.mh-hotspot__ring {
  position: absolute; inset: 0; border: 2px solid var(--vessco-orange); border-radius: 50%; background: rgba(255, 255, 255, .55);
  box-shadow: 0 0 0 1px rgba(34, 34, 34, .35); pointer-events: none;
  transition: background-color .2s ease, box-shadow .2s ease;
  animation: mh-breathe 2s ease-in-out infinite;
}
.mh-hotspot__ring::after { content: ""; position: absolute; inset: 9px; border-radius: 50%; background: var(--vessco-orange); }
.mh-hotspot:hover, .mh-hotspot:focus-visible { z-index: 2; }
.mh-hotspot:hover .mh-hotspot__ring, .mh-hotspot:focus-visible .mh-hotspot__ring { background: rgba(243, 111, 33, .3); box-shadow: 0 0 0 5px rgba(243, 111, 33, .28); }
.mh-hotspot.is-pulse .mh-hotspot__ring { animation: mh-pulse 1.6s ease-out 1, mh-breathe 2s ease-in-out infinite; }
@keyframes mh-breathe {
  0%, 100% { transform: scale(1); opacity: .85; }
  50% { transform: scale(1.08); opacity: 1; }
}
@keyframes mh-pulse {
  0% { box-shadow: 0 0 0 1px rgba(34, 34, 34, .35), 0 0 0 0 rgba(243, 111, 33, .55); }
  100% { box-shadow: 0 0 0 1px rgba(34, 34, 34, .35), 0 0 0 16px rgba(243, 111, 33, 0); }
}
/* Label chip: on hover or keyboard focus, above the ring (below near the bar), never over it. */
.mh-hotspot__chip {
  position: absolute; left: 50%; bottom: calc(100% + 10px); width: max-content; max-width: 220px; padding: 4px 10px;
  transform: translateX(calc(-50% + var(--chip-dx, 0px)));
  background: var(--ink); color: #fff; font: 600 .85rem/1.25 var(--text); text-align: center;
  opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .15s ease, visibility .15s;
}
.mh-hotspot[data-chip="below"] .mh-hotspot__chip { bottom: auto; top: calc(100% + 10px); }
.mh-hotspot:hover .mh-hotspot__chip, .mh-hotspot:focus-visible .mh-hotspot__chip { opacity: 1; visibility: visible; }

/* Scroll cue: one quiet label and a chevron, bottom centre above the roadmap. */
.mh-scroll-cue {
  position: fixed; z-index: 29; left: 50%; bottom: calc(var(--roadmap-h) + 12px); transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 2px; min-height: 44px; padding: 7px 16px 4px;
  background: rgba(34, 34, 34, .85); border: 0; color: rgba(255, 255, 255, .92);
  font: 600 .85rem/1 var(--text); letter-spacing: .14em; text-transform: uppercase; cursor: pointer;
}
.mh-scroll-cue[hidden] { display: none; }
.mh-scroll-cue svg { width: 18px; height: 18px; animation: mh-drift 2.4s ease-in-out infinite; }
.mh-scroll-cue:hover { color: #fff; }
@keyframes mh-drift {
  0%, 60%, 100% { transform: translateY(0); }
  80% { transform: translateY(4px); }
}

/* Connector caption */
.mh-caption {
  position: fixed; z-index: 11; left: 50%; top: 18vh; transform: translateX(-50%);
  width: max-content; max-width: min(760px, calc(100vw - 2 * var(--gutter))); margin: 0; padding: 14px 26px;
  text-align: center; opacity: 0; pointer-events: none;
  background: rgba(255, 255, 255, .96); border-top: 4px solid var(--vessco-orange);
  color: var(--ink); font: 700 clamp(1.3rem, 2.4vw, 2rem)/1.2 var(--display); letter-spacing: -.01em; text-wrap: balance;
}

/* Roadmap */
.mh-roadmap {
  position: fixed; z-index: 30; inset: auto 0 0; height: var(--roadmap-h); padding: 0 var(--gutter);
  background: rgba(255, 255, 255, .95); border-top: 1px solid var(--rule);
}
.mh-roadmap__track { position: absolute; left: calc(var(--gutter) + 100% / 16 - var(--gutter) / 8); right: calc(var(--gutter) + 100% / 16 - var(--gutter) / 8); top: 30px; height: 2px; background: var(--rule); }
.mh-roadmap__fill { position: absolute; inset: 0; background: var(--vessco-orange); transform-origin: left; transform: scaleX(0); }
.mh-roadmap__stops { position: relative; display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); height: 100%; margin: 0; padding: 0; list-style: none; }
.mh-stop__button {
  width: 100%; height: 100%; display: grid; justify-items: center; align-content: start; gap: 2px; padding: 21px 4px 0;
  background: none; border: 0; cursor: pointer; color: var(--muted); text-align: center;
}
.mh-stop__mark {
  width: 20px; height: 20px; display: grid; place-items: center; margin-bottom: 6px;
  background: #fff; border: 2px solid var(--muted); border-radius: 50%; color: #fff;
  transition: background-color .3s ease, border-color .3s ease;
}
.mh-stop__mark svg { width: 12px; height: 12px; opacity: 0; transition: opacity .3s ease; }
.mh-stop__label { font: 700 .9rem/1.1 var(--display); color: var(--ink); }
.mh-stop__when { font: 400 .8rem/1.2 var(--text); }
.mh-stop__button:hover .mh-stop__label { color: var(--vessco-blue); }
.mh-stop.is-done .mh-stop__mark { background: var(--vessco-orange); border-color: var(--vessco-orange); }
.mh-stop.is-done .mh-stop__mark svg { opacity: 1; }
.mh-stop.is-active .mh-stop__mark { border-color: var(--vessco-orange); box-shadow: 0 0 0 5px rgba(243, 111, 33, .25); }
.mh-stop.is-active .mh-stop__label { color: var(--vessco-blue); }

/* Poster capture keeps the plant and its tags, hides the chrome and the hotspots (stills have none). */
:root[data-capture] .mh-copy-layer, :root[data-capture] #shell, :root[data-capture] .mh-hotspots,
:root[data-capture] .mh-roadmap, :root[data-capture] .mh-caption, :root[data-capture] .mh-scroll-cue { visibility: hidden; }

/* Stills mode: tags are baked into the posters. */
.mh-stage.is-stills ~ .mh-tags { display: none; }

/* Short laptop screens: tighten the card so the whole message fits without scrolling. */
@media (min-width: 761px) and (max-height: 820px) {
  .mh-card { top: calc(50% - var(--roadmap-h) / 2 + 30px); max-height: calc(100vh - 128px - var(--roadmap-h)); }
  .mh-card__inner { padding: 20px 24px 22px; }
  .mh-card h2 { font-size: 1.55rem; }
  .mh-card h1 { font-size: 1.9rem; }
  .mh-card__when { margin-top: 6px; }
  .mh-card__lede { margin-top: 10px; font-size: .9rem; line-height: 1.5; }
  .mh-list, .mh-caps { margin-top: 12px; }
  .mh-list li { padding: 6px 0; font-size: .9rem; }
}

/* Narrow screens: the card becomes a bottom sheet above a compact roadmap. */
@media (max-width: 760px) {
  :root { --roadmap-h: 64px; }
  .mh-card, .mh-card[data-position="left"], .mh-card[data-position="right"] {
    top: auto; bottom: calc(var(--roadmap-h) + 8px); left: 12px; right: 12px; width: auto;
    max-height: 60vh; transform: translateY(var(--rise, 0px));
  }
  .mh-list { display: none; }
  .mh-stage.is-stills ~ .mh-copy-layer .mh-list { display: block; }
  /* In stills the list returns, so the sheet scrolls inside a lower cap and the poster's equipment stays clear. */
  .mh-stage.is-stills ~ .mh-copy-layer .mh-card { max-height: 34vh; }
  .mh-card__inner { padding: 18px 18px 20px; }
  .mh-card h1, .mh-card h2 { font-size: 1.45rem; }
  .mh-card__lede { margin-top: 10px; font-size: .9rem; line-height: 1.5; }
  .mh-tag span { font-size: .85rem; max-width: 190px; white-space: normal; }
  .mh-caption { top: 22vh; }
  .mh-scroll-cue { top: calc(var(--shell-h, 60px) + 10px); bottom: auto; }
  .mh-roadmap__track { top: 22px; }
  .mh-stop__button { padding: 13px 0 0; }
  .mh-stop__label { font-size: .6rem; }
  /* Eight labels do not fit a phone's width: only the active stop shows its label, the others stay in the accessibility tree. */
  .mh-stop:not(.is-active) .mh-stop__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .mh-stop__when { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .boot, .boot *, .boot__bar i { animation: none !important; transition: none; }
  .mh-stop__mark, .mh-hotspot { transition: none; }
  .mh-hotspot__ring, .mh-hotspot.is-pulse .mh-hotspot__ring, .mh-scroll-cue svg { animation: none; }
  .mh-hotspot__ring, .mh-hotspot__chip { transition: none; }
}
