/* Beta: "Paros, drawn by hand".

   One hand-drawn panorama of a day on Paros on the site's sand paper, with
   words on paper strips and pencil marks drawn over them. Two layouts share
   this file:

   - Static (the default, and what JS-off and reduced-motion visitors get):
     the title, one swipeable drawing that snaps scene by scene, then every
     beat of words in reading order. Nothing hidden, nothing pinned.
   - Motion (under .pts.art-live, set by story-boot.js / story.js only when the
     visitor allows motion): the drawing and the words are pinned in one
     .art-pin, the camera travels sideways across three depth layers, and
     story.js drives transform, opacity and stroke-dashoffset through the CSSOM.

   A component: every rule is scoped to the story root .pts (a div holding
   the skip link, #story and, standalone only, the ending #plan), and the
   state classes art-live / art-run / art-fin / art-ready sit on that root,
   never on <html>, so the story can be nested in any page (the home page)
   without leaking. Keyframes are prefixed pts-. The only page-level rules:
   .art-page (the standalone page's body) and html:has(.pts.art-live), which
   turns off smooth anchor scrolling while a live story is on the page (a
   jump across 30 screens of story would otherwise crawl through it).

   Sections
     1. Page
     2. The drawing: static stage
     3. The drawing: ink
     4. Margin drawings and ending vignettes: ink
     5. The words
     6. Pencil marks on the words
     7. Hints and the road (static)
     8. Static reading layout
     9. The ending
    10. Motion: the frame
    11. Motion: the words
    12. Motion: starting states and transform origins
    13. Motion: the sky
    14. Motion: the road
    15. Motion: idle life
    16. Motion: the ending draws itself
    17. Screen sizes */

/* ==== 1. Page ================================================================ */

.art-page,
.pts .art-story,
.pts .art-end {
  background: var(--sand);
}

.art-page .site-header {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background: var(--sand);
}

/* the root is the skip link's frame: nested in a page, it shows where the story starts */
.pts {
  position: relative;
}

.pts .skip-story {
  z-index: 41;
}

/* site.css parks .skip just above its frame: nested in a page that is the
   section above the story, so it stays invisible until it has focus */
.pts .skip-story:not(:focus) {
  opacity: 0;
  pointer-events: none;
}

/* ==== 2. The drawing: static stage ============================================ */

/* one swipeable drawing, snapping scene by scene */
.pts .art-stage {
  --stage-h: min(64svh, 600px);
  position: relative;
  height: var(--stage-h);
  overflow-x: auto;
  overflow-y: hidden;
  border-block: 1px solid var(--line);
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}

.pts .art-stage:focus-visible {
  outline: 2px solid var(--sea);
  outline-offset: -2px;
}

.pts .art-layers {
  position: relative;
  width: max-content;
  height: 100%;
}

/* the mid layer's own right margin (800 units past the last scene) must not
   add blank paper to the swipe */
.pts:not(.art-live) .art-layers {
  overflow: hidden;
}

.pts .layer {
  display: block;
  height: 100%;
  width: auto;
  max-width: none;
  margin: 0;
  overflow: visible;
}

/* only the mid layer shows in the static page; its viewBox carries 1500 units
   of margin on the left and 800 on the right, hidden with negative margins so
   the drawing starts at the island */
.pts .layer-far,
.pts .layer-near {
  display: none;
}

/* the mid viewBox starts at -520 so that objects dropping in from above stay
   inside its box (one compositor layer while live); the static page shows
   its 0..1000 band */
.pts .layer-mid {
  height: calc(var(--stage-h) * 1.52);
  margin-top: calc(var(--stage-h) * -0.52);
  margin-left: calc(var(--stage-h) * -1.5);
  margin-right: calc(var(--stage-h) * -0.8);
}

.pts .snap {
  position: absolute;
  top: 0;
  width: 1px;
  height: 100%;
  scroll-snap-align: center;
  pointer-events: none;
}

.pts .snap:nth-of-type(1) { left: calc(0.5 * 12.5%); }
.pts .snap:nth-of-type(2) { left: calc(1.5 * 12.5%); }
.pts .snap:nth-of-type(3) { left: calc(2.5 * 12.5%); }
.pts .snap:nth-of-type(4) { left: calc(3.5 * 12.5%); }
.pts .snap:nth-of-type(5) { left: calc(4.5 * 12.5%); }
.pts .snap:nth-of-type(6) { left: calc(5.5 * 12.5%); }
.pts .snap:nth-of-type(7) { left: calc(6.5 * 12.5%); }
.pts .snap:nth-of-type(8) { left: calc(7.5 * 12.5%); }

/* the sun and moon only exist in the motion layout */
.pts .sky {
  display: none;
}

/* ==== 3. The drawing: ink ====================================================== */

.pts .layer {
  fill: none;
  color: var(--ink);
  stroke: var(--ink);
  stroke-width: 3.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pts .layer-far {
  color: #85765f;
  stroke: #85765f;
  stroke-width: 3.0;
}

.pts .layer-near {
  stroke-width: 5.6;
}

.pts .layer .bold { stroke-width: 5.4; }
.pts .layer .red { color: #b8452b; stroke: #b8452b; }
.pts .layer .gold { color: #b07a36; stroke: #b07a36; }
.pts .layer .dash { stroke-dasharray: 10 16; }
.pts .layer .thin { stroke-width: 2.6; }
.pts .layer .sea-line { stroke: var(--sea); stroke-width: 3.4; }
.pts .layer .wave { stroke: var(--sea); stroke-width: 3.2; opacity: 0.8; }
.pts .layer .windline { stroke: var(--sea); stroke-width: 3.2; opacity: 0.7; }
.pts .layer .door { stroke: #b8452b; stroke-width: 3.4; }
.pts .layer .shadow { stroke-width: 2; opacity: 0.35; }
.pts .layer .star { stroke-width: 3.4; }
.pts .layer-far .star { stroke: var(--ink); stroke-opacity: 0.75; stroke-width: 3.6; }
.pts .layer .solid { fill: var(--sand); stroke: none; }
.pts .layer .solid-night { fill: rgb(46 58 86); stroke: none; }
.pts .layer .earth { fill: #eadcc4; stroke: none; }
.pts .layer .lime { fill: #faf7f0; stroke: none; }
.pts .layer .ghost { fill: none; stroke: none; }
.pts .layer .wash { stroke: none; }
.pts .layer .night { stroke: none; }
.pts .layer .glow { fill: url(#glow); stroke: none; }
.pts .layer .glow-warm { fill: url(#glow-warm); stroke: none; }
.pts .layer .bulb { fill: #f3c77a; stroke-width: 2.4; }
.pts .layer .window { fill: #e0b25a; stroke: none; }
.pts .layer .card-paper { fill: #fbfaf7; stroke: var(--line); stroke-width: 2; }
.pts .layer .tape { fill: rgb(214 196 160 / 0.72); stroke: none; }
.pts .layer .mask-pen { stroke: #fff; stroke-width: 16; fill: none; }

/* movers (boats, birds, the hat) carry a transform attribute that parks them
   somewhere sensible in the static page; live, the engine places them along
   their path, so the parked offset is switched off */
.pts.art-live .layer .rest {
  transform: none;
}

/* the pencil tip that rides the hero strokes (the engine moves it) */
.pts .layer .nib-ink { fill: var(--ink); stroke: none; }
.pts .layer .nib-body { fill: #d8b98a; stroke: var(--ink); stroke-width: 1.6; }

/* ==== 4. Margin drawings and ending vignettes: ink ============================= */

.pts .margin {
  fill: none;
  color: var(--ink);
  stroke: var(--ink);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pts .margin .red { color: #b8452b; stroke: #b8452b; }
.pts .margin .gold { color: #b07a36; stroke: #b07a36; }
.pts .margin .dash { stroke-dasharray: 6 9; }
.pts .margin .shadow { stroke-width: 2.2; opacity: 0.4; }
.pts .margin .bulb { fill: #f3c77a; stroke-width: 2.6; }

/* the odometer inside the doors ring: two digit columns, moved by the engine;
   without it (or with motion reduced) the count is already at ninety-nine */
.pts .margin .odo-t,
.pts .margin .odo-u {
  stroke-width: 3.6;
}

.pts:not(.art-live) .margin .odo-t,
.pts:not(.art-live) .margin .odo-u {
  transform: translateY(-540px);
}

.pts .endart {
  fill: none;
  color: var(--ink);
  stroke: var(--ink);
  stroke-width: 3.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pts .end-map {
  stroke-width: 3;
}

/* the caravan: the vehicle half of the CAR.A.VAN logo, in its own gold, facing
   the way the story travels (make.py caravan()) */
.pts .cv-body { stroke: #8a6a3a; stroke-width: 0.8px; stroke-opacity: 0.55; vector-effect: non-scaling-stroke; }
.pts .cv-rope { fill: none; stroke-linecap: round; stroke-width: 1.6px; vector-effect: non-scaling-stroke; }
.pts .cv-hub { fill: var(--sand); stroke: none; }
.pts .cv-handle { fill: none; stroke: #8a6a3a; stroke-width: 1px; vector-effect: non-scaling-stroke; }
.pts .cv-flame { fill: #fff3cf; stroke: none; }

.pts .endart .red { color: #b8452b; stroke: #b8452b; }
.pts .endart .gold { color: #b07a36; stroke: #b07a36; }
.pts .endart .sea-line { stroke: var(--sea); }
.pts .endart .dash { stroke-dasharray: 8 10; }

/* ==== 5. The words =============================================================== */

.pts .beat > * {
  max-width: 34rem;
}

.pts .beat-title > * {
  max-width: none;
}

.pts .beat h2,
.pts .beat p,
.pts .beat .hour,
.pts .giant,
.pts .sub {
  display: block;
  padding: 0;
  background: none;
  box-shadow: none;
}

/* every line its own paper strip, so the words read over the drawing */
.pts .strip {
  display: inline;
  padding: 0.06em 0.34em;
  background: rgb(251 250 247 / 0.92);
  box-shadow: 0 1px 0 var(--line);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.pts .beat .hour {
  margin: 0 0 0.7rem;
  color: var(--sea);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  line-height: 1.4;
  text-transform: uppercase;
}

/* the heading: strips per line, the whole heading tilted like paper stuck on
   by hand, with a tape tab. The tilt uses the individual rotate property, so
   the engine's entrance transform composes with it. Excludes the title beat:
   embedded (home-page) builds render the giant title as an h2 (the host owns
   the h1), and this rule must not catch it — the title's own size, weight
   and tilt come from .giant, never from ".beat h2". */
.pts .beat:not(.beat-title) h2 {
  --tilt: -1.2deg;
  position: relative;
  margin: 0 0 0.75rem;
  font-family: var(--serif);
  font-size: clamp(1.8rem, 5vw, 2.8rem);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.015em;
  rotate: var(--tilt);
  transform-origin: 0.4em 60%;
}

.pts .tilt-b h2 { --tilt: 0.6deg; }
.pts .tilt-c h2 { --tilt: -0.4deg; }

.pts .beat:not(.beat-title) h2::before {
  content: "";
  position: absolute;
  left: -0.34em;
  top: -0.12em;
  z-index: 1;
  width: 1.2em;
  height: 0.36em;
  background: rgb(214 196 160 / 0.72);
  transform: rotate(-7deg);
  pointer-events: none;
}

.pts .beat p {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.62;
}

/* a second paragraph in the same beat (the night step's closing line) gets
   its own strip, clear of the one before it */
.pts .beat p + p {
  margin-top: 0.6em;
}

/* the waypoint badge beside the hour label: a red numeral in a pencil ring */
.pts .wp {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.55rem;
  height: 1.55rem;
  margin: -0.3rem 0.55rem -0.2rem 0;
  color: #b8452b;
  font-family: var(--serif);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1;
  vertical-align: middle;
}

.pts .wp-ring {
  position: absolute;
  inset: -2px;
  width: auto;
  height: auto;
  overflow: visible;
  fill: none;
  stroke: #b8452b;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* the title */
.pts .beat-title {
  --giant: clamp(3.6rem, min(18vw, 24svh), 9.5rem);
  --title-pad: 0px;
}

.pts .giant {
  margin: 0;
  font-family: var(--serif);
  font-size: var(--giant);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: -0.03em;
}

.pts .giant .mark {
  margin-left: 0.06em;
  padding: 0 0.05em;
}

.pts .sub {
  max-width: 30rem;
  margin: 1.2rem 0 0;
  font-size: clamp(1.02rem, 2.5vw, 1.2rem);
  line-height: 1.55;
}

/* the small drawing beside the words (drawn by make.py) */
.pts .beat .margin {
  display: block;
  float: right;
  width: 5.5rem;
  height: auto;
  margin: -0.4rem 0 0.2rem 0.6rem;
  overflow: visible;
  pointer-events: none;
}

/* ==== 6. Pencil marks on the words ================================================= */

/* a marked word keeps the punctuation after it on its own line */
.pts .nw {
  white-space: nowrap;
}

.pts .mark {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}

.pts .m-circle,
.pts .m-under,
.pts .m-line,
.pts .m-gust,
.pts .m-loop,
.pts .m-x,
.pts .m-sparkles {
  position: absolute;
  max-width: none; /* site.css caps svg at 100%: the rings must reach past the word */
  overflow: visible;
  fill: none;
  stroke: #b07a36;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.pts .m-circle {
  left: -13%;
  top: -30%;
  width: 126%;
  height: 160%;
  stroke-width: 3;
}

.pts .giant .m-circle {
  left: -11%;
  top: -24%;
  width: 124%;
  height: 148%;
  stroke-width: 2.4;
}

.pts .m-under,
.pts .m-line {
  left: -3%;
  bottom: -0.28em;
  width: 106%;
  height: 0.45em;
  stroke-width: 4;
}

.pts .m-line {
  stroke-width: 3.4;
}

.pts .m-gust {
  left: 4%;
  top: -0.78em;
  width: 92%;
  height: 0.8em;
  stroke-width: 3;
}

.pts .m-loop {
  left: -7%;
  top: -34%;
  width: 114%;
  height: 168%;
  stroke-width: 3;
}

/* a red map X beside the word ("X marks the spot"); the word keeps room for it */
.pts .mark-x {
  margin-right: 0.8em;
}

.pts .m-x {
  left: calc(100% + 0.08em);
  top: -0.22em;
  width: 0.72em;
  height: 0.72em;
  stroke-width: 3.2;
}

/* sparkles beside the title, and round "stars" */
.pts .beat-title .m-sparkles {
  left: calc(var(--giant) * 2.45);
  top: calc(var(--title-pad) - var(--giant) * 0.28);
  width: calc(var(--giant) * 1.15);
  height: auto;
  stroke-width: 3;
}

.pts .mark > .m-sparkles {
  left: -22%;
  top: -60%;
  width: 144%;
  height: 210%;
  stroke-width: 2.6;
}

.pts .m-circle.red,
.pts .m-under.red,
.pts .m-line.red,
.pts .m-gust.red,
.pts .m-loop.red,
.pts .m-x.red,
.pts .m-sparkles.red {
  stroke: #b8452b;
}

.pts .m-arrow {
  display: none;
}

/* ==== 7. Hints and the road (static) ================================================ */

/* the scroll hint only makes sense while the story is pinned */
.pts .m-hint {
  display: none;
  width: 2.2rem;
  height: auto;
  margin: 1.5rem 0 0 0.6rem;
  overflow: visible;
  fill: none;
  stroke: #b07a36;
  stroke-width: 3.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* absolute in the scroller: it sits at the start and scrolls away with the first swipe */
.pts .swipe-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.3rem;
  z-index: 1;
  height: 1.6rem;
  margin: 0;
  padding: 0 var(--gutter);
  color: var(--ink-soft);
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  line-height: 1.6rem;
  text-align: right;
  text-transform: uppercase;
  pointer-events: none;
}

/* Without motion the road is a small index of the day under the drawing: a
   red X and the hour for each stop, each a link to its words. */
.pts .road {
  width: min(100% - (var(--gutter) * 2), 36rem);
  margin: 1.2rem auto 0;
  color: var(--ink);
}

.pts .road-line,
.pts .van {
  display: none;
}

.pts .stops {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pts .stop {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 2.75rem;
  color: var(--ink-soft);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-decoration: none;
  text-transform: uppercase;
}

.pts .stop:hover {
  color: var(--ink);
}

.pts .stop-x {
  flex: none;
  width: 12px;
  height: 12px;
  overflow: visible;
  fill: none;
  stroke: #b8452b;
  stroke-width: 2.4;
  stroke-linecap: round;
}

/* ==== 8. Static reading layout (no JS, or reduced motion) ================================ */

.pts:not(.art-live) .art-pin {
  display: flex;
  flex-direction: column;
}

.pts:not(.art-live) .art-words {
  display: contents;
}

.pts:not(.art-live) .beat { order: 2; }
.pts:not(.art-live) .beat.beat-title { order: 0; }
.pts:not(.art-live) .art-stage { order: 1; }
.pts:not(.art-live) .road { order: 1; }

.pts:not(.art-live) .beat {
  position: relative;
  width: min(100% - (var(--gutter) * 2), 36rem);
  margin-inline: auto;
  padding-block: clamp(2rem, 5vw, 3.2rem);
  scroll-margin-top: 5rem;
}

.pts:not(.art-live) .beat + .beat + .beat {
  border-top: 1px dashed var(--line);
}

.pts:not(.art-live) .beat-title {
  --title-pad: clamp(2.6rem, 7vw, 5rem);
  padding-block: var(--title-pad) clamp(2rem, 5vw, 3.2rem);
}

/* ==== 9. The ending ==================================================================== */

.pts .art-end {
  position: relative;
  z-index: 3;
  padding-block: clamp(3rem, 7vw, 6rem) var(--chapter);
  border-top: 1px solid var(--line);
}

.pts .end-map {
  max-width: none;
  margin: 0 0 clamp(1.4rem, 4vw, 2.6rem);
}

.pts .end-map svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.pts .art-end h2 {
  max-width: 16ch;
  margin: 0 0 1.2rem;
  font-family: var(--serif);
  font-size: clamp(2rem, 5.4vw, 3.2rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.015em;
}

.pts .hours {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.2rem 1.4rem;
  max-width: none;
  margin: 1.4rem 0 2rem;
  padding: 0;
  list-style: none;
}

.pts .hours li {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.9rem 0 0;
  border-top: 1px solid var(--line);
  font-family: var(--serif);
  font-size: 1.15rem;
  line-height: 1.3;
}

.pts .hours-art {
  width: 100%;
  max-width: 9rem;
}

.pts .hours-art svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  stroke-width: 3.4;
}

.pts .hours-text {
  display: block;
}

.pts .we {
  max-width: 34rem;
  margin: 0 0 1.8rem;
  font-size: 1.05rem;
  line-height: 1.6;
}

.pts .end-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.6rem;
  margin: 0;
}

.pts .quiet {
  display: inline-block;
  padding: 0.6em 0;
  color: var(--ink-soft);
  font-size: 0.95rem;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.pts .quiet:hover {
  color: var(--ink);
}

.pts .credits {
  max-width: 44rem;
  margin: 2.6rem 0 0;
  color: var(--ink-soft);
  font-size: 0.78rem;
  line-height: 1.5;
}

.pts .credits a {
  display: inline-block;
  padding: 0.6em 0;
  color: inherit;
}

/* ==== 10. Motion: the frame ============================================================== */

/* jumps (skip link, reloads) land at once instead of replaying the whole story;
   the road stops ask for smooth scrolling themselves */
html:has(.pts.art-live) {
  scroll-behavior: auto;
}

/* one sticky pin inside a tall story; story.js sets the story height from the
   step table, this is the same value for the first paint */
.pts.art-live .art-story {
  position: relative;
  height: calc(100svh * 23.5);
  overflow-anchor: none;
}

.pts.art-live .art-pin {
  --pano-h: 58svh;
  --ax: 0.5;
  --hdr: calc(4.6rem + env(safe-area-inset-top, 0px));
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}

.pts.art-live .art-stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  height: auto;
  margin: 0;
  overflow: hidden;
  border: 0;
  scroll-snap-type: none;
}

.pts.art-live .art-layers {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: auto;
  height: auto;
}

/* three depth layers; story.js sets each one's height from its viewBox
   (1000 units = --pano-h) and moves it sideways */
.pts.art-live .layer {
  display: block;
  position: absolute;
  left: 0;
  bottom: calc(3.4rem + env(safe-area-inset-bottom, 0px));
  height: var(--pano-h);
  width: auto;
  max-width: none;
  margin: 0;
  overflow: hidden; /* one compositor layer per drawing; story.js opens it */
  transform-origin: 0 0; /* the finale scales the mid layer about a point story.js picks */
  will-change: transform;
}

.pts.art-live .layer.is-open {
  overflow: visible;
}

/* the finale's resting whole-day view: repainted once, sharp, at its size */
.pts.art-live .layer.is-flat {
  will-change: auto;
}

.pts.art-live .layer-near {
  height: calc(var(--pano-h) * 0.3);
}

.pts.art-live .snap,
.pts.art-live .swipe-hint {
  display: none;
}

/* a sheet of paper that story.js lowers over far jumps (End, anchors) */
.pts.art-live .art-veil {
  position: absolute;
  inset: 0;
  z-index: 4;
  background: var(--sand);
  opacity: 0;
  pointer-events: none;
}

/* ==== 11. Motion: the words ================================================================ */

.pts.art-live .art-words {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 2;
  height: auto;
  pointer-events: none;
}

.pts.art-live .beat {
  position: absolute;
  top: calc(var(--hdr) + clamp(0.6rem, 2.4svh, 2rem));
  left: var(--gutter);
  right: var(--gutter);
  width: auto;
  margin: 0;
  padding: 0;
  opacity: 0;
  pointer-events: none;
  will-change: auto;
}

.pts.art-live .beat-title {
  top: calc(var(--hdr) + 3svh);
  opacity: 1;
  transform: none;
}

.pts.art-live .beat.is-warm {
  will-change: transform, opacity;
}

.pts.art-live .beat a {
  pointer-events: none;
}

.pts.art-live .beat.is-on,
.pts.art-live .beat.is-on a {
  pointer-events: auto;
}

.pts.art-live .m-hint {
  display: block;
}

/* ==== 12. Motion: starting states and transform origins ====================================== */

/* hidden until the engine's first frame takes over */
.pts.art-live [data-fx="draw"] {
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1.01;
}

.pts.art-live [data-fx="arrive"],
.pts.art-live [data-fx="pop"],
.pts.art-live [data-fx="fade"],
.pts.art-live [data-fx="light"],
.pts.art-live [data-fx="along"] {
  opacity: 0;
}

.pts.art-live svg [data-fx],
.pts.art-live svg [data-keys],
.pts.art-live svg [class*="idle-"] {
  transform-box: fill-box;
  transform-origin: 50% 50%;
}

.pts.art-live svg [data-fx="arrive"],
.pts.art-live svg .idle-sway,
.pts.art-live svg .idle-dance {
  transform-origin: 50% 100%;
}

/* movers, spins and the nib work in the layer's own user units */
.pts.art-live svg [data-fx="along"],
.pts.art-live svg [data-spin],
.pts.art-live svg .nib {
  transform-box: view-box;
  transform-origin: 0 0;
}

.pts.art-live svg .o-center { transform-origin: 50% 50%; }
.pts.art-live svg .o-bottom { transform-origin: 50% 100%; }
.pts.art-live svg .o-top { transform-origin: 50% 0; }
.pts.art-live svg .o-left { transform-origin: 0 50%; }
.pts.art-live svg .o-right { transform-origin: 100% 50%; }

.pts.art-live .nib {
  opacity: 0;
  pointer-events: none;
}

/* ==== 13. Motion: the sky ================================================================== */

/* the sun and moon live in screen space, behind every layer; story.js sets the
   sky's height to the horizon so they sink behind the sea line */
.pts.art-live .sky {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: 0;
  height: 60%;
  overflow: hidden;
  pointer-events: none;
}

.pts.art-live .sun {
  position: absolute;
  left: 0;
  top: 0;
  width: clamp(48px, 7vw, 76px);
  height: auto;
  margin: calc(clamp(48px, 7vw, 76px) / -2) 0 0 calc(clamp(48px, 7vw, 76px) / -2);
  overflow: visible;
  fill: none;
  color: #c98f3c;
  stroke: currentColor;
  stroke-width: 5.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pts.art-live .sun,
.pts.art-live .moon {
  opacity: 0;
  will-change: transform;
}

.pts.art-live .sun .sun-late {
  color: #c8553a;
  stroke: #c8553a;
  opacity: 0;
}

.pts.art-live .moon {
  position: absolute;
  left: 0;
  top: 0;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  overflow: visible;
  fill: #fbf6e6;
  stroke: var(--ink);
  stroke-width: 2.2;
  stroke-linejoin: round;
}

/* after sunset the whole stage darkens: one wash behind the moon and every
   drawing layer, reaching down under the road, so there is no edge between
   a night sky and a daylight shore (story.js keys its opacity) */
.pts .night-tint {
  display: none;
}

.pts.art-live .night-tint {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  background: linear-gradient(to bottom, rgb(28 48 130 / 0.46), rgb(34 56 136 / 0.28) 60%, rgb(34 56 136 / 0.2));
  pointer-events: none;
  will-change: opacity;
}

/* ==== 14. Motion: the road ================================================================== */

/* the van is the progress bar, the X marks are the stops */
.pts.art-live .road {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: calc(0.7rem + env(safe-area-inset-bottom));
  z-index: 3;
  width: auto;
  height: 42px;
  margin: 0;
  color: var(--ink);
  --cv-w: 9.5rem;
}

.pts.art-live .road-line {
  display: block;
  position: absolute;
  left: 0;
  bottom: 2px;
  width: 100%;
  height: 6px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-dasharray: 5 7;
  opacity: 0.55;
}

.pts.art-live .road-line path {
  vector-effect: non-scaling-stroke;
}

/* the caravan rides the road left to right: its van starts on the first X,
   its walker reaches the last one at night (story.js runRoad) */
.pts.art-live .van {
  display: block;
  position: absolute;
  left: 0;
  bottom: 3px;
  z-index: 2;
  width: var(--cv-w);
  will-change: transform;
  pointer-events: none;
}

.pts.art-live .van svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.pts.art-live .cv-lamp {
  opacity: 0;
}

.pts.art-run .cv-flame {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: pts-cv-flicker 1.7s ease-in-out infinite alternate;
}

@keyframes pts-cv-flicker {
  from { opacity: 0.8; transform: scale(1, 0.9); }
  to { opacity: 1; transform: scale(0.92, 1.1); }
}

.pts.art-live .stops {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 1;
}

.pts.art-live .stops li {
  position: absolute;
  bottom: -8px;
  left: 0;
  width: 44px;
  height: 44px;
  margin: 0 0 0 -22px;
  padding: 0;
}

.pts.art-live .stops li:nth-child(2) { left: calc(100% / 7); }
.pts.art-live .stops li:nth-child(3) { left: calc(200% / 7); }
.pts.art-live .stops li:nth-child(4) { left: calc(300% / 7); }
.pts.art-live .stops li:nth-child(5) { left: calc(400% / 7); }
.pts.art-live .stops li:nth-child(6) { left: calc(500% / 7); }
.pts.art-live .stops li:nth-child(7) { left: calc(600% / 7); }
.pts.art-live .stops li:nth-child(8) { left: 100%; }

.pts.art-live .stop {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 44px;
  height: 44px;
  min-height: 0;
  padding: 0 0 10px;
  border-radius: 50%;
  color: #b8452b;
  cursor: pointer;
}

/* the hour names stay for screen readers only */
.pts.art-live .stop-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.pts.art-live .stop-x {
  stroke: currentColor;
  transition: transform 0.3s ease;
}

.pts.art-live .stop[aria-current] .stop-x {
  stroke-width: 3.2;
  transform: scale(1.35);
}

.pts.art-live .stop:hover .stop-x {
  transform: scale(1.35);
}

.pts.art-live .stop:focus-visible {
  outline: 2px solid var(--sea);
  outline-offset: -6px;
}

/* ==== 15. Motion: idle life ================================================================== */

/* Small loops, only near the camera and while the story is on screen: the
   animation name is switched on by .art-run (story visible) and .is-near
   (story.js, near the camera and already arrived). */
.pts.art-live .idle-bob { animation: none 3.2s ease-in-out infinite alternate; --idle: pts-idle-bob; }
.pts.art-live .idle-bob-slow { animation: none 4.6s ease-in-out infinite alternate; --idle: pts-idle-bob; }
.pts.art-live .idle-sway { animation: none 4s ease-in-out infinite alternate; --idle: pts-idle-sway; }
.pts.art-live .idle-flap { animation: none 0.4s ease-in-out infinite alternate; --idle: pts-idle-flap; }
.pts.art-live .idle-turn { animation: none 24s linear infinite; --idle: pts-idle-turn; }
.pts.art-live .idle-drift { animation: none 6s ease-in-out infinite alternate; --idle: pts-idle-drift; }
.pts.art-live .idle-flicker { animation: none 2.3s linear infinite; --idle: pts-idle-flicker; }
.pts.art-live .idle-twinkle { animation: none 2.4s ease-in-out infinite alternate; --idle: pts-idle-twinkle; }
.pts.art-live .idle-breathe { animation: none 5s ease-in-out infinite alternate; --idle: pts-idle-breathe; }
.pts.art-live .idle-dance { animation: none 0.9s ease-in-out infinite alternate; --idle: pts-idle-dance; }
.pts.art-live .idle-dance.alt { animation-direction: alternate-reverse; }
.pts.art-live .idle-hint { animation: none 1.4s ease-in-out infinite alternate; --idle: pts-idle-hint; }

.pts.art-live .d1 { animation-delay: -0.7s; }
.pts.art-live .d2 { animation-delay: -1.4s; }
.pts.art-live .d3 { animation-delay: -2.1s; }
.pts.art-live .d4 { animation-delay: -2.8s; }

/* live pieces away from the camera (or not yet arrived) are not painted at
   all: nothing after an animated piece is then forced into a layer of its own */
.pts.art-live .live > [data-x]:not(.is-near) {
  visibility: hidden;
}

.pts.art-run .is-near[class*="idle-"],
.pts.art-run .is-near [class*="idle-"],
.pts.art-run .art-words [class*="idle-"],
.pts.art-run .sky [class*="idle-"],
.pts.art-run .road [class*="idle-"] {
  animation-name: var(--idle);
}

/* a keyed piece at opacity 0 (the scroll hint after the title, a tint by
   day) is not painted and runs no loop */
.pts.art-live .is-gone {
  visibility: hidden;
  animation-name: none !important;
}

/* the finale shows the whole day at once: every piece holds still */
.pts.art-fin .art-layers [class*="idle-"] {
  animation-name: none;
}

@keyframes pts-idle-bob {
  from { transform: translateY(-6px) rotate(-2.5deg); }
  to { transform: translateY(6px) rotate(2.5deg); }
}

@keyframes pts-idle-sway {
  from { transform: rotate(-2deg); }
  to { transform: rotate(2deg); }
}

@keyframes pts-idle-flap {
  from { transform: scaleY(1); }
  to { transform: scaleY(0.7); }
}

@keyframes pts-idle-turn {
  to { transform: rotate(360deg); }
}

@keyframes pts-idle-drift {
  from { transform: translateX(-12px); }
  to { transform: translateX(12px); }
}

@keyframes pts-idle-flicker {
  0%, 100% { opacity: 1; }
  30% { opacity: 0.82; }
  55% { opacity: 0.95; }
  80% { opacity: 0.78; }
}

@keyframes pts-idle-twinkle {
  from { opacity: 0.35; }
  to { opacity: 1; }
}

@keyframes pts-idle-breathe {
  from { transform: scale(1); }
  to { transform: scale(1.06); }
}

@keyframes pts-idle-dance {
  from { transform: rotate(-5deg); }
  to { transform: rotate(5deg); }
}

@keyframes pts-idle-hint {
  from { transform: translateY(0); }
  to { transform: translateY(6px); }
}

/* ==== 16. Motion: the ending draws itself as it scrolls into view ======================== */

/* story.js draws each vignette on with the scroll (card by card, stroke by
   stroke) and rolls the parked van in; without motion all of it is drawn */
.pts.art-live .art-end .end-draw {
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1.01;
}

.pts.art-live .art-end .end-van {
  transform: translateX(-700px);
}

/* ==== 17. Screen sizes ========================================================================== */

@media (max-width: 380px) {
  .pts .beat:not(.beat-title) h2 { font-size: 1.6rem; }
  .pts .beat p { font-size: 0.95rem; }
  .pts .beat .margin { width: 4.8rem; }
}

@media (orientation: portrait) and (max-height: 760px) {
  .pts.art-live .art-pin { --pano-h: 54svh; }
}

@media (min-width: 48rem) {
  .pts.art-live .art-pin { --pano-h: 62svh; --ax: 0.5; }
  .pts.art-live .road { --cv-w: 13rem; }

  .pts .hours li { font-size: 1.25rem; }
}

@media (min-width: 64rem) {
  .pts.art-live .art-pin { --pano-h: 70svh; --ax: 0.62; }

  /* the margin drawing moves out beside the words */
  .pts .beat .margin {
    position: absolute;
    left: calc(100% + 1.5rem);
    top: 0;
    float: none;
    width: 12rem;
    margin: 0;
  }

  .pts:not(.art-live) .beat-title .sub {
    margin-left: 0.4rem;
  }

  /* the gold circle round "Paros." swings below the baseline: give the sub room */
  .pts .beat-title .sub {
    margin-top: 1.7rem;
  }

  /* words in a left column, the scene to their right (--ax) */
  .pts.art-live .beat {
    left: max(var(--gutter), calc((100% - var(--wide)) / 2));
    right: auto;
    width: min(36rem, 42vw);
  }

  .pts.art-live .beat-title {
    top: calc(var(--hdr) + 8svh);
    width: auto;
  }

  .pts .hours { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* short landscape phones: two columns, the words on the left, the drawing
   (kept clear of the header) on the right */
@media (orientation: landscape) and (max-height: 520px) {
  .pts.art-live .art-pin { --pano-h: min(92svh, calc(100svh - 7rem)); --ax: 0.70; }
  .pts.art-live .road { --cv-w: 8.5rem; }

  .pts.art-live .beat {
    top: calc(var(--hdr) + 0.4rem);
    left: var(--gutter);
    right: auto;
    width: calc(40vw - var(--gutter));
  }

  .pts.art-live .beat p { font-size: 0.95rem; line-height: 1.5; }
  .pts.art-live .beat:not(.beat-title) h2 { font-size: 1.5rem; margin-bottom: 0.5rem; }
  .pts.art-live .beat .hour { margin-bottom: 0.35rem; }
  .pts.art-live .beat .margin { display: none; }

  .pts.art-live .beat-title {
    --giant: min(18vw, 26svh);
    top: calc(var(--hdr) + 1.8rem);
  }

  .pts.art-live .sub { font-size: 0.95rem; margin-top: 0.7rem; }
  .pts.art-live .m-hint { display: none; }
}

/* ==== 18. v3 motion: the streamed, tiled panorama ========================== */
/* (formerly motion.css; kept last and in load order so it overrides v2 rules above) */

/* Beta v3: motion rules for the streamed, tiled panorama (master plan 2.4, 3).
   Loaded after story.css (frozen) and overrides its v2 motion rules where the
   layers changed from one <svg> each to <div>s of scene tiles.
   Everything here is under html.art-live, which story-boot.js / story.js set
   only when motion is on; the static page never sees these rules.

   1. The frame: story height, layer boxes, tiles
   2. Waiting for a scene: the pencil that scribbles
   3. Idle life: the new loops
*/

/* ==== 1. The frame ======================================================================== */

/* 24 steps + 0.4 tail + 1.0 finale = 34.95; story.js sets the same from the
   step table, this is the value for the first paint */
.pts.art-live .art-story {
  height: calc(100svh * 35.95);
}

/* story.js places the tiles (and sizes each layer box) before it adds
   art-ready; until then the drawing is not shown, so nothing shifts */
.pts.art-live:not(.art-ready) .art-layers {
  visibility: hidden;
}

/* a layer is a box of tiles in its own user units: story.js sets its width
   and height (1000 units = --pano-h) and moves it sideways */
.pts.art-live .layer {
  display: block;
  position: absolute;
  left: 0;
  bottom: calc(3.4rem + env(safe-area-inset-bottom, 0px));
  width: 0;
  max-width: none;
  margin: 0;
  overflow: hidden;
  transform-origin: 0 0; /* the finale scales the mid layer about a point story.js picks */
  will-change: transform;
}

.pts.art-live .tiles {
  position: absolute;
  inset: 0;
}

/* one <svg> per scene part, placed by story.js in layer pixels; a streamed
   tile arrives at opacity 0 and fades in once its cues are set */
.pts.art-live .tile {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  max-width: none;
  overflow: hidden;
  transition: opacity 0.35s ease;
}

.pts.art-live .tile.is-loading {
  opacity: 0;
  transition: none;
}

/* words in a side column: the title map steps aside for the first beat */
.pts.art-live.art-title-off .tile[data-scene="0"][data-layer="mid"] {
  opacity: 0;
}

/* the pencil tip rides the hero strokes of every scene, over the mid tiles */
.pts.art-live .nib-svg {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  overflow: visible;
  pointer-events: none;
}

.pts .art-scenes,
.pts.art-live .art-scenes {
  display: none;
}

/* ==== 2. Waiting for a scene ================================================================= */

/* the reader outran the network: over the horizon at the camera, a small
   pencil scribbles until the scene is in (story.js adds .is-sketching after
   250 ms of waiting; the loop runs only then) */
.pts .sketch-wait {
  display: none;
}

.pts.art-live .sketch-wait {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  width: 90px;
  height: 56px;
  max-width: none;
  overflow: visible;
  opacity: 0;
  fill: none;
  stroke: var(--ink);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.pts.art-live .is-sketching .sketch-wait {
  opacity: 0.8;
}

.pts.art-live .sketch-wait .sw-line {
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
}

.pts.art-live .sketch-wait .sw-body {
  fill: #d8b98a;
  stroke-width: 1.6;
}

.pts.art-live .sketch-wait .sw-tip {
  fill: var(--ink);
  stroke: none;
}

.pts.art-run .is-sketching .sw-line {
  animation: pts-sw-draw 1.4s linear infinite;
}

.pts.art-run .is-sketching .sw-nib {
  animation: pts-sw-move 1.4s linear infinite;
}

@keyframes pts-sw-draw {
  0% { stroke-dashoffset: 1; }
  85%, 100% { stroke-dashoffset: 0; }
}

@keyframes pts-sw-move {
  0% { transform: translate(0, 0); }
  17% { transform: translate(12px, -5px); }
  34% { transform: translate(24px, 1px); }
  51% { transform: translate(36px, -5px); }
  68% { transform: translate(48px, 1px); }
  85%, 100% { transform: translate(64px, -4px); }
}

/* ==== 3. Idle life: the new loops (same pattern as story.css 15) ================================ */

.pts.art-live .idle-float { animation: none 5s ease-in-out infinite alternate; --idle: pts-idle-float; }
.pts.art-live .idle-drip { animation: none 1.6s linear infinite; --idle: pts-idle-drip; }
.pts.art-live .idle-chop { animation: none 1.1s ease-in-out infinite alternate; --idle: pts-idle-chop; }

.pts.art-live svg .idle-float,
.pts.art-live svg .idle-chop {
  transform-origin: 50% 100%;
}

@keyframes pts-idle-float {
  from { transform: translateY(-2px) rotate(-0.6deg); }
  to { transform: translateY(2px) rotate(0.6deg); }
}

@keyframes pts-idle-drip {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(16px); opacity: 0; }
}

@keyframes pts-idle-chop {
  from { transform: translateY(-3px) rotate(-4deg); }
  to { transform: translateY(3px) rotate(4deg); }
}

/* ==== 19. v3 ink: the drawing kit and the static title map ================= */
/* (formerly art.css; kept last and in load order so it overrides v2 rules above) */

/* Beta v3: the ink of the drawing kit (ART-CORE), and the static title map.
   Loaded after story.css (frozen) and motion.css. Scene groups add their own
   classes in art-antiparos.css (ap-), art-paros.css (pa-), art-parikia.css (pk-).

   1. Paper: opaque land and vessels, darkness, the cave
   2. Pencil: guide line, loose and dotted dashes
   3. The static page: the title map instead of the v2 swipe panorama
*/

/* ==== 1. Paper ========================================================================= */

/* every hill, island, rock and castle, and every vessel, is opaque paper under
   its ink: a boat behind land is hidden by it, never drawn over it */
.pts .layer .land-paper,
.pts .layer .ship-paper {
  fill: var(--sand);
  stroke: none;
}

/* the same shapes darkening with the sky before dawn and after sunset (the
   keys drive the opacity; the static page never shows them) */
.pts .layer .land-dark {
  fill: rgb(52 72 148);
  fill-opacity: 0.6;
  stroke: none;
  opacity: 0;
}

/* a vessel's night veil is a little lighter still, so its rigging reads */
.pts .layer [data-ship] > .land-dark {
  fill-opacity: 0.5;
}

/* a paper halo under a figure standing in front of drawn lines (v3b): the same
   wobbled strokes, wider, in paper; and its night twin, which dims with the
   houses behind (the same keys as .land-dark) */
.pts .layer .fig-halo {
  fill: none;
  stroke: var(--sand);
  stroke-width: 9.8;
}
.pts .layer .land-dark.fig-halo {
  fill: none;
  stroke: rgb(52 72 148);
  stroke-opacity: 0.6;
}

/* the surface of the land under its outline: slope hatching, scrub, stones */
.pts .layer .tex {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.8;
  stroke-opacity: 0.42;
}

.pts .layer .tex-far {
  stroke-width: 2.2;
  stroke-opacity: 0.3;
}

/* inside the hill of the cave */
.pts .layer .cave-dark {
  fill: rgb(90 110 130 / 0.28);
  stroke: none;
}

.pts .layer .tile,
.pts .tile {
  max-width: none;
}

.pts .art-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ==== 2. Pencil ======================================================================== */

/* the faint horizon under everything, so the stage is never blank while a
   scene streams in */
.pts .layer .guide {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.6;
  stroke-dasharray: 6 10;
  opacity: 0.22;
}

/* the route over the two ferry crossings: a looser, dotted dash on the sea */
.pts .layer .dash.wide {
  stroke-dasharray: 3 15;
}

/* a dotted sight line (from the cave to Despotiko: a view, not a trip) */
.pts .layer .dot {
  stroke-dasharray: 0.1 11;
  stroke-width: 4.2;
}

/* ==== 3. The static page ================================================================ */

/* Without motion (JS off, reduced motion) the stage is one picture: the title
   map, centred, under the title. The mid layer's scene-0 tiles all share the
   box -1500 -520 2500 1520, so y 0..1000 fills the stage and the map's centre
   (x 450) sits at the stage's centre. Nothing else of the panorama shows. */
.pts:not(.art-live) .art-stage {
  --stage-h: min(56svh, 520px);
  height: var(--stage-h);
  overflow: hidden;
  scroll-snap-type: none;
}

.pts:not(.art-live) .art-layers {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.pts:not(.art-live) .layer-mid {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}

.pts:not(.art-live) .tiles {
  position: absolute;
  inset: 0;
}

.pts:not(.art-live) .layer-mid .tile {
  display: none;
}

/* --u: px per unit. The map band (x 80..820, y 60..700) fills the stage's
   height, or the screen's width on a phone, whichever is smaller; its centre
   (450, 380) sits at the stage's centre */
.pts:not(.art-live) .layer-mid .tile[data-scene="0"] {
  --u: min(calc(var(--stage-h) / 660), calc(94vw / 760));
  display: block;
  position: absolute;
  top: calc(50% - var(--u) * 900);
  left: calc(50% - var(--u) * 1950);
  width: calc(var(--u) * 2500);
  height: calc(var(--u) * 1520);
  max-width: none;
}

.pts:not(.art-live) :is(.tile[data-scene="guide"], .nib-svg) {
  display: none;
}

/* the v2 swipe hint is gone (there is nothing to swipe) */
.pts .swipe-hint {
  display: none;
}

/* ==== 20. v3 scenes: Antiparos in the morning (ap-) ======================== */
/* (formerly art-antiparos.css; kept last and in load order so it overrides v2 rules above) */

/* Beta v3: Antiparos in the morning (steps 1-8), SCENES-ANTIPAROS.
   Classes used by src/scenes/antiparos.py; every one is prefixed ap-.

   1. Structures and paper: quays and slipways, the ferry's ramps, whitewash
   2. Light: flames, drops
   3. Colour washes: sea, sand, the cave's stone, dark openings
*/

/* ==== 1. Structures and paper ================================================ */

/* slipways and moles: concrete a vessel may touch (data-quay, never land) */
.pts .layer .ap-quay {
  fill: #e6dccb;
  stroke: none;
}

/* the ferry's hinged ramps: a steel plate, opaque */
.pts .layer .ap-steel {
  fill: #ddd3c2;
  stroke: none;
}

/* the Kastro's ring of houses is whitewashed, not sand */
.pts .layer .ap-lime .land-paper {
  fill: #faf7f0;
}

/* the loopholes in the blind outer wall */
.pts .layer .ap-slit {
  stroke-width: 4.4;
}

/* the tour escort: a slightly bolder figure at the head of the group */
.pts .layer .ap-escort {
  stroke-width: 4.4;
}

/* ==== 2. Light ================================================================ */

.pts .layer .ap-flame {
  fill: #fff0c4;
  stroke: #b07a36;
  stroke-width: 2;
}

.pts .layer .ap-drop {
  fill: #cfe0ea;
  stroke: #6f8fa3;
  stroke-width: 1.6;
}

/* ==== 3. Colour washes ======================================================== */

/* blue domes, doors and shutters */
.pts .layer .ap-blue {
  fill: rgb(70 110 160 / 0.55);
  stroke: none;
}

/* the gate's and the cave mouth's darkness */
.pts .layer .ap-dark {
  fill: rgb(60 52 44 / 0.55);
  stroke: none;
}

/* Agia Trapeza: pale stone, opaque over the chamber's shade */
.pts .layer .ap-stone {
  fill: #e7ddcc;
  stroke: none;
}

.pts .layer .ap-sand {
  fill: rgb(226 196 140 / 0.55);
  stroke: none;
}

/* the cove's still water */
.pts .layer .ap-teal {
  fill: rgb(70 170 170 / 0.27);
  stroke: none;
}

/* the tamarisk's feathery canopy */
.pts .layer .ap-olive {
  stroke: #6f7a58;
  stroke-width: 3;
}

/* ==== 21. v3 scenes: Paros in the afternoon (pa-) ========================== */
/* (formerly art-paros.css; kept last and in load order so it overrides v2 rules above) */

/* Beta v3: Paros, midday and afternoon (steps 9-16), SCENES-PAROS.
   Classes used by src/scenes/paros.py; every one is prefixed pa-, and every
   rule is scoped to the panorama layers (.layer), so nothing leaks out.

   1. Structures: quays and piers, whitewash, marble, the tunnel
   2. Boats: hulls and stripes, sails and boards, nets and floats
   3. Light: flames, the glow through the slab
   4. Colour washes: doors and shutters, awnings, sand, octopus, granite
   5. Pencil: strata, alleys, marble hatching, olive leaves, the escort
*/

/* ==== 1. Structures ====================================================== */

/* piers and quays: stone a boat may touch (data-quay, never land) */
/* the lamp-stone earth bowl: a paler wash halo and a darker dried edge */
.pts .layer .earth.pa-halo {
  fill-opacity: 0.45;
}
.pts .layer .pa-bloom {
  fill: none;
  stroke: #b89468;
  stroke-width: 2.2;
  stroke-opacity: 0.45;
}

.pts .layer .pa-quay {
  fill: #e8dfcf;
  stroke: none;
}

.pts .layer .pa-quay-face {
  fill: #d9ccb6;
  stroke: none;
}

/* worked marble: blocks, the relief niche, the path's slabs */
.pts .layer .pa-marble {
  fill: #fbf8f1;
  stroke: none;
}

/* the pale quarry face on the hill */
.pts .layer .pa-rockface {
  fill: rgb(250 247 240 / 0.7);
  stroke: none;
}

/* the dark of a tunnel mouth */
.pts .layer .pa-dark {
  fill: rgb(60 52 44 / 0.62);
  stroke: none;
}

/* inside the quarry tunnel, a cool shade */
.pts .layer .pa-tunnel {
  fill: rgb(96 86 74 / 0.22);
  stroke: none;
}

/* the thin slab of lychnites: marble that lets the light through */
.pts .layer .pa-slab {
  fill: #fbf6e8;
  fill-opacity: 0.6;
  stroke: none;
}

/* ==== 2. Boats ============================================================ */

.pts .layer .pa-hull-white {
  fill: #fbf9f4;
  stroke: none;
}

.pts .layer .pa-hull-blue {
  fill: rgb(74 111 165 / 0.35);
  stroke: none;
}

.pts .layer .pa-st-red { stroke: #b8452b; stroke-width: 3.6; }
.pts .layer .pa-st-blue { stroke: #3f6a9e; stroke-width: 3.6; }
.pts .layer .pa-st-green { stroke: #3f8c6e; stroke-width: 3.6; }

/* windsurf sails (and the racked ones on the beach) */
.pts .layer .pa-sail1 { fill: #c0503a; fill-opacity: 0.55; stroke: none; }
.pts .layer .pa-sail2 { fill: #e0a84a; fill-opacity: 0.55; stroke: none; }
.pts .layer .pa-sail3 { fill: #3f8c96; fill-opacity: 0.55; stroke: none; }
.pts .layer .pa-sail4 { fill: #d98b7a; fill-opacity: 0.55; stroke: none; }
.pts .layer .pa-sail5 { fill: #4a6fa5; fill-opacity: 0.55; stroke: none; }

.pts .layer .pa-board {
  fill: #fbf9f4;
  stroke: none;
}

/* nets, floats */
.pts .layer .pa-net {
  stroke: #6f6658;
  stroke-width: 1.8;
}

.pts .layer .pa-net-fill {
  fill: rgb(111 102 88 / 0.18);
  stroke: none;
}

.pts .layer .pa-float {
  fill: #d0643e;
  stroke: #7a3a22;
  stroke-width: 1.4;
}

/* ==== 3. Light ============================================================ */

.pts .layer .pa-flame {
  fill: #fff0c4;
  stroke: #b07a36;
  stroke-width: 2;
}

/* the lamp's bright heart seen through the slab */
.pts .layer .pa-core {
  fill: #ffe6a6;
  fill-opacity: 0.85;
  stroke: none;
}

/* ==== 4. Colour washes ==================================================== */

.pts .layer .pa-teal {
  fill: rgb(63 140 150 / 0.55);
  stroke: none;
}

.pts .layer .pa-blue {
  fill: rgb(70 110 160 / 0.55);
  stroke: none;
}

.pts .layer .pa-awn-blue {
  fill: rgb(74 111 165 / 0.5);
  stroke: none;
}

.pts .layer .pa-awn-red {
  fill: rgb(192 80 58 / 0.45);
  stroke: none;
}

/* Golden Beach: the sand */
.pts .layer .pa-sand {
  fill: rgb(226 190 120 / 0.55);
  stroke: none;
}

/* the drying octopus */
.pts .layer .pa-octo {
  fill: rgb(196 120 110 / 0.45);
  stroke: none;
}

/* the granite of Kolymbithres, honey in the low sun */
.pts .layer .pa-honey {
  fill: rgb(224 168 74 / 0.25);
  stroke: none;
}

/* ==== 5. Pencil =========================================================== */

.pts .layer .pa-strata {
  stroke: #8f8676;
  stroke-width: 2;
  opacity: 0.6;
}

.pts .layer .pa-alley {
  stroke-width: 3;
  opacity: 0.7;
}

.pts .layer .pa-marble-hatch {
  stroke: #9a9488;
  stroke-width: 1.8;
}

.pts .layer .pa-olive {
  stroke: #5f6b48;
}

/* the tour escort: a slightly bolder figure at the head of the walkers */
.pts .layer .pa-escort {
  stroke-width: 4.4;
}

/* ==== 22. v3 scenes: Parikia in the evening (pk-) ========================== */
/* (formerly art-parikia.css; kept last and in load order so it overrides v2 rules above) */

/* Beta v3: Parikia in the evening (steps 17-20), SCENES-PARIKIA.
   Classes used by src/scenes/parikia.py; every one is prefixed pk-.
   Everything is scoped under .layer (the panorama), so nothing leaks into a
   host page when the story is nested in the home page.

   1. Stone, marble and paving (Ekatontapyliani, the Kastro wall)
   2. Town colour (cypresses, doors, bougainvillea, sand)
   3. People
   4. Light (reflections, moonlight, headlights)
*/

/* ==== 1. Stone, marble and paving ======================================= */

/* the Ekatontapyliani's unwhitewashed stone, laid over its lime base */
.pts .layer .pk-stone {
  fill: rgb(214 196 166 / 0.55);
  stroke: none;
}

/* its dome: whitewashed, a faint cool shade */
.pts .layer .pk-dome {
  fill: rgb(196 208 214 / 0.35);
  stroke: none;
}

/* the courtyard paving, and the whitewash painted in its joints */
.pts .layer .pk-pave {
  fill: #e4d8c3;
  stroke: none;
}
.pts .layer .pk-joint {
  stroke: #fbf8f1;
  stroke-width: 3.2;
}

/* temple blocks and column drums in the Kastro wall: opaque marble */
.pts .layer .pk-marble {
  fill: #f1ebe0;
  stroke: none;
}

/* ==== 2. Town colour ====================================================== */

.pts .layer .pk-cypress {
  fill: rgb(86 104 72 / 0.55);
  stroke: none;
}
.pts .layer .pk-blue {
  fill: #4a6fa5;
  fill-opacity: 0.7;
  stroke: none;
}
.pts .layer .pk-bougain {
  fill: #c2527a;
  fill-opacity: 0.55;
  stroke: none;
}
.pts .layer .pk-sand {
  fill: #e6cc98;
  fill-opacity: 0.55;
  stroke: none;
}

/* ==== 3. People ============================================================ */

.pts .layer .pk-head {
  fill: var(--ink);
  stroke: none;
}
.pts .layer .pk-fig {
  stroke-width: 3.4;
}

/* ==== 4. Light ============================================================= */

.pts .layer .pk-refl {
  stroke: #e0b25a;
  stroke-width: 3;
}
.pts .layer .pk-moon {
  stroke: #dfe6ee;
  stroke-width: 3;
}
.pts .layer .pk-beam {
  fill: #f3d58a;
  fill-opacity: 0.32;
  stroke: none;
}

/* a partial night dimming (the beach at night): the same keys as .land-dark,
   a lighter veil */
.pts .layer .land-dark.pk-dim {
  fill-opacity: 0.14;
}

/* ==== 23. v3 words: the new marks and the two-line title =================== */
/* (formerly words.css; kept last and in load order so it overrides v2 rules above) */

/* Beta v3, WORDS: "Paros & Antiparos, drawn by hand".

   Everything story.css (frozen) does not already cover for the new copy:
   the five new pencil marks (drips, rays, trail, bulbs, and un-hiding the
   arrow story.css shipped but never used), and the two-line title.
   Loaded last, after art.css/art-*.css, so it can override story.css's
   ".m-arrow{display:none}" placeholder rule.

   Sections
     1. New pencil marks
     2. The two-line title
     3. Small screens */

/* ==== 1. New pencil marks ======================================================= */

.pts .m-drips,
.pts .m-rays,
.pts .m-trail,
.pts .m-bulbs,
.pts .m-arrow {
  position: absolute;
  max-width: none; /* site.css caps svg at 100%: marks must reach past the word */
  overflow: visible;
  fill: none;
  stroke: #b07a36;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

/* a wavy underline with three hanging drips, for "stalactites" */
.pts .m-drips {
  left: -2%;
  bottom: -0.95em;
  width: 104%;
  height: 1.35em;
  stroke-width: 3;
}

/* five ticks fanned above the word, for "the Holy Table" */
.pts .m-rays {
  left: 4%;
  top: -1.5em;
  width: 92%;
  height: 1.55em;
  stroke-width: 2.6;
}

/* footprints along a curve under the phrase, then a small X, for "The van waits" */
.pts .m-trail {
  left: -3%;
  bottom: -0.9em;
  width: 106%;
  height: 1.15em;
  stroke-width: 2.8;
}

/* a sagging string of bulbs above the phrase, for "the lights come on" */
.pts .m-bulbs {
  left: 1%;
  top: -1.65em;
  width: 98%;
  height: 1.55em;
  stroke-width: 2.6;
}

/* story.css ships .m-arrow{display:none} (it was never used in v2); the
   "back across" beat needs it: a small curved sweep after the word, into
   the picture, with an arrowhead */
.pts .m-arrow {
  display: block;
  left: calc(100% + 0.06em);
  top: -0.05em;
  width: 2.35em;
  height: 1.18em;
  stroke-width: 3;
}

.pts .m-drips.red,
.pts .m-rays.red,
.pts .m-trail.red,
.pts .m-bulbs.red,
.pts .m-arrow.red {
  stroke: #b8452b;
}

/* ==== 2. The two-line title ====================================================== */

/* "Paros" (with its gold ring) sits on the first line beside a gold italic
   "&"; "Antiparos." (with its red underline) drops to its own line, at a
   smaller size so both fit above the map on a narrow phone. */
.pts .giant {
  font-size: clamp(3.4rem, min(17vw, 22svh), 9rem);
}

.pts .amp {
  padding: 0 0.06em;
  color: #b07a36;
  font-style: italic;
}

.pts .line2 {
  display: block;
  font-size: 0.62em;
  margin-top: 0.04em;
}

.pts .line2 .mark {
  margin-left: 0;
}

/* ==== 3. Small screens =========================================================== */

@media (max-width: 380px) {
  .pts .m-drips,
  .pts .m-trail {
    height: 1.15em;
  }

  .pts .m-rays,
  .pts .m-bulbs {
    height: 1.3em;
  }

  .pts .m-arrow {
    width: 2rem;
  }
}

@media (min-width: 64rem) {
  .pts .giant {
    font-size: clamp(3.6rem, min(14vw, 20svh), 9.5rem);
  }
}

/* ==== 24. v3b scenes: the three new stops (pm-) ==== */
/* (formerly art-more.css) Petaloudes, Kefalos and Detis
   (src/scenes/paros_more.py).

   1. Petaloudes: leaves, bark, water, wood, the moths, sun flecks
   2. Kefalos: the lit flank, blue doors
   3. Detis: the gold wall, the lamp, the beam
   4. People: the paper halo
   5. Idle life: flow, flutter, sweep (same pattern as story.css 15) */

/* ==== 1. Petaloudes ======================================================== */

.pts .layer .pm-slope { fill: rgb(112 140 92 / 0.22); stroke: none; }
.pts .layer .pm-leaf { fill: rgb(96 128 84 / 0.30); stroke: none; }
.pts .layer .pm-hole { fill: var(--sand); fill-opacity: 0.85; stroke: none; }
.pts .layer .pm-bark { fill: rgb(214 196 170 / 0.9); stroke: none; }
.pts .layer .pm-water { fill: rgb(120 170 175 / 0.45); stroke: none; }
.pts .layer .pm-glint {
  fill: none;
  stroke: #f3ebdd;
  stroke-width: 3;
  stroke-dasharray: 10 22;
}
.pts .layer .pm-wood { stroke: #7a5a3a; stroke-width: 3; }
.pts .layer .pm-plank { fill: rgb(196 160 112 / 0.75); stroke: none; }
.pts .layer .pm-fleck { fill: rgb(243 213 138 / 0.45); stroke: none; }

/* the Jersey tiger moth: closed at rest (bark brown), open in flight (red hindwings
   under black-and-cream forewings) */
.pts .layer .pm-moth { fill: #6f604c; stroke: none; }
.pts .layer .pm-moth-ink { stroke-width: 1.8; }
.pts .layer .pm-rest-dot { stroke: #f3ebdd; stroke-width: 3.4; }
.pts .layer .pm-wing-f { fill: #2c261f; stroke: none; }
.pts .layer .pm-wing-h { fill: #c8402a; stroke: none; }
.pts .layer .pm-wing-dot { stroke: #f3ebdd; stroke-width: 3; }
.pts .layer .pm-body { stroke: #2c261f; stroke-width: 2.2; }

/* ==== 2. Kefalos =========================================================== */

.pts .layer .pm-sunflank { fill: rgb(230 196 140 / 0.28); stroke: none; }
.pts .layer .pm-blue { fill: rgb(70 110 160 / 0.8); stroke: none; }

/* ==== 3. Detis ============================================================= */

.pts .layer .pm-sunwall { fill: rgb(232 178 90 / 0.55); stroke: none; }
.pts .layer .pm-lamp { fill: #fff3cf; stroke: #b07a36; stroke-width: 2; }
/* the beam: its fill is a gradient (fill attribute) that fades along the cone */
.pts .layer .pm-beam { stroke: none; }
/* a warm gold core along each cone (its stroke is a gradient too), and dashed edges */
.pts .layer .pm-core { fill: none; stroke-width: 5; stroke-linecap: round; }
.pts .layer .pm-ray { stroke: #c08a34; stroke-width: 2.8; stroke-opacity: 0.85; stroke-dasharray: 16 9; }

/* ==== 4. People ============================================================ */

/* a paper halo under a figure standing in front of drawn lines (same wobble, wider) */
.pts .layer .pm-halo { stroke: var(--sand); stroke-width: 10; }

/* ==== 5. Idle life ========================================================= */

.pts.art-live .idle-flow { animation: none 2.6s linear infinite; --idle: pm-idle-flow; }
.pts.art-live .idle-flutter { animation: none 0.44s step-end infinite; --idle: pm-idle-flutter; }
.pts.art-live .idle-flutter.alt { animation-delay: -0.22s; }
.pts.art-live .idle-sweep { animation: none 4.8s ease-in-out infinite alternate; --idle: pm-idle-sweep; }

/* the beam pivots on the Korakas lamp (13600, 369 in the Detis tile's own units) */
.pts.art-live svg .idle-sweep {
  transform-box: view-box;
  transform-origin: 13600px 369px;
}

@keyframes pm-idle-flow {
  from { stroke-dashoffset: 0; }
  to { stroke-dashoffset: -64; }
}

@keyframes pm-idle-flutter {
  0% { opacity: 1; }
  50% { opacity: 0.1; }
  100% { opacity: 0.1; }
}

@keyframes pm-idle-sweep {
  from { transform: rotate(-8deg); }
  to { transform: rotate(8deg); }
}

/* ==== 25. v3b words ==== */
/* (formerly words-more.css) The new beats' marks and the mark fixes.

   3.3: m-rays (mass "the Holy Table", detis "Korakas lighthouse") and
   m-bulbs (evening "the lights come on") sit low enough to scribble
   through the text line above them at small sizes. Pull them in and
   thin them so they clear that line. Loads after story.css section 23,
   so these rules win over it.

   Checked on desktop (1440) with the marks force-drawn: at story.css's
   own line-height, "top: -0.95em"/"top: -1em" still overlaps the line
   above by about 11-12px for every m-rays/m-bulbs instance (mass,
   detis, evening) — the fix's first form only shrinks the scribble, it
   does not clear it. All three marks sit on the last line of their
   paragraph with nothing below but the margin drawing, so the plan's
   own fallback applies cleanly: hang the mark below the phrase
   instead of above it. */

/* v3b r2: the hanging rays were a 1px smudge (the fan used a sixth of its 200x50
   box). The template now crops the box to the fan (viewBox 78 12 46 32), so at
   1.4em it is about 32x22px with a real 2px stroke, fanning up at the phrase. */
.pts .m-rays {
  top: auto;
  bottom: -1.3em;
  height: 1.4em;
  stroke-width: 3;
}

.pts .m-bulbs {
  top: auto;
  bottom: -1em;
  height: 0.95em;
  stroke-width: 2.2;
}

/* the red loop round "ruins of a Venetian castle." closes before the next word */
.pts .beat[data-step="kefalos"] .m-loop {
  left: -4%;
  width: 108%;
}

.pts .beat[data-step="kefalos"] .nw {
  margin: 0 0.3em 0 0.2em;
}

@media (max-width: 380px) {
  .pts .m-rays {
    height: 1.25em;
  }

  .pts .m-bulbs {
    height: 0.9em;
  }
}
