/* One weight of one typeface: hierarchy comes from size, colour and space, which also keeps the font file small */
@font-face {
  font-family: "Serif SC";
  src: url("fonts/serif-sc.woff2?v=cd41f03a") format("woff2");
  font-weight: 500;
  font-display: block;
}

:root {
  /* Each colour has one job: ink for text, copper for everything that needs attention, paper for the ground */
  --paper: #fbf7ee;
  /* A faint grain, so the ground reads as paper rather than a flat colour */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .42 0 0 0 0 .34 0 0 0 0 .2 .08 0 0 0 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  /* The paper as it looks with the grain on it, for places that can only take one flat colour */
  --ground: #f8f3ea;
  --ink: #15171a;
  --copper: #7c4030;
  --soft: #6b655a;
  --faint: #78726a;
  /* Only for controls that cannot be used, which need not be read */
  --off: #a39d90;
  --rule: #e6dfcf;

  --fs-small: 15px;
  --fs-body: 16px;
  --fs-option: 18px;
  --fs-verse: 23px;
  --fs-title: 46px;
  --fs-score: 76px;

  /* Motion: quick to start, slow to settle. Three speeds: a touch answers at once, a page takes its time, a ceremony longer.
     It plays whatever the phone's reduce-motion setting says; the owner decided that */
  --ease: cubic-bezier(.22, .7, .2, 1);
  --t-press: .12s;
  --t-state: .18s;
  --t-move: .35s;
  --t-page: .45s;
}

* { box-sizing: border-box; margin: 0; -webkit-tap-highlight-color: transparent; }

html { background: var(--ground); -webkit-text-size-adjust: 100%; }

/* Safari 26 on iPhone ignores theme-color and tints its bars from a fixed, full-width, solid element
   at least 6px tall at each edge of the screen. It must stay visible, or Safari stops using it */
.edge { position: fixed; left: 0; width: 100%; height: 6px; z-index: 2; background-color: var(--ground); pointer-events: none; }
.edge.top { top: 0; }
.edge.bottom { bottom: 0; }

body {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--paper) var(--grain);
  color: var(--ink);
  font-family: "Serif SC", serif;
  font-weight: 500;
  font-synthesis: none;
  font-size: var(--fs-body);
  line-height: 1.7;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  touch-action: manipulation;
}

#app {
  max-width: 480px;
  margin: 0 auto;
  padding: calc(env(safe-area-inset-top) + 28px) 24px calc(env(safe-area-inset-bottom) + 36px);
}

@keyframes fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes enter {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

@keyframes leave {
  to { opacity: 0; transform: translateY(-4px); }
}

@keyframes grow {
  from { transform: scaleX(0); }
}

/* A new screen arrives in a few close batches; the bars that stay in place only fade */
.entering > * { animation: enter var(--t-page) var(--ease) backwards; }
.entering > :nth-child(2) { animation-delay: .05s; }
.entering > :nth-child(3) { animation-delay: .1s; }
.entering > :nth-child(4) { animation-delay: .15s; }
.entering > :nth-child(5) { animation-delay: .2s; }
.entering > :nth-child(n+6) { animation-delay: .25s; }
.entering > .topbar, .entering > .progress { animation-name: fade; }
.entering > .arriving { animation: none; }
#app .leaving { animation: leave calc(var(--t-state) - .02s) ease-in forwards; pointer-events: none; }

/* A press answers at once */
.primary, .secondary, .book-chip, .chapter, .review, .stop-row, .link { -webkit-user-select: none; user-select: none; }
.primary:active:not(:disabled), .secondary:active:not(:disabled) { transform: scale(.985); }
.chapter:active, .book-chip:active { transform: scale(.94); }
.link, .review, .stop-row { transition: opacity var(--t-press) var(--ease); }
.link:active, .review:active, .stop-row:not(.locked):active { opacity: .6; }

.label { font-size: var(--fs-small); color: var(--soft); letter-spacing: .08em; }

.link {
  position: relative;
  font-size: var(--fs-small);
  color: var(--soft);
  letter-spacing: .08em;
}
/* Small to look at, about 44px to tap */
.link::after { content: ""; position: absolute; inset: -14px -10px; }

.primary {
  display: block;
  width: 100%;
  padding: 15px;
  background: var(--copper);
  color: var(--paper);
  letter-spacing: .24em;
  text-indent: .24em;
  transition: opacity var(--t-press) var(--ease), transform var(--t-press) var(--ease);
}
.primary:active { opacity: .78; }
.primary:disabled { background: var(--rule); color: var(--off); cursor: default; }

.secondary {
  display: block;
  width: 100%;
  padding: 14px;
  border: 1px solid var(--rule);
  letter-spacing: .24em;
  text-indent: .24em;
  transition: border-color var(--t-state) var(--ease), transform var(--t-press) var(--ease);
}
.secondary:active:not(:disabled) { border-color: var(--copper); }
.secondary:disabled { color: var(--off); cursor: default; }

/* Home */
.brand { padding: 26px 0 26px; text-align: center; }
.brand h1 {
  font-size: var(--fs-title);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: .3em;
  text-indent: .3em;
}
.brand h1::after { content: ""; display: block; width: 24px; height: 2px; margin: 18px auto 0; background: var(--copper); }
.entering .brand h1::after { animation: grow .7s var(--ease) .2s backwards; }
.brand p { margin-top: 16px; color: var(--soft); font-size: var(--fs-small); letter-spacing: .14em; text-indent: .14em; }
/* Short phones: a smaller name, so more of the page fits on the first screen */
@media (max-height: 700px) {
  .brand { padding: 14px 0 18px; }
  .brand h1 { font-size: 40px; }
  .brand h1::after { margin-top: 12px; }
  .brand p { margin-top: 12px; }
}

/* The two main functions: one framed bar with a block that slides across */
.modes { position: relative; display: flex; border: 1px solid var(--copper); }
.modes button {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 44px;
  color: var(--copper);
  letter-spacing: .4em;
  text-indent: .4em;
  transition: color var(--t-state) var(--ease);
}
/* Beside the selected block a divider disappears into it; between the other two it shows */
.modes button + button { border-left: 1px solid var(--copper); }
.modes button.on { color: var(--paper); }
.mode-thumb {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 50%;
  background: var(--copper);
  transition: transform var(--t-move) var(--ease), width var(--t-move) var(--ease);
}

.section { padding: 24px 0 0; }
/* Switching what the home screen shows: what changed rises, the bars stay */
.settling > :not(.testaments):not(.book-row) { animation: enter var(--t-page) var(--ease) backwards; }
.settling.all > .book-row { animation: fade var(--t-page) var(--ease) backwards; }
.settling > :nth-child(3) { animation-delay: .03s; }
.settling > :nth-child(4) { animation-delay: .07s; }
.settling > :nth-child(5) { animation-delay: .11s; }
.settling > :nth-child(n+6) { animation-delay: .15s; }
.section-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 16px; }
.testaments { position: relative; display: flex; gap: 32px; margin-bottom: 18px; padding-bottom: 4px; }
.testaments button {
  position: relative;
  color: var(--faint);
  letter-spacing: .14em;
  transition: color var(--t-state) var(--ease);
}
.testaments button::after { content: ""; position: absolute; inset: -12px -10px; }
.testaments button.on { color: var(--copper); }
.seg-ink {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--copper);
  transition: transform var(--t-move) var(--ease), width var(--t-move) var(--ease);
}

.book-row { display: flex; justify-content: space-between; align-items: center; width: 100%; min-height: 44px; margin-bottom: 6px; text-align: left; }
.book-name { font-size: 22px; letter-spacing: .08em; }

.picker { margin: 10px 0 22px; padding: 16px 0 2px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.picker-empty { margin: 6px 0 4px; color: var(--soft); }
.book-group { margin-bottom: 16px; }
.book-group .label { margin-bottom: 8px; }
/* Three across, every block the same size. The two seven-character names take two lines, so all are tall enough for that */
.book-chips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.book-chip {
  min-height: 54px;
  padding: 6px 2px;
  line-height: 1.3;
  border: 1px solid var(--rule);
  font-size: 15px;
  white-space: nowrap;
  transition: background var(--t-state) var(--ease), color var(--t-state) var(--ease), border-color var(--t-state) var(--ease), transform var(--t-press) var(--ease);
}
/* Below this width a four-character name no longer fits a quarter of the row at 15px */
@media (max-width: 340px) { .book-chip { font-size: 14px; } }
.book-chip.started { border-color: var(--copper); }
.book-chip.on { background: var(--copper); border-color: var(--copper); color: var(--paper); }

.chapters { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
/* A long book scrolls up and down only: the tap area of the buttons would otherwise let it slide sideways */
.chapters.long {
  max-height: 300px;
  max-height: clamp(150px, 100svh - 500px - var(--below, 0px), 300px);
  padding-bottom: 28px;
  overflow-x: hidden;
  overflow-y: auto;
  touch-action: pan-y;
  /* The fade says there is more, in place of a scrollbar; the padding lets the last row clear it */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
}
/* The system's scrollbar shows white on the paper */
.chapters.long, .verse-card, .missed-list { scrollbar-width: none; }
.chapters.long::-webkit-scrollbar, .verse-card::-webkit-scrollbar, .missed-list::-webkit-scrollbar { display: none; }
.chapter {
  position: relative;
  isolation: isolate;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--soft);
  transition: background var(--t-state) var(--ease), color var(--t-state) var(--ease), transform var(--t-press) var(--ease);
}
/* The cells are a little under 44px on phones; the tap area closes the gaps between them */
.chapter::before { content: ""; position: absolute; inset: -3px; }
/* The last column's tap area stays inside a long book's scrolling box, so nothing is left to slide sideways */
.chapters.long .chapter:nth-child(7n)::before { right: 0; }
.chapter.done { color: var(--ink); }
/* A finished chapter is filled with a light wash of copper, so how far a book has come shows at a glance */
.chapter.done::after {
  content: "";
  position: absolute;
  inset: 3px;
  z-index: -1;
  background: rgba(124, 64, 48, .08);
}
/* The mark of a chapter just finished appears after the page has settled */
.chapter.just::after { animation: mark-fill .7s var(--ease) .55s backwards; }
@keyframes mark-fill { from { opacity: 0; transform: scale(.4); } }
.chapter.next { box-shadow: inset 0 0 0 1px var(--copper); color: var(--copper); }
.chapter.on { background: var(--copper); color: var(--paper); }
.chapter.on.done::after { opacity: 0; }

.counts { display: flex; gap: 28px; }
.count { position: relative; color: var(--faint); padding-bottom: 3px; border-bottom: 1px solid transparent; transition: color var(--t-state) var(--ease), border-color var(--t-state) var(--ease); }
.count::after { content: ""; position: absolute; inset: -12px -12px; }
.count.on { color: var(--copper); border-bottom-color: var(--copper); }

.count-row { margin: 22px 0 16px; }
.panel-action { padding-top: 24px; }
.start { padding-top: 6px; }
.review {
  display: flex;
  justify-content: space-between;
  width: 100%;
  padding: 18px 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  margin-top: 28px;
  text-align: left;
}
.review span:last-child { color: var(--soft); }

.motto { margin-top: 44px; text-align: center; color: var(--faint); font-size: 13px; line-height: 1.9; letter-spacing: .06em; }
.motto .sync-link { display: inline-block; margin-bottom: 10px; color: var(--soft); font-size: 13px; letter-spacing: .06em; }
.motto .sync-link.nudge { color: var(--copper); }

.credit { font-size: 11px; letter-spacing: .08em; }

/* Question */
.topbar { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.progress { height: 1px; background: var(--rule); margin-bottom: 44px; }
.progress i { display: block; height: 1px; background: var(--copper); transition: width var(--t-page) var(--ease); }

.stem { font-size: var(--fs-verse); line-height: 1.75; min-height: 4.2em; margin-bottom: 26px; }
.blank {
  display: inline-block;
  min-width: 3em;
  height: 1.1em;
  margin: 0 .15em;
  border-bottom: 1px solid var(--ink);
  /* Level with the underline of the filled-in answer, so the line stays put when it appears */
  vertical-align: -.326em;
}
.blank-group { white-space: nowrap; }
/* Drawn as backgrounds so the line can grow, and continue across a line break. It sits where the blank's line was */
.filled {
  color: var(--copper);
  padding: 0 .1em 1px;
  background: linear-gradient(var(--copper), var(--copper)) left bottom / 100% 1px no-repeat;
}
/* The answer settles like ink, as a new copper line runs over the blank's old one */
.filled.settle {
  background-image: linear-gradient(var(--copper), var(--copper)), linear-gradient(var(--ink), var(--ink));
  background-size: 100% 1px, 100% 1px;
  background-position: left bottom, left bottom;
  background-repeat: no-repeat;
  animation: ink-word .7s var(--ease) backwards, ink-line .6s var(--ease) backwards;
}
@keyframes ink-word { from { color: transparent; text-shadow: 0 0 8px rgba(124, 64, 48, .55); } to { text-shadow: 0 0 0 rgba(124, 64, 48, 0); } }
@keyframes ink-line { from { background-size: 0 1px, 100% 1px; } }

.options { border-top: 1px solid var(--rule); }
.option {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 58px;
  padding: 12px 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--fs-option);
  line-height: 1.5;
  text-align: left;
  transition: color var(--t-state) var(--ease), background var(--t-state) var(--ease), opacity .2s var(--ease);
}
.option.gone { opacity: 0; }
.draw path { stroke-dasharray: 1; animation: draw .32s var(--ease) backwards; }
@keyframes draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.option:active { background: #f3ecdc; }
@media (hover: hover) {
  .option:hover:not(:disabled) { background: #f6f0e2; }
}
.option:disabled { cursor: default; color: var(--ink); }
/* Copper marks the answer in the text, so right and wrong are told by ink, grey and the marks */
.option.right { color: var(--ink); }
.option.wrong { color: var(--soft); }
.option.wrong span:first-child { text-decoration: line-through; text-decoration-thickness: 1px; }
.option svg { flex: none; width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.5; }

/* The verse is what the player should leave with */
.fresh { animation: enter var(--t-page) var(--ease) backwards; }
/* A new question: the options follow the stem one after another */
.choices.fresh { animation: none; }
.choices.fresh .option { animation: enter var(--t-page) var(--ease) backwards; animation-delay: .06s; }
.choices.fresh .option:nth-child(2) { animation-delay: .1s; }
.choices.fresh .option:nth-child(3) { animation-delay: .14s; }
.choices.fresh .option:nth-child(4) { animation-delay: .18s; }
.verse-card { flex: 0 1 auto; min-height: 0; margin-top: 24px; overflow-y: auto; overscroll-behavior: contain; }
.verse-card.settle { animation: enter var(--t-page) var(--ease) .2s backwards; }
.verse-card.settle .mark { animation: mark-in .8s var(--ease) .5s backwards; }
@keyframes mark-in { from { color: var(--ink); } }
.actions.settle { animation: fade var(--t-page) var(--ease) .34s backwards; }
.verse-card .ref { display: block; margin-bottom: 6px; color: var(--soft); font-size: var(--fs-small); letter-spacing: .08em; }
.verse-card p { line-height: 1.85; }
.mark { color: var(--copper); }
/* No name underlines on the answer screen or among the missed questions: a line under a word reads as a fill-in */
.verse-card .name, .missed .name { text-decoration: none; }
/* Proper names are underlined in the printed Chinese Union Version */
.name { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-skip-ink: none; }
.actions { flex: none; display: flex; flex-direction: column; gap: 18px; align-items: center; margin-top: auto; padding-top: 22px; }

/* The answer, score and card screens each fit one screen and never scroll */
html:has(body:is([data-screen="quiz"], [data-screen="result"], [data-screen="card"])) { height: 100%; overflow: hidden; overscroll-behavior: none; }
body:is([data-screen="quiz"], [data-screen="result"], [data-screen="card"]) { position: fixed; inset: 0; min-height: 0; overflow: hidden; overscroll-behavior: none; }
body:is([data-screen="quiz"], [data-screen="result"], [data-screen="card"]) #app { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
body[data-screen="quiz"] #app > * { flex: none; }
body[data-screen="quiz"] #app > .verse-card { flex: 0 1 auto; }
#app.compact { padding-top: calc(env(safe-area-inset-top) + 14px); padding-bottom: calc(env(safe-area-inset-bottom) + 14px); }
.compact .progress { margin-bottom: 14px; }
.compact .stem { min-height: 0; margin-bottom: 12px; font-size: 19px; line-height: 1.6; }
.compact .option { min-height: 46px; padding: 8px 0; font-size: 16px; }
.compact .verse-card { margin-top: 12px; font-size: 15px; }
.compact .verse-card p { line-height: 1.7; }
.compact .actions { gap: 10px; padding-top: 12px; }
.compact .actions .primary { padding: 11px; }

/* Short phones: tighten the space around the question so an answered screen still fits */
@media (max-height: 700px) {
  .progress { margin-bottom: 22px; }
  .stem { min-height: 0; margin-bottom: 18px; }
  .verse-card { margin-top: 16px; }
  .actions { padding-top: 16px; gap: 14px; }
}

/* A phone on its side: two columns. The options and their button keep the right, and the verse
   opens under the question on the left, taking all the height the question leaves */
@media (orientation: landscape) and (max-height: 500px) {
  body[data-screen="quiz"] #app {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto auto 1fr auto;
    column-gap: 32px;
    max-width: 720px;
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
  }
  .topbar, .progress { grid-column: 1 / -1; }
  .progress { margin-bottom: 14px; }
  .ask { grid-area: 3 / 1 / 4 / 2; }
  .choices { grid-area: 3 / 2 / 5 / 3; }
  body[data-screen="quiz"] #app > .verse-card { grid-area: 4 / 1 / 6 / 2; margin-top: 0; }
  .actions { grid-area: 5 / 2 / 6 / 3; }
}

/* Chapter reading. The page opens scrolled to the verse, so the way back must stay in view */
.back-bar {
  position: sticky;
  top: 0;
  z-index: 1;  /* The verses below fade in on their own layer and would otherwise paint over the bar */
  margin: 0 -24px;
  padding: calc(env(safe-area-inset-top) + 14px) 24px 14px;
  background: var(--paper) var(--grain);
  border-bottom: 1px solid var(--rule);
}
body[data-screen="chapter"] #app, body[data-screen="reading"] #app, body[data-screen="quit"] #app, body[data-screen^="sync"] #app { padding-top: 0; }
.bar-title {
  position: absolute;
  left: 50%;
  bottom: 14px;
  transform: translate(-50%, 4px);
  max-width: 52%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--ink);
  font-size: var(--fs-small);
  letter-spacing: .08em;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-move) var(--ease), transform var(--t-move) var(--ease);
}
.bar-title.shown { opacity: 1; transform: translate(-50%, 0); }
.read h2, .read p { scroll-margin-top: 70px; }
.read-title { font-size: 24px; letter-spacing: .08em; margin: 26px 0 26px; }
.read { font-size: var(--fs-read, var(--fs-body)); }
.read h2 { margin: 30px 0 12px; font-size: .94em; font-weight: 500; color: var(--soft); letter-spacing: .14em; }
.read p { margin-bottom: 12px; line-height: 1.95; }
.read .book-part { margin-bottom: 0; color: var(--soft); letter-spacing: .3em; text-align: center; }
.read .psalm-title { font-size: .94em; line-height: 1.8; color: var(--soft); }
.read .note { font-size: .94em; color: var(--soft); }
.read-end { display: flex; flex-direction: column; gap: 12px; margin-top: 34px; padding-top: 24px; border-top: 1px solid var(--rule); }
.read-row { display: flex; gap: 10px; }
/* The text size: a small and a large character */
.back-bar .size { display: flex; align-items: baseline; gap: 22px; }
.size-down { font-size: 13px; }
.size-up { font-size: 19px; line-height: 1; }
.size .link:disabled { color: var(--off); }
.read-row .secondary { flex: 1; min-width: 0; }
.read-row .secondary:active:not(:disabled) { border-color: var(--ink); }
.read .num { margin-right: .4em; font-size: .81em; color: var(--faint); }
.read .here { margin: 0 -10px 12px; padding: 4px 10px; background: rgba(124, 64, 48, .1); }
.read .here .num { color: var(--soft); }

/* The New Testament route */
.route-title { margin: 0 0 12px; }
.route-note { line-height: 1.8; }
.route-note.soft { margin-top: 4px; color: var(--soft); font-size: var(--fs-small); }
.card-art svg { display: block; width: 100%; height: auto; background: rgba(124, 64, 48, .05); }
.card-art .l { fill: none; stroke: var(--copper); stroke-width: 1.1; stroke-linecap: round; stroke-linejoin: round; }
.card-art .f { fill: var(--copper); }
.card-art .t { fill: rgba(124, 64, 48, .16); }
.card-art .p { fill: var(--paper); }
.card-art .h { fill: none; stroke: rgba(124, 64, 48, .4); stroke-width: .8; stroke-linecap: round; }
/* One shape for every card: 4:5 on every phone. Sizes inside follow the card's width, so all twelve keep one layout.
   The stage is the room left on the screen, and the card is as large as fits it. It reaches past the page's
   margins, so narrow phones do not make the words too small */
:root { --card-w: 340px; }
.card-stage {
  --card-w: min(100cqw, 80cqh, 340px);
  container-type: size;
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 -12px;
}
.card {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  width: var(--card-w);
  aspect-ratio: 4 / 5;
  flex: none;
  padding: calc(var(--card-w) * .035) calc(var(--card-w) * .035) calc(var(--card-w) * .04);
  border: 1px solid var(--rule);
  background: var(--paper);
  box-shadow: 0 8px 22px rgba(31, 29, 27, .09);
}
.card h2 { flex: none; margin: 0 2cqw 4.6cqw; padding-top: 3.6cqw; font-size: 8.6cqw; font-weight: 500; line-height: 1.25; letter-spacing: .1em; }
.card p { flex: 1; min-height: 0; margin: 0 2cqw; font-size: 4.9cqw; line-height: 1.7; text-indent: -.45em; text-wrap: pretty; }
.card .ref { flex: none; margin: 1.6cqw 2cqw 0; color: var(--soft); font-size: 3.7cqw; letter-spacing: .1em; }
.arrival-label { flex: none; padding: 6px 0 14px; text-align: center; color: var(--soft); font-size: var(--fs-small); letter-spacing: .14em; }
.arriving { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.card-actions { flex: none; width: min(100%, 340px); margin: 18px auto 0; }
/* The card screen: the card and the two buttons under it sit together in the middle of the room left */
body[data-screen="card"] #app > .card-stage { flex: 0 1 425px; margin-top: auto; }
.card-nav { flex: none; display: flex; gap: 10px; width: min(100%, 340px); margin: 20px auto auto; }
.card-nav .secondary { flex: 1; }
body[data-screen="card"] .topbar { flex: none; }
.card.turn { animation: enter var(--t-page) var(--ease) backwards; }
.entering .card.turn { animation: none; }
/* Arriving at a stop: the card is laid down, the scene drawn (in app.js), and the words appear.
   The whole sequence is about two seconds; one tap finishes it */
.arrival-label { animation: fade .6s var(--ease) backwards; }
.arriving .card { animation: enter .6s var(--ease) backwards; }
.arriving .card h2 { animation: fade .6s var(--ease) 1.25s backwards; }
.arriving .card p { animation: enter .6s var(--ease) 1.4s backwards; }
.arriving .card .ref { animation: fade .6s var(--ease) 1.6s backwards; }
.arriving .card-actions { animation: fade .5s var(--ease) 1.8s backwards; }
.arriving.playing .card-actions { pointer-events: none; }
.route-map { margin-top: 20px; }
.route-map svg { display: block; width: 100%; height: auto; border: 1px solid var(--rule); background: var(--paper); }
.route-map .sea { fill: rgba(124, 64, 48, .1); stroke: rgba(124, 64, 48, .4); stroke-width: .7; stroke-linejoin: round; }
.route-map .land { fill: var(--paper); stroke: rgba(124, 64, 48, .4); stroke-width: .7; stroke-linejoin: round; }
.route-map .walked { fill: none; stroke: var(--copper); stroke-width: 1.6; stroke-linecap: round; }
.route-map .ahead { fill: none; stroke: var(--faint); stroke-width: 1; stroke-dasharray: 3 4; stroke-linecap: round; }
.route-map .hit { fill: transparent; }
.route-map .dot { transform-box: fill-box; transform-origin: center; }
/* A slow ring at the stop you have reached */
.route-map .halo { fill: var(--copper); opacity: 0; pointer-events: none; transform-box: fill-box; transform-origin: center; animation: halo 3.4s ease-out infinite; }
@keyframes halo { from { opacity: .28; transform: scale(1); } 70%, to { opacity: 0; transform: scale(2.3); } }
.route-map .dot { fill: var(--paper); stroke: var(--faint); stroke-width: 1; }
.route-map .num { fill: var(--faint); font-size: 11px; text-anchor: middle; }
.route-map .place { fill: var(--faint); font-size: 14.5px; }
.route-map .reached { cursor: pointer; }
.route-map .reached .dot { fill: var(--copper); stroke: var(--copper); }
.route-map .reached .num { fill: var(--paper); }
.route-map .reached .place { fill: var(--ink); }
.route-map .next .dot { stroke: var(--copper); stroke-width: 1.4; }
.route-map .next .num, .route-map .next .place { fill: var(--copper); }
.stops { margin-top: 18px; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.stop-row { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 56px; padding: 8px 0; border-bottom: 1px solid var(--rule); text-align: left; }
.stop-num { flex: none; width: 1.6em; color: var(--soft); font-size: var(--fs-small); }
.stop-name { flex: 1; letter-spacing: .08em; }
.stop-row .card-art { flex: none; width: 76px; }
.stop-row .card-art svg { box-shadow: 0 0 0 1px var(--rule); }
.stop-row.locked .stop-num, .stop-row.locked .stop-name { color: var(--faint); }
.stop-need { flex: none; color: var(--faint); font-size: var(--fs-small); }
/* The Old Testament line */
.timeline { position: relative; margin-top: 18px; padding: 0; list-style: none; }
.t-rail { position: absolute; left: 8px; width: 1px; background: var(--rule); }
.t-on { position: absolute; top: 0; left: 0; width: 1px; background: var(--copper); }
.t-node { position: relative; padding-left: 32px; }
.t-dot { position: absolute; top: 50%; border: 1px solid var(--faint); border-radius: 50%; background: var(--paper); }
.small .t-dot { left: 5.5px; width: 6px; height: 6px; margin-top: -3px; }
.big .t-dot { left: 2.5px; width: 12px; height: 12px; margin-top: -6px; }
.reached .t-dot { border-color: var(--copper); background: var(--copper); }
.current .t-dot::after { content: ""; position: absolute; inset: -1px; border-radius: 50%; background: var(--copper); opacity: 0; animation: halo 3.4s ease-out var(--halo-delay, 0s) infinite; }
.small { display: flex; align-items: center; min-height: 34px; }
.t-name { letter-spacing: .08em; }
.small .t-name { color: var(--faint); font-size: 14px; }
.small.reached .t-name { color: var(--soft); }
.t-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%; min-height: 62px; padding: 6px 0; text-align: left; }
.big .t-name { color: var(--faint); font-size: 20px; }
.big.reached .t-name { color: var(--ink); }
.t-row .card-art { flex: none; width: 76px; }
.t-row .card-art svg { box-shadow: 0 0 0 1px var(--rule); }
button.t-row { transition: opacity var(--t-press) var(--ease); }
button.t-row:active { opacity: .6; }
.sync-row { display: flex; gap: 10px; margin-top: 12px; }
.route-note + .sync-row { margin-top: 20px; }
.sync-row > button { flex: 1; min-width: 0; padding: 13px 6px; letter-spacing: .12em; text-indent: .12em; }
.sync-state { display: flex; justify-content: space-between; margin-top: 20px; color: var(--ink); font-size: var(--fs-small); }
.sync-state .sync-status { color: var(--soft); }
.sync-message { margin-top: 10px; color: var(--copper); }
.sync-message.centred { margin-top: 14px; text-align: center; }
.sync-code { margin: 8px 0 18px; font-size: 26px; letter-spacing: .12em; user-select: all; -webkit-user-select: all; }
.sync-input { display: block; width: 100%; padding: 12px 14px; border: 1px solid var(--rule); border-radius: 0; background: var(--paper);
  color: var(--ink); font: inherit; font-size: 20px; letter-spacing: .12em; text-transform: uppercase; }
.sync-input:focus { outline: none; border-color: var(--copper); }
.sync-buttons { display: flex; flex-direction: column; gap: 12px; margin-top: 20px; }
.sync-found { line-height: 1.9; }
.sync-choice { text-align: left; text-indent: 0; letter-spacing: .04em; padding: 14px 16px; }
.sync-choice b { display: block; font-weight: 500; }
.sync-choice.danger b { color: var(--copper); }
.sync-choice span { display: block; margin-top: 4px; color: var(--soft); font-size: var(--fs-small); }

/* Result */
.score { flex: none; padding: 56px 0 8px; text-align: center; }
.score b { font-size: var(--fs-score); font-weight: 500; line-height: 1.1; }
.score span { font-size: 24px; color: var(--soft); margin-left: .2em; }
.score b { display: inline-block; text-align: right; }
/* The share answered right, running out as the number counts up */
.score-line { flex: none; width: 120px; height: 1px; margin: 10px auto 16px; background: var(--rule); }
.score-line i { display: block; height: 1px; background: var(--copper); transform-origin: left; animation: grow .9s var(--ease) .25s backwards; }
.score-note { flex: none; text-align: center; color: var(--soft); margin-bottom: 26px; letter-spacing: .04em; }
/* A small node reached: the line runs on from the last node after the score has counted up, the new node
   lights and pulses twice, then the sentence comes in */
.step { flex: none; width: 216px; margin: -4px auto 0; }
.step-line { position: relative; display: flex; justify-content: space-between; }
.step-track { position: absolute; left: 32px; right: 32px; top: 4px; height: 1px; background: var(--rule); }
.step-track i { display: block; height: 1px; background: var(--copper); transform-origin: left; animation: grow .6s linear 1.1s backwards; }
.step-from, .step-to { position: relative; width: 64px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.step-dot { position: relative; width: 9px; height: 9px; border: 1px solid var(--copper); border-radius: 50%; background: var(--copper); }
.step-from .step-dot { margin-top: 1px; width: 7px; height: 7px; }
.step-to .step-dot { animation: step-light .4s var(--ease) 1.7s backwards; }
.step-to .step-dot::after { content: ""; position: absolute; inset: -1px; border-radius: 50%; background: var(--copper); opacity: 0; animation: halo 2.2s ease-out 1.7s 2; }
@keyframes step-light { from { background: var(--paper); border-color: var(--faint); transform: scale(.75); } }
.step-name { color: var(--faint); font-size: var(--fs-small); letter-spacing: .06em; white-space: nowrap; }
.step-to .step-name { color: var(--ink); animation: fade .5s var(--ease) 1.7s backwards; }
.step .score-note.passed { margin: 14px 0 26px; color: var(--copper); animation: enter .5s var(--ease) 2s backwards; }
.missed-list {
  flex: 0 1 auto;
  min-height: 0;
  padding-bottom: 20px;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  /* The fade says there is more, in place of a scrollbar */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 20px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 20px), transparent);
}
.missed { border-top: 1px solid var(--rule); padding: 16px 0; }
.missed .ref { display: block; margin-bottom: 4px; color: var(--soft); font-size: var(--fs-small); letter-spacing: .08em; }
.missed p { line-height: 1.85; }
.missed-title { margin-bottom: 14px; }
.result-actions { flex: none; display: flex; flex-direction: column; align-items: center; gap: 12px; margin-top: auto; padding-top: 16px; border-top: 1px solid var(--rule); }
.result-actions button:not(.link) { width: 100%; }
.result-actions .link { margin-top: 4px; }

/* Short phones: tighter around the score and the card */
@media (max-height: 700px) {
  .score { padding-top: 8px; }
  .score b { font-size: 60px; }
  .score-note { margin-bottom: 14px; }
  .step .score-note.passed { margin: 10px 0 14px; }
  body:is([data-screen="result"], [data-screen="card"]) #app { padding-top: calc(env(safe-area-inset-top) + 14px); padding-bottom: calc(env(safe-area-inset-bottom) + 16px); }
  .result-actions { gap: 8px; }
  .result-actions .primary, .result-actions .secondary { padding: 11px; }
}

/* A phone on its side: two columns, the card or the score on the left */
@media (orientation: landscape) and (max-height: 500px) {
  body:is([data-screen="result"], [data-screen="card"]) #app { max-width: 720px; padding-left: max(24px, env(safe-area-inset-left)); padding-right: max(24px, env(safe-area-inset-right)); }
  .arriving { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr auto auto 1fr; column-gap: 32px; }
  .arriving .card-stage { grid-area: 1 / 1 / 5 / 2; }
  .arrival-label { grid-area: 2 / 2; }
  .arriving .card-actions { grid-area: 3 / 2; margin-top: 0; }
  body[data-screen="card"] #app:not(:has(.arriving)) { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto 1fr auto 1fr; column-gap: 32px; }
  body[data-screen="card"] .topbar { grid-area: 1 / 2; }
  body[data-screen="card"] #app > .card-stage { grid-area: 1 / 1 / 5 / 2; margin-top: 0; }
  body[data-screen="card"] .card-nav { grid-area: 3 / 2; margin: 0; }
  body[data-screen="result"] #app { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto auto auto 1fr auto; column-gap: 32px; }
  .score, .score-line, .score-note, .step { grid-column: 1; }
  .missed-list { grid-area: 1 / 2 / 6 / 3; }
  .result-actions { grid-area: 6 / 1 / 7 / 3; flex-direction: row; margin-top: 8px; padding-top: 10px; }
  .result-actions button:not(.link) { flex: 1; }
  .result-actions .link { flex: none; margin: 0 8px; }
}
