/* The Transcendence kit: layout, type, the docked title and chapter list, the reading scrim, paper sections.
   A page links this file, then its own page.css for what only that page has. Paper only: there is no dark theme.
   Type floor: a line on paint is at least 30 px, body text and captions at least 18 px and near full contrast. */

@font-face { font-family: "Inter Tight"; src: url(fonts/InterTight-var.woff2) format("woff2"); font-weight: 100 900; font-display: swap; }
@font-face { font-family: "Instrument Serif"; src: url(fonts/InstrumentSerif-400.woff2) format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Instrument Serif"; src: url(fonts/InstrumentSerif-400-italic.woff2) format("woff2"); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "Bodoni Moda"; src: url(fonts/BodoniModa-var.woff2) format("woff2"); font-weight: 400 500; font-display: swap; }
@font-face { font-family: "Jost"; src: url(fonts/Jost-var.woff2) format("woff2"); font-weight: 300 400; font-display: swap; }

:root {
  --tf-paper: #E9E4D6;          /* the paper */
  --tf-ink: #17130E;            /* ink on paper */
  --tf-ink-soft: #4A4338;       /* captions on paper: never faint */
  --tf-light: #F4EEE0;          /* type on paint */
  --tf-light-soft: #DDD5C4;
  --tf-chalk: #A8442C;          /* red chalk: the one accent */
  --tf-sepia: #4B3524;          /* brown ink for drawings */
  --tf-night: #0B0907;          /* behind the paintings */
  --tf-rail: 20vw;              /* the left rail that holds title and chapter list */
  --tf-gap: 14px;
  --tf-edge: 14px;
  --tf-sans: "Inter Tight", "Helvetica Neue", Arial, sans-serif;
  --tf-serif: "Instrument Serif", "Iowan Old Style", Georgia, serif;
  --tf-didone: "Bodoni Moda", "Didot", "Bodoni 72", serif;                  /* dictionary headword */
  --tf-plain: "Jost", "Futura", "Avenir Next", "Helvetica Neue", sans-serif;  /* the rest of a dictionary entry */
  --tf-ease: cubic-bezier(0.23, 1, 0.32, 1);
}

*, *::before, *::after { box-sizing: border-box; }
html { background: var(--tf-night); -webkit-text-size-adjust: 100%; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
body {
  margin: 0; color: var(--tf-light); font-family: var(--tf-serif); font-size: 20px; line-height: 1.2;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility;
  overflow-x: clip;
}
::selection { background: var(--tf-chalk); color: var(--tf-paper); }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--tf-chalk); outline-offset: 4px; }

/* 1. the stage: one sticky full-screen canvas, the page scrolls over it */
.tf-stage { position: sticky; top: 0; height: 100lvh; margin-bottom: -100lvh; z-index: 0; overflow: hidden; background: var(--tf-night); }
.tf-stage canvas { display: block; width: 100%; height: 100%; }
main { position: relative; z-index: 1; }

/* 2. chapters */
.tf-chapter { position: relative; }
.tf-col { margin-left: var(--tf-rail); padding: 0 var(--tf-edge); }
.tf-opener { position: relative; min-height: 150svh; padding: 34svh 0 30svh; }
.tf-word {
  margin: 0 0 0 -0.045em; font: 700 clamp(4.2rem, 13.5vw, 16rem)/0.9 var(--tf-sans); letter-spacing: -0.035em;
  color: var(--tf-light); white-space: nowrap;
}
.tf-lead {                      /* a line on paint: never under 30 px, one line of at most about twelve words */
  margin: 0; max-width: 15em; font: 400 clamp(1.9rem, 3.3vw, 3.8rem)/1.02 var(--tf-serif); letter-spacing: -0.022em;
  text-wrap: balance;
}
.tf-word + .tf-block { margin-top: 5.5svh; }
/* .tf-cap was the large script first letter. The owner removed it; the class is kept as a no-op. */
/* a text block on paint, with its reading scrim as a sibling (never a full-frame overlay) */
.tf-block { position: relative; width: fit-content; max-width: 100%; }
.tf-scrim {
  position: absolute; inset: -34% -10% -38% -13%; z-index: -1; pointer-events: none;
  background: radial-gradient(closest-side, rgba(8, 6, 4, 0.62), rgba(8, 6, 4, 0.36) 60%, rgba(8, 6, 4, 0));
}
/* text over a pale painting (a dawn sky): ink, and a pale glow in place of the dark scrim. Give the scene
   `tone: 'light'` in page.js too, so the title and chapter list turn to ink while that picture is shown. */
.tf-on-light { color: var(--tf-ink); }
.tf-on-light .tf-word { color: var(--tf-ink); }
.tf-on-light .tf-scrim { background: radial-gradient(closest-side, rgba(244, 238, 224, 0.62), rgba(244, 238, 224, 0.34) 60%, rgba(244, 238, 224, 0)); }
/* where a block sits, so it can keep off the brightest or busiest paint: default is the left of the column */
.tf-block.tf-right { margin-left: auto; }
.tf-block.tf-mid { margin-left: auto; margin-right: auto; }
/* a block that holds its place on screen while its opener scrolls by (pair it with data-tf-range) */
.tf-hold { position: sticky; top: var(--tf-hold-top, 30svh); align-self: start; }
.tf-part { position: relative; min-height: var(--tf-part, 100svh); }   /* a stretch of an opener that a held block stays within */
.tf-opener:has(.tf-hold) { display: grid; }          /* so the column is as tall as the opener and the block can hold */
/* a block that rises into place as it enters: the kit publishes --tf-in (0 to 1) on every [data-tf-cue] */
[data-tf-cue].tf-rise { opacity: var(--tf-in, 1); transform: translate3d(0, calc((1 - var(--tf-in, 1)) * 3.2svh), 0); }

/* 3. the rail: title card and chapter list. One attribute, data-scrolled, moves both. */
.tf-rail { position: fixed; inset: 0; z-index: 5; pointer-events: none; color: var(--tf-light); --hero-x: 9.5vw; --hero-y: 27svh; --hero-scale: 2.2; --list-scale: 1.5; --title-w: 224px; }
.tf-rail > * { pointer-events: auto; }
.tf-title {                     /* the mark and the name. The name stands alone: no line under it */
  position: absolute; left: var(--tf-edge); top: var(--tf-edge); width: var(--title-w); display: grid; grid-template-columns: auto 1fr; gap: 0 9px; align-items: center;
  transform-origin: 0 0; transition: transform 1s var(--tf-ease), color 0.35s linear; will-change: transform;
}
.tf-mark { display: block; width: 30px; height: 30px; background: currentColor; -webkit-mask: url(mark.svg) center / contain no-repeat; mask: url(mark.svg) center / contain no-repeat; }
.tf-wordmark { font: 500 18px/1 var(--tf-sans); letter-spacing: -0.035em; white-space: nowrap; }
.tf-wordmark i { font-style: normal; font-weight: 300; opacity: 0.72; }
.tf-title::before {            /* the thin frame around the title while it is the hero */
  content: ""; position: absolute; inset: -11px -13px; border: 0.45px solid currentColor; opacity: 0; transition: opacity 0.5s linear;
}
.tf-rail[data-scrolled="false"] .tf-title { transform: translate3d(var(--hero-x), var(--hero-y), 0) scale(var(--hero-scale)); }
.tf-rail[data-scrolled="false"] .tf-title::before {            /* the frame runs down around the chapter list too */
  opacity: 0.6; bottom: calc(-11px - (var(--n, 5) * var(--row, 19px) * var(--list-scale) + 46px) / var(--hero-scale));
}

.tf-rail { --row: 19px; }
.tf-chapters {
  position: absolute; left: var(--tf-edge); bottom: var(--tf-edge); width: min(calc(var(--tf-rail) - 2 * var(--tf-edge)), 176px);
  margin: 0; padding: 0; list-style: none; counter-reset: tf-chapter; font: 700 16px/var(--row) var(--tf-sans); letter-spacing: -0.03em;
  transform-origin: 0 100%; transition: transform 1s var(--tf-ease), color 0.35s linear, width 1s var(--tf-ease);
}
.tf-rail[data-scrolled="false"] .tf-chapters {
  width: calc(var(--title-w) * var(--hero-scale) / var(--list-scale));
  transform: translate3d(var(--hero-x), calc(var(--hero-y) + 30px * var(--hero-scale) + 30px + var(--n, 5) * var(--row) * var(--list-scale) - 100svh + 2 * var(--tf-edge)), 0) scale(var(--list-scale));
}
.tf-chapters li { counter-increment: tf-chapter; }
.tf-chapters a { display: flex; align-items: baseline; gap: 6px; opacity: 0.74; transition: opacity 0.3s linear; }
.tf-chapters a::after { content: counter(tf-chapter, upper-roman); font: 400 12px/1 var(--tf-serif); letter-spacing: 0; min-width: 1.6em; text-align: right; }
.tf-chapters a i { flex: 1; align-self: center; height: 0; border-bottom: 1px dotted currentColor; clip-path: inset(-2px 100% -2px 0); transition: clip-path 0.5s var(--tf-ease); }
.tf-chapters a[aria-current="true"], .tf-chapters a:hover, .tf-chapters a:focus-visible { opacity: 1; }
.tf-chapters a[aria-current="true"] i, .tf-chapters a:hover i { clip-path: inset(-2px 0 -2px 0); }
.tf-rail[data-title-on="paper"] .tf-title, .tf-rail[data-list-on="paper"] .tf-chapters { color: var(--tf-ink); }
html:not(.tf-ready) .tf-title, html:not(.tf-ready) .tf-chapters { opacity: 0; }
.tf-title, .tf-chapters { transition-property: transform, color, opacity, width; }
html.tf-ready .tf-title { opacity: 1; transition: transform 1s var(--tf-ease), color 0.35s linear, opacity 1.6s linear 0.6s; }
html.tf-ready .tf-chapters { opacity: 1; transition: transform 1s var(--tf-ease), color 0.35s linear, width 1s var(--tf-ease), opacity 1.6s linear 1.4s; }

/* 4. paper sections: ink on the paper the canvas draws. At least 120svh tall, so only one torn edge is on screen. */
.tf-paper { position: relative; min-height: 130svh; padding: 30svh 0 34svh; color: var(--tf-ink); }
.tf-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--tf-gap); }
.tf-h { margin: 0; font: 400 clamp(2.8rem, 6.6vw, 7rem)/0.94 var(--tf-serif); letter-spacing: -0.035em; text-wrap: balance; }
.tf-quote { margin: 0; font: 400 clamp(1.7rem, 3.05vw, 3.4rem)/1.02 var(--tf-serif); letter-spacing: -0.022em; text-wrap: balance; }
.tf-label { margin: 0; font: 700 1rem/1.25 var(--tf-sans); letter-spacing: -0.01em; }
.tf-statement { margin: 0; font: 400 clamp(1.5rem, 2.1vw, 2.1rem)/1.12 var(--tf-serif); letter-spacing: -0.015em; text-wrap: pretty; }
.tf-caption { margin: 0; font: 400 1.125rem/1.25 var(--tf-serif); color: var(--tf-ink-soft); }   /* 18 px, never smaller */

/* a dictionary entry, as if cut from a dictionary: headword, how it is said, a thin rule, numbered senses.
   <div class="tf-entry" data-tf-cue>            (or data-tf-range="a b" to follow the chapter's timeline)
     <p class="tf-entry-word">transcend</p>
     <p class="tf-entry-say">/tran·send/ <i>·</i> verb</p>
     <ol><li>to go beyond one discipline.</li><li>beyond one lifetime.</li><li>beyond what's possible.</li></ol>
   </div>
   The senses arrive one at a time as --tf-show goes 0 to 1. It works on paper and, inside a .tf-block with a
   .tf-scrim, on paint. Add class tf-entry-open to show every sense at once. */
.tf-entry {
  --tf-show: clamp(0, calc((var(--tf-p, 1) - var(--tf-entry-from, 0.2)) * var(--tf-entry-rate, 3)), 1);
  --senses: 3; width: min(100%, 21em); font: 300 clamp(1.5rem, 2.25vw, 2.4rem)/1.34 var(--tf-plain); letter-spacing: 0.012em;
  font-feature-settings: "ss01";                       /* Jost's one-storey a, as in the reference picture */
}
.tf-entry[data-tf-range] { --tf-show: var(--tf-r, 1); }
.tf-entry.tf-entry-open { --tf-show: 1; }
.tf-entry-word { margin: 0; font: 400 clamp(3.4rem, 6.6vw, 7.4rem)/1 var(--tf-didone); letter-spacing: 0.07em; text-transform: lowercase; font-variation-settings: "opsz" 28; }
.tf-entry-say { margin: 0.9em 0 0; font-size: 0.86em; letter-spacing: 0.03em; }
.tf-entry-say i { font-style: normal; padding: 0 0.28em; }
.tf-entry-say::after { content: ""; display: block; height: 1px; margin: 1.5em 0 0; background: currentColor; opacity: 0.75; }
.tf-entry ol { margin: 1.5em 0 0; padding: 0; list-style: none; counter-reset: tf-sense; }
.tf-entry li {
  --on: clamp(0, calc((var(--tf-show) * (var(--senses) + 0.6) - var(--i, 0) - 0.3) * 1.5), 1);
  counter-increment: tf-sense; position: relative; padding-left: 1.7em; margin-top: 0.42em;
  opacity: var(--on); transform: translate3d(0, calc((1 - var(--on)) * 0.5em), 0);
}
.tf-entry li::before { content: counter(tf-sense); position: absolute; left: 0; top: 0.24em; font-size: 0.62em; letter-spacing: 0.04em; opacity: 0.8; }
.tf-entry li:nth-child(2) { --i: 1; } .tf-entry li:nth-child(3) { --i: 2; } .tf-entry li:nth-child(4) { --i: 3; } .tf-entry li:nth-child(5) { --i: 4; }
.tf-rule { height: 1px; background: currentColor; opacity: 0.22; border: 0; margin: 0; }
.tf-plate { margin: 0; }
.tf-plate img { display: block; width: 100%; height: auto; }
.tf-plate figcaption { margin-top: 10px; }

/* 5. a line drawing that draws itself with the scroll. Put class tf-draw and data-tf-cue (or data-tf-range) on
   the <svg> or its wrapper; give every <path> pathLength="1" and, to order the strokes, style="--d: 0.2"
   (0 first, about 0.6 last). Text inside fades in at its own --d. */
.tf-draw { --draw: clamp(0, calc((var(--tf-p, 1) - var(--tf-draw-from, 0.14)) * var(--tf-draw-rate, 3.1)), 1); }
.tf-draw[data-tf-range] { --draw: var(--tf-r, 1); }
.tf-draw path, .tf-draw line, .tf-draw circle, .tf-draw ellipse, .tf-draw polyline {
  fill: none; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: clamp(0, calc(1 - (var(--draw) - var(--d, 0)) * var(--tf-stroke-rate, 3.2)), 1);
}
.tf-draw text { opacity: clamp(0, calc((var(--draw) - var(--d, 0)) * 6), 1); }
@media (prefers-reduced-motion: reduce) { .tf-draw { --draw: 1; } }

/* 6. modes. flat: the canvas shows one still per chapter. css: no canvas at all. */
.tf-still { display: none; }
html[data-tf-mode="css"] .tf-stage { display: none; }
html[data-tf-mode="css"] .tf-still {
  display: block; position: sticky; top: 0; height: 100lvh; margin-bottom: -100lvh; z-index: 0;
  background: var(--tf-night) center / cover no-repeat;
}
html[data-tf-mode="css"] .tf-chapter + .tf-chapter .tf-still { -webkit-mask-image: linear-gradient(transparent, #000 16%); mask-image: linear-gradient(transparent, #000 16%); }
html[data-tf-mode="css"] .tf-opener { z-index: 1; }
html[data-tf-mode="css"] .tf-paper { z-index: 1; background: var(--tf-paper); }
html:not(.tf-on) .tf-paper { background: var(--tf-paper); }   /* no script at all: still readable */

@media (max-width: 760px) {
  :root { --tf-rail: 0px; --tf-edge: 18px; }
  body { font-size: 18px; }
  .tf-opener { padding-top: 40svh; }
  .tf-word { font-size: clamp(3.6rem, 19.5vw, 6rem); }
  .tf-lead, .tf-quote { font-size: clamp(1.75rem, 7.6vw, 2.3rem); max-width: 100%; }
  .tf-entry { font-size: 1.3rem; }
  .tf-entry-word { font-size: clamp(2.6rem, 13vw, 3.6rem); letter-spacing: 0.06em; }
  .tf-rail { --hero-x: 8px; --hero-y: 11svh; --hero-scale: 1.45; --n: 0; }   /* above the picture's focus, in the dark */
  .tf-rail[data-scrolled="false"] .tf-title::before { bottom: -11px; }
  .tf-chapters { display: none; }
  .tf-mark { width: 26px; height: 26px; }
  .tf-wordmark { font-size: 16px; }
  .tf-paper { padding: 24svh 0 28svh; }
}

@media (prefers-reduced-motion: reduce) {
  .tf-title, .tf-chapters, .tf-chapters a i { transition-duration: 0.01s !important; }
  [data-tf-cue].tf-rise { opacity: 1; transform: none; }
  .tf-entry { --tf-show: 1 !important; }
}
