/* ═══════════════════════════════════════════════════════════════════════════
   LUITOR XUR — the vellum
   ───────────────────────────────────────────────────────────────────────────
   One page of a notebook: rag paper, iron-gall ink, red chalk, a little gold.
   Nothing on it is a rectangle with a shadow. Everything is drawn.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --vellum: #e9dcc0;
  --vellum-lit: #f2e8d3;
  --vellum-deep: #d9c9a4;
  --vellum-shade: #c9b68d;

  --ink: #241a0f;
  --ink-soft: #4c3a25;
  --ink-thin: rgba(36, 26, 15, 0.72);
  --ink-faint: rgba(36, 26, 15, 0.42);
  --ink-ghost: rgba(36, 26, 15, 0.18);

  --sanguine: #94371c;
  --sanguine-thin: rgba(148, 55, 28, 0.6);
  --gold: #9a7523;
  --gold-thin: rgba(154, 117, 35, 0.55);

  --serif-display: 'Cormorant Garamond', 'Iowan Old Style', Georgia, serif;
  --serif-text: 'EB Garamond', Georgia, 'Times New Roman', serif;
  --serif-as: 'Noto Serif Bengali', 'Cormorant Garamond', Georgia, serif;

  --rule: 1px solid var(--ink-faint);

  /* φ. The page is laid out on it, so it may as well be a number here. */
  --phi: 1.618;

  color-scheme: light;
}

/* Candlelight. Not an inversion — the same page, later at night. */
@media (prefers-color-scheme: dark) {
  :root {
    --vellum: #241d15;
    --vellum-lit: #2f261b;
    --vellum-deep: #1b1610;
    --vellum-shade: #14100b;

    --ink: #ecdfc2;
    --ink-soft: #cbba97;
    --ink-thin: rgba(236, 223, 194, 0.7);
    --ink-faint: rgba(236, 223, 194, 0.4);
    --ink-ghost: rgba(236, 223, 194, 0.16);

    --sanguine: #c9704a;
    --sanguine-thin: rgba(201, 112, 74, 0.5);
    --gold: #d3ab54;
    --gold-thin: rgba(211, 171, 84, 0.45);

    color-scheme: dark;
  }
}

/* ── the film ground ────────────────────────────────────────────────────────
   The second of the two grounds. The paper is taken away and the page is laid
   over a field at dusk; the ink, which would be lost against a lit sky, is
   re-cut in silver. Every colour the page uses is a token, so this is a change
   of palette and a change of plate, and nothing else in the stylesheet has to
   know about it. */
:root[data-ground='film'] {
  --vellum: #050505;
  --vellum-lit: rgba(250, 250, 250, 0.055);
  --vellum-deep: #030303;
  --vellum-shade: #000000;

  --ink: #fafafa;
  --ink-soft: #c3c2c2;
  --ink-thin: rgba(250, 250, 250, 0.72);
  --ink-faint: rgba(250, 250, 250, 0.42);
  --ink-ghost: rgba(250, 250, 250, 0.15);

  --sanguine: #e08a63;
  --sanguine-thin: rgba(224, 138, 99, 0.5);
  --gold: #d9bd7c;
  --gold-thin: rgba(217, 189, 124, 0.45);

  color-scheme: dark;
}

/* The paper's own business — its grain, its wire marks, its foxing, the chalk
   study and the candle's falloff — is all paper, and there is none here. */
:root[data-ground='film'] .vellum__grain,
:root[data-ground='film'] .vellum__fibres,
:root[data-ground='film'] .vellum__foxing,
:root[data-ground='film'] .vellum__vignette,
:root[data-ground='film'] .vellum__study {
  display: none;
}

.vellum__film {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 1.2s ease, visibility 1.2s;
}

:root[data-ground='film'] .vellum__film {
  opacity: 1;
  visibility: visible;
}

.film__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 48%;
  /* A bright plate under small silver type is a plate you cannot read over.
     The saturation comes down so the lavender stops fighting the copper the
     page marks its rubrics in, and the whole thing is held back a stop. */
  filter: saturate(0.78) brightness(0.82) contrast(1.02);
  pointer-events: none;
}

/* The plate is a photograph and the page is a column of small type over it.
   Two scrims: one down the page so the foot goes to black under the colophon,
   one across it so the two margins where the text sits are held down while the
   light at the centre is left alone. */
.vellum__film::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(
      to bottom,
      rgba(5, 5, 5, 0.76) 0%,
      rgba(5, 5, 5, 0.5) 24%,
      rgba(5, 5, 5, 0.56) 60%,
      rgba(5, 5, 5, 0.9) 86%,
      rgba(5, 5, 5, 0.98) 95%,
      #050505 100%
    ),
    linear-gradient(
      to right,
      rgba(5, 5, 5, 0.95) 0%,
      rgba(5, 5, 5, 0.76) 21%,
      rgba(5, 5, 5, 0.4) 47%,
      rgba(5, 5, 5, 0.76) 75%,
      rgba(5, 5, 5, 0.95) 100%
    );
}

@media (max-width: 1079px) {
  .film__video {
    object-position: 46% center;
  }

  .vellum__film::after {
    background:
      linear-gradient(
        to bottom,
        rgba(5, 5, 5, 0.82) 0%,
        rgba(5, 5, 5, 0.58) 24%,
        rgba(5, 5, 5, 0.62) 58%,
        rgba(5, 5, 5, 0.92) 86%,
        #050505 100%
      ),
      linear-gradient(to right, rgba(5, 5, 5, 0.82) 0%, rgba(5, 5, 5, 0.56) 50%, rgba(5, 5, 5, 0.82) 100%);
  }
}

/* On the film the cover's ground stops being a sheet and becomes a held frame:
   the plate carries on behind it, blurred, with the page dropped out. */
:root[data-ground='film'] .seal {
  background: rgba(5, 5, 5, 0.58);
  -webkit-backdrop-filter: blur(14px) saturate(0.9);
  backdrop-filter: blur(14px) saturate(0.9);
}

:root[data-ground='film'] .seal::before {
  display: none;
}

/* ── the switch ─────────────────────────────────────────────────────────────
   Two choices in a ruled box, each naming itself and then saying what it is.
   A pair of words alone read as a label rather than as a control, so this is
   drawn as something to press: a frame, a filled mark against the one in
   force, and a ground that lifts under the pointer. */
.ground {
  display: grid;
  gap: 1px;
  margin: 0 0 0.7rem;
  border: 1px solid var(--ink-ghost);
  background: var(--ink-ghost);
}

.ground__key {
  position: relative;
  display: grid;
  gap: 0.08rem;
  padding: 0.5rem 0.6rem 0.5rem 1.65rem;
  border: 0;
  background: var(--vellum-lit);
  cursor: pointer;
  text-align: left;
  color: var(--ink-soft);
  transition: box-shadow 0.4s ease, color 0.4s ease;
}

.ground__name {
  font-family: var(--serif-display);
  font-size: 0.82rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.ground__gloss {
  font-size: 0.74rem;
  font-style: italic;
  color: var(--ink-faint);
  transition: color 0.4s ease;
}

/* The mark: an empty ring that fills when its choice is the one in force. */
.ground__key::before {
  content: '';
  position: absolute;
  left: 0.62rem;
  top: 0.78rem;
  width: 0.52rem;
  height: 0.52rem;
  border: 1px solid var(--ink-faint);
  border-radius: 50%;
  transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}

/* The row is marked at its edge rather than by changing its ground: a wash
   that reads as a lift on paper reads as a hole on the video, and the page
   already marks the hour now sounding this way in the programme list. */
.ground__key:hover,
.ground__key:focus-visible {
  color: var(--ink);
  box-shadow: inset 3px 0 0 var(--sanguine-thin);
}

.ground__key[aria-pressed='true'] {
  color: var(--sanguine);
  box-shadow: inset 3px 0 0 var(--sanguine);
}

.ground__key[aria-pressed='true'] .ground__gloss {
  color: var(--sanguine-thin);
}

.ground__key[aria-pressed='true']::before {
  border-color: var(--sanguine);
  background: var(--sanguine);
  box-shadow: 0 0 0 2px var(--sanguine-thin);
}

/* The one control on the page is not marginalia, so its heading is set in the
   page's own words rather than in the Latin the notes around it use. */
.note--ground .note__label {
  color: var(--ink-soft);
}

@media (prefers-reduced-motion: reduce) {
  .vellum__film {
    transition: none;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--vellum);
  color: var(--ink);
  font-family: var(--serif-text);
  font-size: clamp(15px, 0.55vw + 12.5px, 17px);
  line-height: 1.62;
  font-feature-settings: 'liga' 1, 'kern' 1, 'onum' 1;
  overflow-x: hidden;
}

::selection {
  background: var(--sanguine-thin);
  color: var(--ink);
}

:focus-visible {
  outline: 1px solid var(--sanguine);
  outline-offset: 3px;
}

/* ── the vellum itself ───────────────────────────────────────────────────── */

.vellum {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* The study is hung past the right edge on purpose; clip it here so it does
     not lengthen the page's scrollable width. */
  overflow: hidden;
}

.vellum__grain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.3;
  mix-blend-mode: multiply;
}

@media (prefers-color-scheme: dark) {
  .vellum__grain {
    opacity: 0.3;
    mix-blend-mode: overlay;
  }
}

/* Laid lines — the wire marks left in handmade paper. */
.vellum__fibres {
  position: absolute;
  inset: 0;
  opacity: 0.5;
  background-image:
    repeating-linear-gradient(90deg, transparent 0 26px, var(--ink-ghost) 26px 26.5px),
    repeating-linear-gradient(0deg, transparent 0 3px, rgba(0, 0, 0, 0.014) 3px 3.5px);
}

/* ── the study ──────────────────────────────────────────────────────────────
   Him, on the page, in the manner of a red-chalk study: not a photograph laid
   on the paper but a drawing made in it. The colour is taken out and put back
   as sanguine, the figure is held at the opacity of chalk rather than ink, and
   multiply lets the paper's own grain and foxing come through the flesh, which
   is what separates a drawing from a print.

   He stands to the right, rising off the bottom edge, so that the folio's
   centre column — where the dial is — stays clear and the page is never
   competing with the instrument. A soft mask dissolves him into the vellum at
   every edge; a study is never cut out, it simply stops. */
.vellum__study {
  position: absolute;
  right: -6vw;
  bottom: -2vh;
  width: clamp(24rem, 42vw, 46rem);
  height: min(88vh, 58rem);
  background-image: image-set(
    url('../img/study.webp') type('image/webp'),
    url('../img/study.png') type('image/png')
  );
  background-repeat: no-repeat;
  background-position: right bottom;
  background-size: contain;
  opacity: 0.13;
  mix-blend-mode: multiply;
  filter: grayscale(1) sepia(0.8) saturate(1.6) contrast(0.92) blur(1.4px);
  /* The head is where a study is always faintest — the draughtsman works down
     from it — so the mask lets go at the top and holds through the shoulder. */
  -webkit-mask-image:
    linear-gradient(180deg, transparent 0, #000 26%, #000 74%, transparent 99%),
    radial-gradient(64% 70% at 66% 58%, #000 24%, transparent 82%);
  mask-image:
    linear-gradient(180deg, transparent 0, #000 26%, #000 74%, transparent 99%),
    radial-gradient(64% 70% at 66% 58%, #000 24%, transparent 82%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  animation: study-settles 3.4s ease 0.4s both;
}

@keyframes study-settles {
  from { opacity: 0; transform: translateY(1.2rem) scale(1.02); }
  to { opacity: 0.13; transform: none; }
}

/* Candlelight. Chalk on a dark ground is lighter than the ground, not darker,
   so the blend turns over and the figure is lifted out rather than pressed in. */
@media (prefers-color-scheme: dark) {
  .vellum__study {
    mix-blend-mode: screen;
    opacity: 0.11;
    filter: grayscale(1) sepia(0.5) saturate(1.2) contrast(1.05) brightness(1.2) blur(1.4px);
  }

  @keyframes study-settles {
    from { opacity: 0; transform: translateY(1.2rem) scale(1.02); }
    to { opacity: 0.11; transform: none; }
  }
}

/* On a narrow page there is no clear column to keep, so he sits behind
   everything, fainter, and centred rather than pushed to one side. */
@media (max-width: 1079px) {
  .vellum__study {
    right: 50%;
    transform: translateX(50%);
    width: min(120vw, 32rem);
    height: 58vh;
    opacity: 0.085;
    -webkit-mask-image: radial-gradient(66% 62% at 50% 44%, #000 26%, transparent 76%);
    mask-image: radial-gradient(66% 62% at 50% 44%, #000 26%, transparent 76%);
    animation: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .vellum__study {
    animation: none;
  }
}

/* Foxing: the rust-coloured blooms that age brings to rag paper. */
.vellum__foxing {
  position: absolute;
  inset: 0;
  opacity: 0.4;
  background:
    radial-gradient(15rem 11rem at 12% 18%, rgba(150, 96, 40, 0.09), transparent 70%),
    radial-gradient(22rem 14rem at 88% 12%, rgba(133, 90, 42, 0.08), transparent 72%),
    radial-gradient(18rem 20rem at 78% 84%, rgba(146, 88, 36, 0.07), transparent 70%),
    radial-gradient(12rem 9rem at 26% 92%, rgba(120, 78, 34, 0.08), transparent 70%),
    radial-gradient(30rem 24rem at 50% 46%, var(--vellum-lit), transparent 78%);
}

/* The falloff of one candle, a little off centre. */
.vellum__vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    120% 100% at 46% 38%,
    transparent 46%,
    rgba(60, 40, 18, 0.07) 76%,
    rgba(42, 26, 10, 0.2) 100%
  );
}

/* ── the folio ───────────────────────────────────────────────────────────── */

.folio {
  position: relative;
  z-index: 1;
  max-width: 1560px;
  margin: 0 auto;
  padding: clamp(1.4rem, 3vw, 3.2rem) clamp(1.1rem, 3.4vw, 3.6rem) 3rem;
  display: grid;
  gap: clamp(1.4rem, 2.6vw, 3rem);
  grid-template-columns: 1fr;
  grid-template-areas:
    'head'
    'plate'
    'right'
    'left'
    'colophon';
}

@media (min-width: 1080px) {
  .folio {
    grid-template-columns: minmax(15rem, 0.82fr) minmax(30rem, 1.6fr) minmax(16rem, 0.9fr);
    grid-template-areas:
      'head  head  head'
      'left  plate right'
      'colophon colophon colophon';
    align-items: start;
  }
}

/* ── head ────────────────────────────────────────────────────────────────── */

.folio__head {
  grid-area: head;
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  text-align: center;
  padding-bottom: 0.6rem;
}

.head__mark {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  width: min(100%, 30rem);
  justify-content: center;
}

.head__rule {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--ink-faint) 22%, var(--ink-faint) 78%, transparent);
}

.head__folio,
.head__clock {
  margin: 0;
  font-family: var(--serif-display);
  font-size: 0.72rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ink-thin);
  white-space: nowrap;
}

.head__clock {
  letter-spacing: 0.22em;
  font-variant-numeric: tabular-nums;
}

.head__clock abbr {
  text-decoration: none;
  color: var(--sanguine);
}

.head__title {
  margin: 0.1rem 0 0;
  display: grid;
  gap: 0.1rem;
  line-height: 1;
}

.head__title-as {
  font-family: var(--serif-as);
  font-weight: 400;
  font-size: clamp(2.1rem, 5.6vw, 3.6rem);
  color: var(--ink);
  letter-spacing: 0.01em;
}

.head__title-en {
  font-family: var(--serif-display);
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1rem, 1.8vw, 1.35rem);
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  text-transform: uppercase;
  color: var(--sanguine);
}

.head__sub {
  margin: 0.35rem 0 0.5rem;
  max-width: 44rem;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.head__sub em {
  color: var(--ink);
}

/* ── margins ─────────────────────────────────────────────────────────────── */

.margin {
  display: grid;
  gap: clamp(1.3rem, 2.2vw, 2.1rem);
  align-content: start;
}

.margin--left {
  grid-area: left;
}

.margin--right {
  grid-area: right;
}

@media (min-width: 1080px) {
  .margin--left {
    padding-right: 1.2rem;
    border-right: var(--rule);
  }

  .margin--right {
    padding-left: 1.2rem;
    border-left: var(--rule);
  }
}

/* The margin labels used to be in Latin, which is the notebook this page is
   dressed as and not the language it is about. They lead in Assamese now, the
   way the programmes always did, with the English following the interpunct.
   The Assamese half cannot take the small-caps treatment the English half
   does — letter-spacing pulls a conjunct apart and there is no upper case to
   go to — so it is set on its own terms and only the gloss is lettered. */
.label__as {
  font-family: var(--serif-as);
  font-size: 1.24em;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
}

.note__label,
.entry__eyebrow {
  font-family: var(--serif-display);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--sanguine);
  margin: 0 0 0.55rem;
}

.note__body {
  margin: 0;
  font-size: 0.9rem;
  color: var(--ink-soft);
  hyphens: auto;
}

/* A gloss under a list, set smaller than the list it explains. */
.note__body--fine {
  margin-top: 0.7rem;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--ink-faint);
}

/* Written the way he wrote — right to left, to be read in a glass. */
.note--mirror {
  opacity: 0.4;
  transition: opacity 0.9s ease;
}

.note--mirror:hover {
  opacity: 0.72;
}

.mirror-text {
  margin: 0;
  transform: scaleX(-1);
  font-family: var(--serif-display), 'Noto Serif Bengali', serif;
  font-style: italic;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--ink-thin);
}

.note--source {
  padding-top: 0.9rem;
  border-top: var(--rule);
}

.source__link {
  display: inline-block;
  margin-top: 0.5rem;
  font-family: var(--serif-display);
  font-style: italic;
  font-size: 0.84rem;
  color: var(--sanguine);
  text-decoration: none;
  border-bottom: 1px solid var(--sanguine-thin);
}

.source__link:hover {
  border-bottom-color: var(--sanguine);
}

/* ── the day's programme ─────────────────────────────────────────────────── */

.schedule {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.05rem;
}

.prog {
  display: grid;
  grid-template-columns: 4.6rem 1fr;
  gap: 0.6rem;
  align-items: baseline;
  width: 100%;
  padding: 0.42rem 0.35rem 0.42rem 0.5rem;
  background: none;
  border: 0;
  border-left: 2px solid transparent;
  cursor: pointer;
  font: inherit;
  text-align: left;
  font-size: 0.85rem;
  color: var(--ink-thin);
  transition: color 0.4s ease, border-color 0.4s ease, background 0.4s ease;
}

.prog:hover {
  color: var(--ink);
  background: linear-gradient(90deg, rgba(148, 55, 28, 0.05), transparent 78%);
}

.prog[data-on='true'] {
  color: var(--ink);
  border-left-color: var(--sanguine);
  background: linear-gradient(90deg, rgba(148, 55, 28, 0.08), transparent 78%);
}

.prog__hours {
  font-variant-numeric: tabular-nums;
  font-size: 0.76rem;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

.prog[data-on='true'] .prog__hours {
  color: var(--sanguine);
}

.prog__name {
  display: grid;
  gap: 0.05rem;
}

.prog__as {
  font-family: var(--serif-as);
  font-size: 0.95rem;
  line-height: 1.35;
}

.prog__en {
  font-family: var(--serif-display);
  font-style: italic;
  font-size: 0.76rem;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

.prog[data-on='true'] .prog__en {
  color: var(--ink-thin);
}

/* ── the index of voices ─────────────────────────────────────────────────── */

.voices {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.28rem;
}

.voices li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.6rem;
  align-items: baseline;
  font-size: 0.84rem;
  color: var(--ink-soft);
}

.voices li::after {
  content: '';
  grid-column: 1 / -1;
  height: 1px;
  background: var(--ink-ghost);
}

.voices span {
  font-variant-numeric: tabular-nums;
  font-size: 0.74rem;
  color: var(--ink-faint);
}

.voices li[data-on='true'] {
  color: var(--sanguine);
}

.voices li[data-on='true'] span {
  color: var(--sanguine-thin);
}

/* ── the plate ───────────────────────────────────────────────────────────── */

.plate {
  grid-area: plate;
  display: grid;
  gap: clamp(1rem, 2vw, 1.8rem);
  justify-items: center;
}

.plate__figure,
.study {
  margin: 0;
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 0.7rem;
}

.machina {
  width: min(100%, 44rem);
  height: auto;
  overflow: visible;
}

.machina text {
  font-family: var(--serif-display);
  fill: var(--ink-thin);
}

.construction {
  fill: none;
  stroke: var(--ink-faint);
  stroke-width: 1;
}

.construction--golden {
  stroke: var(--gold-thin);
  stroke-dasharray: 3 5;
}

.spiral {
  fill: none;
  stroke: var(--gold-thin);
  stroke-width: 1;
  stroke-dasharray: 2600;
  stroke-dashoffset: 2600;
  animation: draw 9s cubic-bezier(0.33, 0, 0.15, 1) 0.6s forwards;
}

@keyframes draw {
  to {
    stroke-dashoffset: 0;
  }
}

.arcs path {
  fill: none;
  stroke: var(--ink-thin);
  stroke-width: 8;
  stroke-linecap: butt;
  opacity: 0.34;
  transition: opacity 0.8s ease, stroke 0.8s ease, stroke-width 0.8s ease;
}

.arcs path[data-block][data-on='true'] {
  stroke: var(--sanguine);
  stroke-width: 11;
  opacity: 0.95;
}

.arc-labels text {
  font-size: 12.5px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  fill: var(--ink-thin);
  transition: fill 0.8s ease;
}

.arc-labels text[data-on='true'] {
  fill: var(--sanguine);
}

.ticks line {
  stroke: var(--ink-faint);
  stroke-width: 0.9;
}

.ticks line[data-major='true'] {
  stroke: var(--ink-thin);
  stroke-width: 1.4;
}

.numerals text {
  font-size: 13px;
  letter-spacing: 0.12em;
  fill: var(--ink-thin);
  text-anchor: middle;
  dominant-baseline: middle;
}

/* the disc */
.disc {
  transform-origin: 360px 360px;
}

.grooves circle {
  fill: none;
  stroke: var(--ink-faint);
  stroke-width: 0.75;
}

.disc__seat {
  fill: var(--vellum);
}

.disc__label {
  fill: none;
  stroke: var(--sanguine);
  stroke-width: 1.2;
}

.disc__spindle {
  fill: var(--ink);
}

body[data-playing='true'] .disc {
  animation: revolve 24s linear infinite;
}

@keyframes revolve {
  to {
    transform: rotate(360deg);
  }
}

/* the gear train */
.gears path,
.gears circle {
  fill: none;
  stroke: var(--ink-faint);
  stroke-width: 0.85;
}

.gears g {
  transform-box: fill-box;
  transform-origin: center;
}

body[data-playing='true'] .gears g[data-spin='cw'] {
  animation: revolve 11s linear infinite;
}

body[data-playing='true'] .gears g[data-spin='ccw'] {
  animation: revolve 7s linear infinite reverse;
}

/* the hand */
.hand {
  transform-origin: 360px 360px;
  transition: transform 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

.hand line {
  stroke: var(--sanguine);
  stroke-width: 1.4;
}

.hand circle {
  fill: var(--vellum);
  stroke: var(--sanguine);
  stroke-width: 1.2;
}

.hand path {
  fill: var(--sanguine);
}

.annotation line {
  stroke: var(--ink-faint);
  stroke-width: 0.7;
}

.annotation text {
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  fill: var(--ink-faint);
}

/* captions, in the voice of a plate in a treatise */
.plate__caption,
.study__caption {
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
  max-width: 34rem;
  font-size: 0.8rem;
  color: var(--ink-thin);
  font-style: italic;
  text-align: left;
}

.caption__num {
  font-family: var(--serif-display);
  font-style: normal;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--sanguine);
  white-space: nowrap;
}

.study__canvas {
  width: 100%;
  max-width: 44rem;
  height: auto;
}

/* ── the entry: what is turning now ──────────────────────────────────────── */

/* ── the cartouche ──────────────────────────────────────────────────────────
   The record now turning, given a panel of its own: a lighter ground where the
   candle falls, a hairline frame, and the four corner marks a draughtsman rules
   before he begins so he knows where the drawing stops. Everything inside it is
   set to one rhythm — gold for the labels, sanguine for the name in Assamese,
   ink for the rest — so the column reads as one illuminated block rather than
   as six things stacked up. */
.entry {
  position: relative;
  display: grid;
  gap: 0.45rem;
  /* A grid item's automatic minimum is its content, and a long unbroken
     Assamese title at display size is wider than this column. Without this the
     cartouche pushes itself past the folio's edge. */
  min-width: 0;
  grid-template-columns: minmax(0, 1fr);
  padding: 1.25rem 1.15rem 1.35rem;
  background:
    radial-gradient(130% 70% at 50% 0%, var(--vellum-lit) 0%, transparent 72%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.16), transparent 46%);
  border: 1px solid var(--ink-ghost);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 0.6rem 1.8rem -0.9rem rgba(36, 26, 15, 0.28);
}

/* The corner marks: eight short rules, ruled in sanguine, set in from the
   frame the way register marks sit in from a plate's edge. */
.entry::before {
  content: '';
  position: absolute;
  inset: 0.42rem;
  pointer-events: none;
  background-image:
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin)),
    linear-gradient(var(--sanguine-thin), var(--sanguine-thin));
  background-repeat: no-repeat;
  background-size:
    9px 1px, 1px 9px,
    9px 1px, 1px 9px,
    9px 1px, 1px 9px,
    9px 1px, 1px 9px;
  background-position:
    left top, left top,
    right top, right top,
    left bottom, left bottom,
    right bottom, right bottom;
}

@media (prefers-color-scheme: dark) {
  .entry {
    background:
      radial-gradient(130% 70% at 50% 0%, var(--vellum-lit) 0%, transparent 72%),
      linear-gradient(180deg, rgba(255, 236, 200, 0.05), transparent 46%);
    box-shadow:
      inset 0 1px 0 rgba(255, 236, 200, 0.07),
      0 0.6rem 2rem -0.9rem rgba(0, 0, 0, 0.5);
  }
}

.entry__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.8rem;
  flex-wrap: wrap;
  padding-bottom: 0.5rem;
  margin-bottom: 0.15rem;
  border-bottom: 1px solid var(--ink-ghost);
}

.entry__eyebrow {
  margin: 0;
  font-family: var(--serif-as);
  letter-spacing: 0.06em;
  text-transform: none;
  font-size: 1.08rem;
  color: var(--gold);
}

.entry__state {
  font-family: var(--serif-display);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  /* The engine writes anything from "on air" to "the station is already
     playing" here. Kept on one line it is wider than the column, so it is
     allowed to wrap and to give way to the hour beside it. */
  min-width: 0;
  flex: 0 1 auto;
  overflow-wrap: break-word;
  text-align: right;
  line-height: 1.35;
}

.entry__state::before {
  content: '';
  flex: none;
  align-self: center;
  width: 0.42rem;
  height: 0.42rem;
  border-radius: 50%;
  background: var(--ink-faint);
  transition: background 0.5s ease, box-shadow 0.5s ease;
}

.entry__state[data-state='playing']::before {
  background: var(--sanguine);
  box-shadow: 0 0 0 3px var(--sanguine-thin);
  animation: pulse 3.4s ease-in-out infinite;
}

.entry__state[data-state='seeking']::before {
  background: var(--gold);
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* ── the record now turning ─────────────────────────────────────────────────
   This column had every line the page could draw and no light in it. What it
   wanted was not more ink but what an illuminator does with the same ink: a
   rubricated title, a ruled flourish under it to stop the eye, leaders running
   out to the facts the way an index carries a reader to a page number, and a
   scale on the progress that can actually be read. The one thing that moves is
   the thing that is moving — while a song runs, the inner ring of the play key
   turns with the gear train, and the nib at the head of the rule glows wet. */
.entry__title {
  position: relative;
  margin: 0;
  font-family: var(--serif-display);
  font-weight: 400;
  font-size: clamp(1.7rem, 2.9vw, 2.4rem);
  line-height: 1.06;
  letter-spacing: -0.005em;
  overflow-wrap: break-word;
  text-wrap: balance;
  color: var(--ink);
}

/* The flourish: a rule that starts heavy at the sanguine lozenge and runs out
   to nothing, the way a ruled line does when the nib lifts. */
/* A rule with a lozenge at its centre, thinning to nothing at both ends —
   the mark a scribe closes a block of text with. */
.entry__flourish {
  display: block;
  height: 9px;
  margin: 0.55rem 0 0.35rem;
  background:
    linear-gradient(90deg, transparent, var(--gold-thin) 22%, var(--gold) 48%, var(--gold-thin) 78%, transparent),
    radial-gradient(circle at 50% 50%, var(--sanguine) 0 3px, transparent 3.4px);
  background-repeat: no-repeat;
  background-size: 100% 1px, 100% 100%;
  background-position: 0 50%, 0 0;
}

.entry__native {
  margin: 0.15rem 0 0;
  font-family: var(--serif-as);
  font-weight: 400;
  font-size: 1.2rem;
  line-height: 1.45;
  overflow-wrap: break-word;
  color: var(--sanguine);
}

.entry__native:empty {
  display: none;
}

.entry__facts {
  margin: 0.35rem 0 0;
  display: grid;
  gap: 0.1rem;
}

.fact[hidden] {
  display: none;
}

.fact {
  display: grid;
  grid-template-columns: 3.4rem 1fr;
  gap: 0.7rem;
  align-items: baseline;
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--ink-ghost);
  transition: border-color 0.5s ease;
}

.fact:hover {
  border-bottom-color: var(--sanguine-thin);
}

.fact dt {
  position: relative;
  font-family: var(--serif-display);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}

/* Leaders, as an index runs them out to the page number. */
.fact dt::after {
  content: '';
  position: absolute;
  left: 100%;
  right: -0.55rem;
  bottom: 0.22em;
  border-bottom: 1px dotted var(--ink-ghost);
}

.fact dd {
  margin: 0;
  font-size: 0.95rem;
  color: var(--ink);
}

/* the progress rule, drawn as a scale bar */
.progress {
  margin-top: 0.7rem;
  display: grid;
  gap: 0.35rem;
}

.progress__source {
  display: none;
}

.progress__rule {
  position: relative;
  height: 15px;
  border-left: 1px solid var(--ink-thin);
  border-right: 1px solid var(--ink-thin);
}

/* The divisions of the scale, and the line they stand on. */
.progress__rule::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(90deg, var(--ink-ghost) 0 1px, transparent 1px 5%),
    linear-gradient(var(--ink-faint), var(--ink-faint));
  background-repeat: repeat-x, no-repeat;
  background-size: 100% 5px, 100% 1px;
  background-position: 0 100%, 0 calc(100% - 2px);
}

.progress__ink {
  position: absolute;
  left: 0;
  bottom: 2px;
  height: 2px;
  width: 0%;
  background: linear-gradient(90deg, var(--gold) 0%, var(--sanguine) 82%);
  transition: width 1s linear;
}

/* The nib. It is wet while the song runs and dry when it does not. */
.progress__ink::after {
  content: '';
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--sanguine);
  transition: box-shadow 0.6s ease;
}

body[data-playing='true'] .progress__ink::after {
  box-shadow: 0 0 0 3px var(--sanguine-thin), 0 0 10px 2px var(--sanguine-thin);
  animation: nib-wet 3.2s ease-in-out infinite;
}

@keyframes nib-wet {
  0%, 100% { box-shadow: 0 0 0 2.5px var(--sanguine-thin), 0 0 8px 1px var(--sanguine-thin); }
  50% { box-shadow: 0 0 0 4px var(--sanguine-thin), 0 0 14px 3px var(--sanguine-thin); }
}

.progress__times {
  display: flex;
  justify-content: space-between;
  font-family: var(--serif-display);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.14em;
  color: var(--ink-thin);
}

/* ── the keys ────────────────────────────────────────────────────────────── */

/* Back, play and next on one line with the volume beside them is wider than
   this column; the volume drops to a rule of its own beneath instead. */
.keys {
  margin-top: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(0.9rem, 2.4vw, 1.5rem);
}

.keys .vol {
  flex: 1 0 100%;
  justify-content: center;
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--ink-ghost);
  color: var(--sanguine);
}

.keys .vol__range {
  max-width: 9rem;
}

.key {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
}

.key svg {
  width: 2.5rem;
  height: 2.5rem;
}

.key--play svg {
  width: 3.9rem;
  height: 3.9rem;
}

/* The escapement: sixty divisions, one a second, every fifth one longer. */
.key__escapement line {
  stroke: var(--ink-ghost);
  stroke-width: 0.55;
  transition: stroke 0.6s ease;
}

.key__escapement .tooth--long {
  stroke: var(--gold-thin);
  stroke-width: 0.8;
}

.key__escapement {
  transform-box: fill-box;
  transform-origin: center;
}

body[data-playing='true'] .key__escapement {
  animation: escapement 60s linear infinite;
}

body[data-playing='true'] .key__escapement line {
  stroke: var(--gold-thin);
}

.key svg {
  overflow: visible;
}

.key__ring {
  fill: none;
  stroke: var(--ink-thin);
  stroke-width: 1;
  transition: stroke 0.4s ease, fill 0.5s ease;
}

/* The play key's escapement. It is ruled in gold and, while a song runs, it
   turns — the same minute-long revolution as the gear train on the plate, so
   the two agree with each other. */
.key__ring--inner {
  stroke: var(--gold-thin);
  stroke-dasharray: 2 4;
  transform-box: fill-box;
  transform-origin: center;
}

body[data-playing='true'] .key--play .key__ring--inner {
  animation: escapement 60s linear infinite;
  stroke: var(--gold);
}

@keyframes escapement {
  to { transform: rotate(360deg); }
}

/* A wash of light under the play key while it sounds. */
.key--play svg {
  transition: filter 0.6s ease;
}

body[data-playing='true'] .key--play svg {
  filter: drop-shadow(0 0 9px var(--sanguine-thin));
}

body[data-playing='true'] .key--play .key__ring:not(.key__ring--inner) {
  stroke: var(--sanguine);
}

.key__glyph-fill {
  fill: var(--sanguine);
  transition: fill 0.4s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  transform-box: fill-box;
  transform-origin: center;
}

.key:hover .key__ring,
.key:focus-visible .key__ring {
  stroke: var(--sanguine);
  fill: var(--sanguine-thin);
  fill-opacity: 0.12;
}

.key:hover .key__glyph-fill,
.key:focus-visible .key__glyph-fill {
  transform: scale(1.12);
}

.key:active .key__glyph-fill {
  transform: scale(0.94);
}

.key:hover .key__label,
.key:focus-visible .key__label {
  color: var(--sanguine);
}

.key__label {
  transition: color 0.4s ease;
}

.key__label {
  font-family: var(--serif-display);
  font-size: 0.68rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-thin);
}

.offair {
  margin: 0.8rem 0 0;
  font-size: 0.8rem;
  font-style: italic;
  text-align: center;
  color: var(--ink-faint);
}

.offair button {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  color: var(--sanguine);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ── colophon ────────────────────────────────────────────────────────────── */

.colophon {
  grid-area: colophon;
  margin: 0 auto;
  max-width: 46rem;
  padding-top: 1.2rem;
  border-top: var(--rule);
  text-align: center;
  font-size: 0.76rem;
  line-height: 1.7;
  color: var(--ink-faint);
}

.colophon__sig {
  display: block;
  margin-top: 0.4rem;
  font-family: var(--serif-display);
  font-style: italic;
  letter-spacing: 0.08em;
}

/* ── the seal ────────────────────────────────────────────────────────────── */

.seal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background: radial-gradient(120% 100% at 50% 40%, var(--vellum-lit), var(--vellum) 55%, var(--vellum-shade));
  transition: opacity 1.1s ease, visibility 1.1s;
}

/* The cover's ground is opaque, so the study on the page below cannot show
   through it. It gets its own — further off the edge and fainter still, a
   presence at the margin rather than a portrait. */
.seal::before {
  content: '';
  position: absolute;
  right: -8vw;
  bottom: -4vh;
  width: clamp(22rem, 40vw, 44rem);
  height: min(92vh, 60rem);
  background-image: image-set(
    url('../img/study.webp') type('image/webp'),
    url('../img/study.png') type('image/png')
  );
  background-repeat: no-repeat;
  background-position: right bottom;
  background-size: contain;
  opacity: 0.11;
  mix-blend-mode: multiply;
  filter: grayscale(1) sepia(0.8) saturate(1.6) contrast(0.92) blur(1.6px);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 28%, #000 76%, transparent 99%);
  mask-image: linear-gradient(180deg, transparent 0, #000 28%, #000 76%, transparent 99%);
  pointer-events: none;
}

@media (prefers-color-scheme: dark) {
  .seal::before {
    mix-blend-mode: screen;
    opacity: 0.1;
    filter: grayscale(1) sepia(0.5) saturate(1.2) brightness(1.2) blur(1.6px);
  }
}

/* On a narrow cover he would sit straight behind the word, which reads as a
   collision rather than a background. Dropped to the foot of the page instead,
   so what is behind the lettering is the shoulder and not the face. */
@media (max-width: 1079px) {
  .seal::before {
    right: 50%;
    bottom: -16vh;
    transform: translateX(50%);
    width: min(110vw, 28rem);
    height: 74vh;
    opacity: 0.07;
    -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 48%, #000 82%, transparent 99%);
    mask-image: linear-gradient(180deg, transparent 0, #000 48%, #000 82%, transparent 99%);
  }

  .seal__body {
    max-width: 21rem;
  }
}

.seal[hidden] {
  display: grid;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.seal__inner {
  display: grid;
  justify-items: center;
  gap: 0.4rem;
  text-align: center;
  /* Bounded by the grid's content box rather than the viewport, so the seal's
     own padding is never overrun on a narrow screen. */
  width: 100%;
  max-width: 64rem;
}

/* ── the mark ───────────────────────────────────────────────────────────────
   The name, lettered into the figure it was ruled inside. Everything is drawn
   rather than set: the construction goes down first in a hard pale line, the
   pen then crosses the page once from left to right, and the strokes of the
   word appear behind it as it passes. The ink floods the letters afterwards,
   the way it does when a nib is lifted and the paper takes what is left. */
.sealmark {
  width: 100%;
  max-width: 64rem;
  height: auto;
  overflow: visible;
}

.sealmark__construction {
  fill: none;
  stroke: var(--ink-faint);
  stroke-width: 0.7;
  opacity: 0;
  animation: rule-up 2s ease 0.1s forwards;
}

.sealmark__construction .tick {
  stroke: var(--ink-thin);
  stroke-width: 0.8;
}

.sealmark__construction .tick--long {
  stroke: var(--sanguine-thin);
  stroke-width: 1.1;
}

.sealmark__construction .frame {
  stroke: var(--ink-ghost);
  stroke-width: 0.8;
}

.sealmark__construction .diagonal {
  stroke: var(--ink-ghost);
  stroke-width: 0.6;
  stroke-dasharray: 4 6;
}

.sealmark__construction .phi {
  stroke: var(--gold-thin);
  stroke-width: 0.6;
  stroke-dasharray: 2 7;
}

@keyframes rule-up {
  from { opacity: 0; }
  to { opacity: 1; }
}

.sealmark__ring {
  fill: none;
  stroke: var(--sanguine-thin);
  stroke-width: 1.1;
  opacity: 0;
  animation: rule-up 1.8s ease 0.3s forwards;
}

.sealmark__ring--fine {
  stroke: var(--ink-faint);
  stroke-width: 0.8;
}

/* The word. Both copies are the same glyphs: one outlined, drawn on by the
   sweeping mask, one solid, flooded in behind it a beat later. */
.sealmark__fill,
.sealmark__stroke {
  font-family: var(--serif-as);
  font-size: 150px;
  font-weight: 400;
  letter-spacing: 0.01em;
}

.sealmark__stroke {
  fill: none;
  stroke: var(--sanguine);
  stroke-width: 1.5;
  stroke-linejoin: round;
  paint-order: stroke;
}

.sealmark__fill {
  fill: var(--ink);
  opacity: 0;
  animation: ink-floods 2.4s ease 1.5s forwards;
}

@keyframes ink-floods {
  from { opacity: 0; }
  to { opacity: 0.92; }
}

/* The pen, crossing once. */
.sealmark__sweep {
  transform-box: fill-box;
  transform-origin: left center;
  transform: scaleX(0);
  animation: pen-crosses 2.1s cubic-bezier(0.5, 0.04, 0.3, 1) 0.45s forwards;
}

@keyframes pen-crosses {
  to { transform: scaleX(1); }
}

.sealmark__roman {
  fill: var(--sanguine);
  font-family: var(--serif-display);
  font-size: 30px;
  font-style: italic;
  letter-spacing: 0.42em;
  opacity: 0;
  animation: rule-up 1.6s ease 2.5s forwards;
}

@media (prefers-reduced-motion: reduce) {
  .sealmark__construction,
  .sealmark__ring,
  .sealmark__fill,
  .sealmark__roman {
    opacity: 1;
    animation: none;
  }

  .sealmark__sweep {
    transform: scaleX(1);
    animation: none;
  }
}

@media (max-width: 700px) {
  .sealmark__fill,
  .sealmark__stroke {
    font-size: 158px;
  }

  .sealmark__roman {
    font-size: 34px;
    letter-spacing: 0.3em;
  }
}

.seal__body {
  margin: 0;
  max-width: 26rem;
  font-size: 0.95rem;
  font-style: italic;
  color: var(--ink-soft);
  opacity: 0;
  animation: rule-up 1.6s ease 2.8s forwards;
}

@media (prefers-reduced-motion: reduce) {
  .seal__body,
  .seal__key {
    opacity: 1;
    animation: none;
  }
}

.seal__key {
  opacity: 0;
  animation: rule-up 1.6s ease 3s forwards;
  margin-top: 0.9rem;
  padding: 0.6rem 2.4rem;
  background: none;
  border: 1px solid var(--sanguine);
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--serif-display);
  font-size: 0.82rem;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  text-transform: uppercase;
  color: var(--sanguine);
  transition: background 0.5s ease, color 0.5s ease;
}

.seal__key:hover,
.seal__key:focus-visible {
  background: var(--sanguine);
  color: var(--vellum-lit);
}

/* the player: heard, never seen */
.stage {
  position: fixed;
  width: 1px;
  height: 1px;
  left: -100vw;
  top: -100vh;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

/* ── first paint ─────────────────────────────────────────────────────────── */

.folio {
  opacity: 0;
  animation: rise 1.6s cubic-bezier(0.22, 1, 0.36, 1) 0.15s forwards;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(0.6rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .spiral {
    stroke-dashoffset: 0;
  }

  .folio {
    opacity: 1;
  }
}

/* ── volume ───────────────────────────────────────────────────────────────── */

/* Red chalk, like every other quantity the scribe marked on the page. The keys
   are 44-unit circles with a caption under each; this sits on their centre
   line rather than on the top edge they are aligned to. */
.vol {
  --vol-track: var(--ink-ghost);
  --vol-fill: var(--sanguine);
  --vol-thumb: var(--sanguine);
  --vol-ink: var(--ink-thin);

  align-self: center;
  margin-left: 0.3rem;
}

.vol__key:hover {
  color: var(--sanguine);
}

.vol__value {
  font-family: var(--serif-text);
  font-style: italic;
  font-size: 0.74rem;
  letter-spacing: 0;
  opacity: 0.8;
}
