/* translations.codebycarson.com — generic viewer shell */

:root, :root[data-theme="dark"] {
  --bg: #181a1b;
  --surface: #1e2021;
  --border: #3c4143;
  --text: #e8e6e3;
  --muted: #a7a096;
  --accent: #8eb4f1;
  --accent-hover: #b1cbf5;
  --note: #cfc9bf;
  --paper: #111;
  --rd-line: rgba(142, 180, 241, 0.55);
  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg: #f6f4ef;
  --surface: #fffdf8;
  --border: #d9d4c8;
  --text: #1f1f1f;
  --muted: #6b665e;
  --accent: #2f5fb3;
  --accent-hover: #1e4a94;
  --note: #4a4640;
  --paper: #e9e5dc;
  --rd-line: rgba(47, 95, 179, 0.5);
  color-scheme: light;
}

:root {
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --bar-h: 3rem;   /* both re-measured from the real elements in app.js, so */
  --foot-h: 3rem;  /* a header that wraps on a narrow screen still adds up */
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
}

a { color: var(--accent); }
a:hover { color: var(--accent-hover); }

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

.bar {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.9rem;
  min-height: var(--bar-h);
  padding: 0.35rem 0.9rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  min-width: 0;
  white-space: nowrap;
}

.home { text-decoration: none; }
.home:hover { text-decoration: underline; }

.sep { color: var(--muted); }

.book-title {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 14ch;
}

.pager {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.jump { margin: 0; }

.meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.75rem;
  min-width: 0;
  color: var(--muted);
  font-size: 0.85rem;
}

.pageno { color: var(--text); white-space: nowrap; }
.folio { white-space: nowrap; font-style: italic; }
.src { white-space: nowrap; }
.src:empty { display: none; }

.controls {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-left: auto;
}

.layers { display: flex; gap: 0.25rem; }

/* ---------- buttons and the jump input ---------- */

.bar button,
.jump input {
  font: inherit;
  font-size: 0.85rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.2rem 0.55rem;
}

.bar button { cursor: pointer; }
.bar button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.bar button:disabled { color: var(--muted); border-color: var(--border); cursor: not-allowed; }

.layers button[aria-selected="true"] {
  color: var(--accent);
  border-color: var(--accent);
}

.theme { line-height: 1; min-width: 2rem; }

/* Only shown when embedded (see the embed section at the end). */
.full { display: none; }

/* On/off, like a layer tab: lit while the readings are shown. */
.readings-toggle[aria-pressed="true"]:not(:disabled) {
  color: var(--accent);
  border-color: var(--accent);
}

.jump input {
  width: 6rem;
  min-width: 0;
}
.jump input:focus-visible,
.bar button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.jump input.bad {
  border-color: #c0392b;
  animation: shake 0.3s ease;
}

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  40% { transform: translateX(4px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(3px); }
}

/* ---------- stage ---------- */

.stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.image-panel {
  background: var(--paper);
  min-width: 0;
}

/* The scan sits in a frame of its own: at rest it is fitted to the frame, and
   zoomed it is an oversized image panned inside it. */
.frame {
  position: relative;
  overflow: hidden;
  background: var(--paper);
  cursor: zoom-in;
}
.frame.empty { cursor: default; }
.frame:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.text-panel {
  padding: 1.5rem;
  font-family: var(--serif);
  font-size: 1.05rem;
  line-height: 1.55;
  min-width: 0;
  /* The sidenote layout keys off the panel's own width, not the window's:
     the panel is only half the window once the two panels sit side by side. */
  container-type: inline-size;
}

/* 62ch of text + 18rem of notes + the gap, centred on a very wide panel. */
.text-inner {
  max-width: 104ch;
  margin: 0 auto;
}

img.scan {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 auto;
  opacity: 0;
  transition: opacity 0.25s ease;
  user-select: none;
  -webkit-user-drag: none;
}
img.scan.loaded { opacity: 1; }

/* Zoomed: 1:1 in device pixels (JS sets the px size), panned by transform. */
.image-panel.zoomed .frame {
  display: block;
  cursor: grab;
  touch-action: none;
}
.image-panel.zoomed .frame.dragging { cursor: grabbing; }
.image-panel.zoomed img.scan {
  position: absolute;
  top: 0;
  left: 0;
  margin: 0;
  max-width: none;
  max-height: none;
  transform-origin: 0 0;
  will-change: transform;
}

.img-missing,
.pending,
.error {
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.9rem;
}
/* The image panel has no padding of its own; the text panel has. */
.img-missing { padding: 1.5rem; }
.pending, .error { margin: 0; }

.img-missing a { white-space: normal; word-break: break-word; }

.blk-heading {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin: 1.5rem 0 0.6rem;
}
.blk-heading:first-child { margin-top: 0; }
/* A title page is a stack of display lines, not a run of headings: margins
   collapse to the larger of the two, so both sides have to come down. */
.blk-heading + .blk-heading { margin-top: 0.25rem; }
.blk-heading:has(+ .blk-heading) { margin-bottom: 0.25rem; }
.blk-heading.spaced { letter-spacing: 0.12em; }

.blk-ornament {
  margin: 1.2rem 0;
  text-align: center;
  color: var(--note);
  letter-spacing: 0.08em;
}
.blk-blank { height: 1rem; }
.blk { margin: 0 0 1.1rem; }

/* ---------- paragraphs ---------- */

.para { margin: 0 0 1.3rem; }
.para .body,
.para .lines { margin: 0; }

/* One printed line per row. A line too long for the column wraps with a
   hanging indent, so the printed lineation is still readable. */
.lines .ln {
  display: block;
  font-size: 0.98rem;
  hyphens: none;
  white-space: normal;
  padding-left: 1.2em;
  text-indent: -1.2em;
}

.cont {
  color: var(--muted);
  margin-right: 0.3em;
  cursor: default;
}

/* An uncertain reading is underlined where the doubt is about the words: a
   printed line, or a note. */
.ln.uncertain,
.note.uncertain {
  text-decoration: underline dotted;
  text-decoration-color: var(--muted);
  text-underline-offset: 0.25em;
  cursor: help;
}

/* A whole block is flagged when the doubt is about the printing rather than
   the reading — letterspacing, show-through, a broken sort. Underlining every
   word of it would put a title page almost entirely under dots, so it gets a
   change bar out in the margin instead; the note is in the tooltip. */
.para.uncertain,
.blk-heading.uncertain,
.blk-ornament.uncertain,
.blk.uncertain {
  border-left: 1px dotted var(--muted);
  margin-left: -0.6rem;
  padding-left: 0.6rem;
  cursor: help;
}

/* ---------- contested readings ---------- */

/* Words the two transcription passes read differently. The text keeps its own
   typography; only a faint dotted rule, in the accent rather than the muted
   grey of an uncertain line, says there is an apparatus behind it. */
.rd {
  text-decoration: underline dotted;
  text-decoration-color: var(--rd-line);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  text-decoration-skip-ink: none;
  cursor: help;
  border-radius: 2px;
}
.rd:hover,
.rd[aria-expanded="true"] { text-decoration-color: var(--accent); }
.rd:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.rd-pop {
  position: fixed;
  z-index: 30;
  max-width: min(26rem, calc(100vw - 16px));
  padding: 0.55rem 0.7rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);
  font-family: var(--sans);
  font-size: 0.8rem;
  line-height: 1.4;
}
.rd-pop[hidden] { display: none; }

.rd-entry + .rd-entry {
  margin-top: 0.55rem;
  padding-top: 0.55rem;
  border-top: 1px solid var(--border);
}
.rd-row {
  display: grid;
  grid-template-columns: 6.2rem minmax(0, 1fr);
  gap: 0 0.6rem;
}
.rd-k { color: var(--muted); }
.rd-v { overflow-wrap: anywhere; }
.rd-v.fr { font-family: var(--serif); font-size: 0.95rem; }
.rd-v.none { color: var(--muted); font-style: italic; }
.rd-why {
  margin: 0.35rem 0 0;
  color: var(--note);
  overflow-wrap: anywhere;
}

/* The page's apparatus criticus: every contested reading, folded away. */
.apparatus {
  margin: 1.6rem 0 0;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
  font-family: var(--sans);
  font-size: 0.82rem;
  max-width: 62ch;
}
.apparatus summary {
  cursor: pointer;
  color: var(--muted);
  width: max-content;
}
.apparatus summary:hover { color: var(--accent); }
.apparatus summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.app-list {
  margin: 0.7rem 0 0;
  padding-left: 1.6rem;
}
.app-list li { margin: 0 0 0.8rem; color: var(--muted); }
.app-list li::marker { color: var(--muted); }
.app-list .rd-entry { color: var(--text); }
.app-where {
  display: inline-block;
  margin-bottom: 0.15rem;
  color: var(--muted);
  font: inherit;
  font-style: italic;
  background: none;
  border: 0;
  padding: 0;
}
button.app-where {
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
}
button.app-where:hover { color: var(--accent-hover); }
button.app-where:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ---------- about ---------- */

.about-open {
  font: inherit;
  color: var(--accent);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.about-open:hover { color: var(--accent-hover); text-decoration: underline; }
.about-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

dialog.about {
  max-width: min(36rem, calc(100vw - 32px));
  padding: 1.2rem 1.4rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.92rem;
  line-height: 1.55;
}
dialog.about::backdrop { background: rgba(0, 0, 0, 0.45); }
dialog.about h2 {
  margin: 0 2rem 0.6rem 0;
  font-family: var(--serif);
  font-size: 1.1rem;
  font-weight: 600;
}
dialog.about p { margin: 0 0 0.75rem; }
dialog.about p:last-child { margin-bottom: 0; }
.about-close {
  position: absolute;
  top: 0.5rem;
  right: 0.6rem;
  font: inherit;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--muted);
  background: none;
  border: 0;
  cursor: pointer;
}
.about-close:hover { color: var(--accent); }

/* ---------- markers and notes ---------- */

.mk {
  color: var(--accent);
  font-size: 0.7em;
  padding: 0 0.15em;
  cursor: pointer;
  vertical-align: super;
  line-height: 0;
}
.mk:hover, .mk.hl { color: var(--accent-hover); text-decoration: underline; }
.mk:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.notes { display: none; }

.note {
  display: grid;
  grid-template-columns: 1.15em minmax(0, 1fr);
  gap: 0 0.35em;
  margin: 0 0 0.9rem;
  padding-left: 0.5rem;
  border-left: 2px solid transparent;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--note);
}
.note:last-child { margin-bottom: 0; }
.note .nk {
  grid-column: 1;
  font-weight: 700;
  color: var(--muted);
  vertical-align: baseline;
  font-size: 0.9em;
  line-height: inherit;
}
.note > :not(.nk) { grid-column: 2; }
.note .cite, .note .orig, .note .gloss, .note .ntext { display: block; }
.note .orig { font-style: italic; color: var(--muted); }
.note .gloss { margin-top: 0.2rem; }
.note.foot .ntext { font-style: italic; }
.note.hl {
  border-left-color: var(--accent);
  color: var(--text);
}
.note.hl .nk { color: var(--accent); }

/* Narrow: the notes are folded away until a marker is tapped. */
.para.open .notes {
  display: block;
  margin-top: 0.8rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
}

/* Wide enough for a margin of its own: notes beside their own paragraph. */
@container (min-width: 38rem) {
  .para.has-notes {
    display: grid;
    grid-template-columns: minmax(0, 62ch) 18rem;
    gap: 1.5rem;
    align-items: start;
  }
  /* The printed French marginalia are narrow, hard-wrapped abbreviations, so
     they take a slimmer column; that is what keeps a diplomatic line from
     re-wrapping in a panel only half the window wide. English citations run
     to a sentence and keep the full 18rem. */
  .layer-fr .para.has-notes { grid-template-columns: minmax(0, 62ch) 13rem; }
  .notes { display: block; }
  .para.open .notes {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }
}


@media (min-width: 900px) {
  .stage {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    height: calc(100dvh - var(--bar-h) - var(--foot-h));
  }
  /* The whole page is visible at once; nothing scrolls inside the image
     panel, at rest or zoomed (zoomed, the frame pans instead). */
  .image-panel { overflow: hidden; }
  .text-panel { overflow: auto; border-left: 1px solid var(--border); }
  .frame {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  img.scan {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
  }
}

/* Stacked: the scan is capped so the text panel starts on the first screen;
   the image letterboxes inside its frame (zoomIn freezes the frame's height). */
@media (max-width: 899.98px) {
  .frame {
    height: clamp(240px, 52dvh, 560px);
    display: flex;
    align-items: center;
    justify-content: center;
  }
  img.scan {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
  }
}

@media (max-width: 700px) {
  .bar { gap: 0.4rem 0.7rem; padding: 0.4rem 0.7rem; }
  .controls { margin-left: 0; }
  .book-title { max-width: 10ch; }
  .jump input { width: 4.5rem; }
  .text-panel { padding: 1.1rem; }
}

/* ---------- cited sources ---------- */

/* A note whose citation has stored text: a small "source" button under it,
   and a link out where only a page scan exists. */
.note .src-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.7rem;
  margin-top: 0.25rem;
  font-family: var(--sans);
  font-size: 0.75rem;
}
.src-open {
  font: inherit;
  color: var(--accent);
  background: none;
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 0 0.4rem;
  cursor: pointer;
  line-height: 1.5;
}
.src-open::before { content: "§ "; color: var(--muted); }
.src-open:hover,
.src-open[aria-expanded="true"] { border-color: var(--accent); color: var(--accent-hover); }
.src-open:focus-visible,
.src-scan:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.src-scan { text-decoration: none; line-height: 1.6; }
.src-scan:hover { text-decoration: underline; }

/* The pane: a third column on a wide screen, a bottom sheet below that. Its
   header stays put; only the passages scroll. */
.source-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--sans);
}
.source-pane[hidden] { display: none; }
.source-pane:focus { outline: none; }

.sp-head {
  position: relative;
  flex: none;
  max-height: 45%;
  overflow: auto;
  padding: 0.8rem 2.6rem 0.7rem 1rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.8rem;
  line-height: 1.4;
}
.sp-close {
  position: absolute;
  top: 0.45rem;
  right: 0.55rem;
  font: inherit;
  font-size: 1.35rem;
  line-height: 1;
  padding: 0.1rem 0.35rem;
  color: var(--muted);
  background: none;
  border: 0;
  border-radius: 4px;
  cursor: pointer;
}
.sp-close:hover { color: var(--accent); }
.sp-close:focus-visible { outline: 2px solid var(--accent); }
.sp-meta p { margin: 0 0 0.3rem; overflow-wrap: anywhere; }
.sp-meta p:last-child { margin-bottom: 0; }
.sp-corpus { color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.72rem; }
.sp-title {
  margin: 0 0 0.35rem;
  font-family: var(--serif);
  font-size: 1.02rem;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.sp-ref { color: var(--note); }
.sp-credit { color: var(--muted); font-size: 0.74rem; }

.sp-cites {
  margin: 0 0 0.6rem;
  padding: 0 0 0.55rem;
  list-style: none;
  border-bottom: 1px dotted var(--border);
}
.sp-cites li + li { margin-top: 0.15rem; }
.sp-cite {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--accent);
  background: none;
  border: 0;
  border-left: 2px solid transparent;
  padding: 0.1rem 0 0.1rem 0.45rem;
  cursor: pointer;
  overflow-wrap: anywhere;
}
.sp-cite.no-text { color: var(--muted); }
.sp-cite:hover { color: var(--accent-hover); }
.sp-cite[aria-current="true"] { color: var(--text); border-left-color: var(--accent); }
.sp-cite:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.sp-body {
  position: relative;  /* passages' offsetTop is measured from here */
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: 0.6rem 1rem 1.2rem;
}
.sp-msg { margin: 0.4rem 0; color: var(--muted); font-size: 0.85rem; }
.sp-passage {
  margin: 0 -0.5rem 0.4rem;
  padding: 0.35rem 0.5rem;
  border-left: 2px solid transparent;
  border-radius: 0 3px 3px 0;
}
.sp-passage.hit {
  border-left-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.sp-label {
  margin: 0 0 0.15rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--muted);
}
.sp-passage.hit .sp-label { color: var(--accent); }
.sp-passage p {
  margin: 0 0 0.45rem;
  font-family: var(--serif);
  font-size: 0.95rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.sp-passage p:last-child { margin-bottom: 0; }

/* Side by side, the pane must not squeeze the text panel under the 38rem its
   sidenotes need (the container query above), or the note that opened it
   folds away. So from 1280px it is a third column and the text keeps 43rem
   (38rem + padding + a scrollbar); between 900 and 1280 it covers the scan instead. */
@media (min-width: 900px) {
  .source-pane { border-left: 1px solid var(--border); height: 100%; }
  /* Explicit cells, or the placed pane pushes the auto-placed panels into a
     second row. */
  .stage.with-source .image-panel { grid-column: 1; grid-row: 1; }
  .stage.with-source .text-panel { grid-column: 2; grid-row: 1; }
  .stage.with-source .source-pane {
    grid-column: 1;
    grid-row: 1;
    z-index: 2;
    border-left: 0;
    border-right: 1px solid var(--border);
  }
}
@media (min-width: 1280px) {
  .stage.with-source {
    grid-template-columns: minmax(0, 1fr) minmax(43rem, 1.25fr) minmax(18rem, 26rem);
  }
  .stage.with-source .source-pane {
    grid-column: 3;
    border-right: 0;
    border-left: 1px solid var(--border);
  }
}

@media (max-width: 899.98px) {
  .source-pane {
    position: fixed;
    z-index: 20;
    left: 0;
    right: 0;
    bottom: 0;
    height: min(65dvh, 34rem);
    border-top: 1px solid var(--border);
    border-radius: 10px 10px 0 0;
    box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.3);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
}

/* ---------- footer ---------- */

.foot {
  padding: 1rem;
  padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  text-align: center;
  font-size: 0.8rem;
  color: var(--muted);
  border-top: 1px solid var(--border);
}

/* ---------- embed (?embed=1) ---------- */

/* Inside the blog's iframe the frame is the viewport: the body is a column the
   height of the frame, the stage takes whatever the header leaves, and only
   the text panel scrolls — the document itself never does. The site link and
   the footer go; navigation, jump box, layer and theme stay, plus a link out
   to the full viewer. */
html.embed,
html.embed body {
  height: 100%;
  overflow: hidden;
}
html.embed body {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}
.embed .bar {
  position: static;
  flex: none;
}
.embed .home,
.embed .sep,
.embed .foot { display: none; }
/* The extra link would otherwise run off the edge of a phone-width frame. */
.embed .controls { flex-wrap: wrap; row-gap: 0.4rem; }
.embed .full {
  display: inline;
  font-size: 0.85rem;
  white-space: nowrap;
  text-decoration: none;
}
.embed .full:hover { text-decoration: underline; }
.embed .stage {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
}
.embed .image-panel { overflow: hidden; min-height: 0; }
.embed .text-panel { overflow: auto; min-height: 0; }
.embed .frame {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.embed img.scan {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}

/* Stacked (a blog column is ~760px): the scan gets just over half the frame,
   so the start of the text is on screen without scrolling. */
@media (max-width: 899.98px) {
  .embed .stage { grid-template-rows: minmax(0, 55fr) minmax(0, 45fr); }
  .embed .text-panel { border-top: 1px solid var(--border); }
}
