/* Bayeux Tapestry walking audioguide — prototype.
 *
 * Self-contained on purpose: this folder is an experiment and must stay
 * deletable, so the site's palette and controls are copied here rather than
 * pulled from /css/styles.css. Same tokens (#2c2c2c / #6b6b6b / #9b9b9b,
 * #e5e5e5 hairlines, the 80px circular play button) so it still feels like
 * audioguide.london.
 */

:root {
  --ink: #2c2c2c;
  --ink-soft: #6b6b6b;
  --ink-faint: #9b9b9b;
  --hairline: #e5e5e5;
  --linen: #ece5d8;          /* the cloth's own ground, used behind the band */
  --band-radius: 16px;
}

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

html { height: 100%; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  background: #ffffff;
  color: var(--ink);
  height: 100%;
  overflow: hidden;              /* nothing on this page scrolls */
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
}

.guide {
  position: relative;            /* the home button is pinned to this corner */
  height: var(--actual-vh, 100vh);
  max-width: 900px;
  margin: 0 auto;
  padding: max(0.5rem, env(safe-area-inset-top, 0px)) 16px
           max(0.5rem, env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  text-align: center;
}

/* ------------------------------------------------------------------ header */

/* Out of flow on purpose: the page must not scroll, so the way back home is not
   allowed to cost the band a single pixel. It hangs off .guide rather than off
   .guide-header, which the landscape variant below drops entirely. */
.home-button {
  position: absolute;
  top: max(0.35rem, env(safe-area-inset-top, 0px));
  left: max(2px, env(safe-area-inset-left, 0px));
  z-index: 10;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--ink);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.15s ease, transform 0.12s ease, color 0.15s ease;
}

.home-button:hover { background: rgba(0, 0, 0, 0.05); color: #1a1a1a; }
.home-button:active { background: rgba(0, 0, 0, 0.08); transform: scale(0.96); }
.home-button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.home-button-icon { display: block; pointer-events: none; }

/* The other corner, same rules: out of flow, so saving the guide for the walk
   costs the band nothing, and it survives the landscape variant. */
.save-button {
  position: absolute;
  top: max(0.35rem, env(safe-area-inset-top, 0px));
  right: max(2px, env(safe-area-inset-right, 0px));
  z-index: 10;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.15s ease, transform 0.12s ease, color 0.15s ease;
}

.save-button:hover { background: rgba(0, 0, 0, 0.05); }
.save-button:active { transform: scale(0.96); }
.save-button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.save-button[hidden] { display: none; }
.save-button.is-done { color: #2f7a43; cursor: default; }
.save-button.is-busy { cursor: progress; }

.save-icon {
  position: absolute;
  width: 21px;
  height: 21px;
  pointer-events: none;
}

/* One icon at a time: the arrow until it is saved, the tick afterwards, and
   neither while the ring is filling. */
.save-icon-done { display: none; }
.save-button.is-busy .save-icon-down { opacity: 0.25; }
.save-button.is-done .save-icon-down { display: none; }
.save-button.is-done .save-icon-done { display: block; }

/* The progress ring is drawn only while downloading; 119.38 is its
   circumference (2πr, r = 19), so stroke-dashoffset is 1 − fraction of it. */
.save-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.save-button.is-busy .save-ring { opacity: 1; }
.save-ring-track { fill: none; stroke: rgba(0, 0, 0, 0.09); stroke-width: 2.5; }
.save-ring-fill {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-dasharray: 119.38;
  stroke-dashoffset: 119.38;
  transition: stroke-dashoffset 0.25s linear;
}

/* Transient, and floats over whatever is beneath: it is only on screen while
   the download runs and for a moment after, and the page has no room to spare. */
.save-note {
  position: absolute;
  top: calc(max(0.35rem, env(safe-area-inset-top, 0px)) + 46px);
  right: max(6px, env(safe-area-inset-right, 0px));
  z-index: 11;
  max-width: 62vw;
  padding: 5px 11px;
  border-radius: 13px;
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
  font-size: 0.72rem;
  font-weight: 400;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  text-align: right;
  pointer-events: none;
}

.save-note[hidden] { display: none; }

.guide-header { flex: 0 0 auto; padding-bottom: 0.4rem; }

.guide-title {
  font-size: 1.6rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.guide-sub {
  margin-top: 0.15rem;
  font-size: 0.78rem;
  font-weight: 300;
  color: var(--ink-faint);
  letter-spacing: 0.02em;
}

/* The chapter line is the one readout that changes constantly, so it gets a
   fixed height — the band must never jump because "Scene 9" became "Scene 10". */
.chapter {
  flex: 0 0 auto;
  height: 1.5rem;
  line-height: 1.5rem;
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.chapter-scene { color: var(--ink); font-weight: 600; }
.chapter-sep { color: var(--ink-faint); margin: 0 0.35em; }

/* -------------------------------------------------------------------- band */

/* The band group takes whatever height is left over, and centres itself in it.
   The band's own height is not "the space available" — it is derived from how
   much cloth we want across the screen (see VIEW_CM in app.js), because the
   band's aspect ratio is fixed by the tapestry's. A taller band shows LESS
   tapestry, which is the opposite of what a walking guide wants. */
.stage {
  flex: 0 0 auto;
}

/* Applied for one synchronous measurement in app.js's fit(): with the slack
   handed back to the stage, stage.clientHeight reports exactly how much room
   the band could have. Outside this class the slack belongs to .titulus, so
   asking the stage would just return the band's own current height. */
.measuring .stage { flex: 1 1 auto; min-height: 0; }
.measuring .titulus { flex: 0 0 auto; }

.band {
  position: relative;
  flex: 0 0 auto;
  height: 170px;                 /* placeholder; app.js computes the real one */
  overflow: hidden;
  border-radius: var(--band-radius);
  background: var(--linen);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  touch-action: none;            /* we own every gesture in here */
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.band.dragging { cursor: grabbing; }

.strip {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  will-change: transform;
}

.strip img {
  position: absolute;
  top: 0;
  display: block;
  pointer-events: none;
  /* tiles butt up against each other; without this a hairline of background
     shows through at fractional scales */
  image-rendering: auto;
}

/* Where one numbered scene ends and the next begins. Drawn as a tick biting in
   from the top and bottom edges rather than a line across the cloth, so the
   embroidery stays unobstructed. Width is compensated for the strip's scale. */
.divider {
  position: absolute;
  top: 0;
  height: 100%;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(44, 44, 44, 0.3) 0, rgba(44, 44, 44, 0.3) 6%, transparent 6%,
    transparent 94%, rgba(44, 44, 44, 0.3) 94%, rgba(44, 44, 44, 0.3) 100%);
}

/* "Now" — fixed, the cloth flows under it. */
.playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 38%;              /* app.js sets the real value; see place() */
  width: 2px;
  margin-left: -1px;
  background: rgba(44, 44, 44, 0.55);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.45);
  pointer-events: none;
}

.playhead::before,
.playhead::after {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
}

.playhead::before { top: 0; border-top: 6px solid var(--ink); }
.playhead::after { bottom: 0; border-bottom: 6px solid var(--ink); }

/* Does not lean on backdrop-filter to stay readable over busy embroidery. */
.band-hint {
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 8px;
  margin: 0 auto;
  width: fit-content;
  max-width: 100%;
  padding: 5px 11px;
  border-radius: 13px;
  background: rgba(255, 255, 255, 0.93);
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 400;
  text-align: center;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.band-hint.gone { opacity: 0; }

/* ----------------------------------------------------------------- minimap */

/* The whole 68.87 m squashed into one screen width. It reads as an abstract
   ribbon rather than a picture — which is the point: it is the only control
   that can cross the tapestry quickly, since one full swipe of the band is
   barely fifteen seconds of narration. */
.minimap {
  position: relative;
  flex: 0 0 auto;
  height: 44px;
  margin-top: 12px;
  border-radius: 6px;
  overflow: hidden;
  background: var(--linen);
  touch-action: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.minimap:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.minimap-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;
  opacity: 0.85;
  pointer-events: none;
}

.minimap-view {
  position: absolute;
  top: 0;
  bottom: 0;
  min-width: 3px;
  background: rgba(255, 255, 255, 0.34);
  box-shadow: inset 0 0 0 1px rgba(44, 44, 44, 0.35);
  pointer-events: none;
}

.minimap-head {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
  background: var(--ink);
  pointer-events: none;
}

.minimap-ticks { position: absolute; inset: 0; pointer-events: none; }

.minimap-ticks span {
  position: absolute;
  bottom: 2px;
  transform: translateX(-50%);
  font-size: 0.58rem;
  font-weight: 600;
  color: rgba(44, 44, 44, 0.75);
  letter-spacing: 0.02em;
  text-shadow: 0 0 3px #fff, 0 0 3px #fff, 0 0 2px #fff;
}

.minimap-ticks span::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -8px;
  width: 1px;
  height: 7px;
  background: rgba(44, 44, 44, 0.45);
}

/* ---------------------------------------------------------------- titulus */

/* The band cannot use spare height — its aspect ratio is the tapestry's, so a
   taller band would show LESS cloth. The text takes the slack instead, and the
   story gets a proper reading area rather than a cramped strip. */
.titulus {
  flex: 1 1 auto;
  min-height: 4.6rem;
  margin-top: 0.9rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.4rem;
  overflow: hidden;
}

.titulus-latin {
  font-family: "Iowan Old Style", Palatino, "Palatino Linotype", Georgia, serif;
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  color: var(--ink);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.titulus-trans {
  font-size: 1rem;
  font-weight: 300;
  color: var(--ink-soft);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* What is coming, so you know whether to keep walking or stay put. */
.titulus-next {
  margin-top: 0.5rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--hairline);
  align-self: center;
  max-width: 34ch;
  font-size: 0.78rem;
  font-weight: 300;
  color: var(--ink-faint);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.titulus-next b { font-weight: 500; color: var(--ink-soft); }

.titulus-trans .fallback {
  color: var(--ink-faint);
  font-size: 0.72rem;
  white-space: nowrap;
}

/* --------------------------------------------------------------- controls */

.controls {
  flex: 0 0 auto;
  margin-top: 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
}

.step-button {
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.2s ease, transform 0.2s ease;
}

.step-button svg { width: 24px; height: 24px; }
.step-button:hover { background: rgba(0, 0, 0, 0.05); color: var(--ink); }
.step-button:active { transform: scale(0.92); }

.play-pause-button {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--ink);
  color: #ffffff;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 16px rgba(44, 44, 44, 0.2);
  -webkit-tap-highlight-color: transparent;
  transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.play-pause-button:hover {
  background: #1a1a1a;
  box-shadow: 0 6px 20px rgba(44, 44, 44, 0.3);
}

.play-pause-button:active { transform: scale(0.95); }

.play-pause-icon { width: 30px; height: 30px; fill: currentColor; }
.play-pause-icon[hidden] { display: none; }

/* Above the transport, as on the artwork detail page: you pick the voice you
   want before you start it, not in the footer under the clock. */
.language-row {
  flex: 0 0 auto;
  margin-top: 0.55rem;
  display: flex;
  justify-content: center;
}

.foot {
  flex: 0 0 auto;
  margin-top: 0.55rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
}

.time-display {
  font-size: 0.85rem;
  font-weight: 300;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.language-select {
  padding: 9px 34px 9px 13px;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 300;
  color: var(--ink);
  background-color: #ffffff;
  border: 1px solid #e8e8e8;
  border-radius: 6px;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b6b6b' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}

.language-select:hover { border-color: #d0d0d0; }
.language-select:focus { outline: none; border-color: var(--ink-soft); }

/* ------------------------------------------------------------------- foot */

.mock-note {
  flex: 0 0 auto;
  margin-top: 0.5rem;
  font-size: 0.7rem;
  font-weight: 300;
  color: var(--ink-faint);
}

.credit {
  flex: 0 0 auto;
  margin-top: 0.35rem;
  font-size: 0.58rem;
  font-weight: 300;
  line-height: 1.4;
  color: #bdbdbd;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* --------------------------------------------------------------- variants */

/* Short phones: give the band every pixel the chrome can spare. */
@media (max-height: 700px) {
  .guide-sub { display: none; }
  .titulus { min-height: 3.6rem; margin-top: 0.6rem; }
  .titulus-next { display: none; }
  .play-pause-button { width: 62px; height: 62px; }
  .play-pause-icon { width: 26px; height: 26px; }
  .language-row { margin-top: 0.4rem; }
  .language-select { padding: 7px 30px 7px 11px; }
  .mock-note, .credit { display: none; }
}

/* Landscape phone: the band is the whole point, so let it take the height and
   fold the readouts into a single row underneath. */
@media (orientation: landscape) and (max-height: 520px) {
  .guide-header, .mock-note, .credit { display: none; }
  .minimap { height: 30px; margin-top: 8px; }
  .titulus { min-height: 2.6rem; margin-top: 0.4rem; }
  .titulus-latin, .titulus-trans { -webkit-line-clamp: 1; font-size: 0.85rem; }
  .titulus-next { display: none; }
  .controls { margin-top: 0.3rem; gap: 1.2rem; }
  .play-pause-button { width: 54px; height: 54px; }
  .play-pause-icon { width: 22px; height: 22px; }
  .language-row { margin-top: 0.3rem; }
  .language-select { padding: 5px 28px 5px 10px; font-size: 0.8rem; }
  .foot { margin-top: 0.3rem; }
  /* No header to sit beside, so tuck the buttons up against the chapter line. */
  .home-button, .save-button { width: 36px; height: 36px; top: 0; }
  .save-note { top: 38px; }
}

@media (min-width: 720px) {
  .guide { padding-left: 24px; padding-right: 24px; }
  .guide-title { font-size: 2rem; }
  .minimap { height: 52px; }
  .titulus-latin, .titulus-trans { font-size: 0.95rem; }
}
