/* /as: the essay page. The reading layout, the chrome, the notes and the
   section dots come from /lib/article/article.css. What is this page's own:
   the wave in the subtitle, and the recipe at the end (ritual.js): three
   drawings in the margin, and the recipe's own words as the controls.
   Colours, type scale and spacing tokens come from /style.css; nothing here
   sets a font-size outside that scale or adds a colour. */

/* ---------- the subtitle: design as ~, the missing noun ---------- */

.wave-slot { display: inline-block; }

/* the wave arrives a beat after the words: one clip reveal, left to right */
.essay__standfirst .wave {
  animation: wave-arrive 800ms cubic-bezier(0.25, 0.8, 0.25, 1) 700ms both;
}

@keyframes wave-arrive {
  from { clip-path: inset(-30% 100% -30% 0); }
  to   { clip-path: inset(-30% 0 -30% 0); }
}

html.og .essay__standfirst .wave { animation: none; }

/* ---------- the recipe's drawings ---------- */
/* The altar, the board, the spread (and, once taken, the polaroid): margin
   figures, level with what they belong beside on a wide screen, inline and
   compact on a phone. They keep the margin's width everywhere, so the type
   inside them stays the meta size: the drawings are 264 units wide. */

.ritual-fig {
  width: 16.5rem;
  max-width: 100%;
}

.ritual-fig[hidden] { display: none; }

/* inline (a phone, a tablet): close to what they belong to */
.essay__section > .ritual-fig { margin-top: 0.9em; }
.essay__section > .ritual-fig + :where(ul, ol) { margin-top: 0.9em; }
.essay__steps .ritual-fig { margin-top: 0.75em; }

/* in the margin, the lists keep their own spacing under their labels */
@media (min-width: 1100px) {
  .essay__section > .essay__muted + .ritual-fig + :where(ul, ol) { margin-top: 0.5em; }
}

/* things only ever drawn in ink: the stars, the wave on the card backs */
.fig .ritual-altar .altar__star,
.fig .ritual-spread .tarot__star,
.fig .ritual-spread .tarot__wave { fill: var(--ink); }

/* ---- the altar: two beeswax candles and a stick of incense ---- */

/* the honeycomb of the wax, faint */
.fig .ritual-altar .altar__hex {
  fill: none;
  stroke: var(--ink);
  stroke-width: 0.6;
  opacity: 0.32;
}

/* unlit: no flame, no ember, no smoke */
.ritual-altar .altar__fire,
.ritual-altar .altar__ember,
.ritual-altar .altar__smoke,
.ritual-altar .altar__wisp {
  opacity: 0;
  transition: opacity 400ms;
}

.ritual-altar .altar__fire {
  transform-box: fill-box;
  transform-origin: 50% 100%;
}

/* lit: the flames flicker */
.ritual-altar.is-lit .altar__fire {
  opacity: 1;
  animation: altar-flicker 1.3s ease-in-out infinite;
}

#altar-candle-2 .altar__fire { animation-duration: 1.55s; animation-delay: -0.4s; }

@keyframes altar-flicker {
  0%, 100% { transform: scale(1, 1) skewX(0deg); }
  22%  { transform: scale(0.94, 1.08) skewX(-4deg); }
  48%  { transform: scale(1.05, 0.94) skewX(3deg); }
  70%  { transform: scale(0.97, 1.05) skewX(-2deg); }
  86%  { transform: scale(1.03, 0.97) skewX(1deg); }
}

/* the incense: an ember, and smoke that rises in dashes and thins out */
.fig .ritual-altar .altar__smoke {
  fill: none;
  stroke: var(--ink-muted);
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-dasharray: 7 5;
}

.ritual-altar.is-incense .altar__ember { opacity: 1; }

.ritual-altar.is-incense .altar__smoke {
  opacity: 1;
  animation: altar-smoke 2.2s linear infinite;
}

.ritual-altar.is-incense .altar__smoke--2 { animation-duration: 2.9s; opacity: 0.7; }

@keyframes altar-smoke {
  to { stroke-dashoffset: -24; }
}

/* snuffed: one wisp from each wick, rising and gone */
.ritual-altar.is-snuffed .altar__wisp {
  animation: altar-wisp 1.9s ease-out forwards;
}

#altar-candle-2 .altar__wisp { animation-delay: 120ms; }

@keyframes altar-wisp {
  0%   { opacity: 0; transform: translateY(0); stroke-dashoffset: 1; }
  15%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-9px); stroke-dashoffset: 0; }
}

/* the same wisp, standing still: it only fades */
@keyframes altar-wisp-still {
  from { opacity: 1; }
  to   { opacity: 0; }
}

.fig .ritual-altar .altar__wisp {
  stroke: var(--ink-muted);
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}

/* ---- the board: the alphabet on an arc, yes, no, goodbye ---- */

/* the words sit over the planchette, as if through glass: a paper edge
   round each letter keeps the planchette's line from crossing it */
.fig .ritual-board text {
  paint-order: stroke;
  stroke: var(--paper);
  stroke-width: 4px;
  stroke-linejoin: round;
}

.fig .ritual-board .board__letters { letter-spacing: 0.06em; }

.fig .ritual-board .board__word {
  letter-spacing: 0.08em;
  transition: fill 500ms;
}

/* the word the planchette lands on is said in ink */
.fig .ritual-board[data-at="yes"] .board__yes,
.fig .ritual-board[data-at="no"] .board__no,
.fig .ritual-board[data-at="goodbye"] .board__goodbye { fill: var(--ink); }

/* placed by ritual.js; the slide is two transitions, set from there */
.ritual-board .planchette { transform-origin: 0 0; }

/* ---- the spread: three cards ---- */

.fig .ritual-spread .tarot__focus {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.5;
  stroke-dasharray: 4 4;
  opacity: 0;
}

.ritual-spread .tarot[role="button"] { cursor: pointer; }
.ritual-spread .tarot:focus { outline: none; }
.ritual-spread .tarot:focus-visible .tarot__focus { opacity: 1; }

/* a turn: the card narrows to its edge, changes side, widens again */
.ritual-spread .tarot__flip {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  transition: transform 170ms ease-in;
}

.ritual-spread .tarot__flip.is-turning { transform: scaleX(0.03); }
.ritual-spread .tarot__flip.is-opening { transition: transform 230ms ease-out; }

/* reversed: the face upside down */
.ritual-spread .tarot__face.is-reversed {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  transform: rotate(180deg);
}

.fig .ritual-spread .tarot__face .tarot__spirit { fill: var(--ink); }

/* the second material: the cards lift a few pixels, once, one after another */
.ritual-spread.is-lifting .tarot__lift { animation: tarot-lift 640ms ease-in-out both; }
.ritual-spread.is-lifting .tarot[data-i="1"] .tarot__lift { animation-delay: 90ms; }
.ritual-spread.is-lifting .tarot[data-i="2"] .tarot__lift { animation-delay: 180ms; }

@keyframes tarot-lift {
  0%, 100% { transform: translateY(0); }
  45% { transform: translateY(-5px); }
}

/* what the cards say, under them */
.spread__readings {
  margin: 0.55em 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--t-meta);
  line-height: 1.4;
  color: var(--ink-muted);
}

.spread__readings[hidden] { display: none; }

.essay .spread__readings li {
  margin: 0;
  font-size: var(--t-meta);
  line-height: 1.4;
}

.essay .spread__readings li + li { margin-top: 0.3em; }
.spread__num { color: var(--ink); }

/* ---------- the recipe's words, as controls ---------- */
/* Interactive words keep the text's size and colour and get a dotted
   underline and a pointer; nothing louder. */

.ritual-word {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  color: var(--ink);
  text-align: inherit;
  text-decoration: underline dotted;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 0.22em;
  cursor: pointer;
}

.ritual-word:hover { text-decoration-style: solid; text-decoration-thickness: from-font; }

/* ---- the materials: real checkboxes, drawn as hand-inked boxes ---- */

#ritual-materials.is-live > li::before { content: none; }

.material { cursor: pointer; }

.material__check {
  position: absolute;
  left: -1.4em;
  top: 0.28em;
  width: 1em;
  height: 1em;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.material__ink {
  position: absolute;
  left: -1.4em;
  top: 0.28em;
  width: 1em;
  height: 1em;
  overflow: visible;
  pointer-events: none;
}

.material__ink path {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* the tick is a pen stroke, drawn in */
.material__ink .material__tick {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 220ms ease-out;
}

.material__check:checked + .material__ink .material__tick { stroke-dashoffset: 0; }

.material__check:focus-visible + .material__ink {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 2px;
}

.material__aside[hidden] { display: none; }

/* ---- step 1: the artefact, a word you can type; decorations around it ---- */

.ritual-artefact {
  position: relative;
  display: inline-block;
  max-width: 100%;
}

.ritual-artefact input {
  max-width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  color: var(--ink);
  text-decoration: underline dotted;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 0.22em;
}

.ritual-artefact input::placeholder {
  color: var(--ink);
  opacity: 1;
  text-decoration: underline dotted;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 0.22em;
}

.ritual-artefact input:focus-visible { outline-offset: 3px; }

/* measures the word, so the field is as wide as what it holds */
.ritual-artefact__mirror {
  position: absolute;
  left: 0;
  top: 0;
  white-space: pre;
  visibility: hidden;
  pointer-events: none;
}

/* a sparkle as ritual.js draws it: one em square, on the line like the glyph
   it stands for; alone in its own box (round the word, in flight), a block */
.sparkle-glyph {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.12em;
  overflow: visible;
}

.sparkle .sparkle-glyph,
.sparkle-flyer .sparkle-glyph { display: block; }

.sparkle {
  position: absolute;
  z-index: 1;
  font-size: var(--t-base);
  line-height: 1;
  color: var(--ink);
  pointer-events: none;
  transform: translate(-50%, -50%) rotate(var(--r, 0deg));
  animation: sparkle-in 240ms ease-out both;
}

@keyframes sparkle-in {
  from { transform: translate(-50%, -50%) rotate(var(--r, 0deg)) scale(0); }
}

/* past nine, the oldest falls off the line */
.sparkle.is-falling { animation: sparkle-fall 760ms cubic-bezier(0.5, 0, 0.9, 0.5) forwards; }

@keyframes sparkle-fall {
  to { transform: translate(-50%, 1.8em) rotate(calc(var(--r, 0deg) + 80deg)); opacity: 0; }
}

/* ---- step 2: the blanks draw cards ---- */

/* empty, a blank is the essay's line of underscores, drawn dotted */
.ritual-blank.is-empty {
  color: transparent;
  text-decoration-color: var(--ink);
  text-decoration-skip-ink: none;
}

/* ---- step 3: three lines, like a form; touch one and the step skips itself ---- */

.ritual-lines {
  display: grid;
  gap: 0.1em;
  max-width: 26em;
  margin: 0 0 0.15em;
}

.ritual-line {
  display: block;
  width: 100%;
  height: 1.45em;
  margin: 0;
  padding: 0;
  border: 0;
  border-bottom: 2px dotted var(--ink);
  border-radius: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  cursor: text;
}

.ritual-line:focus-visible { outline-offset: 3px; }

.is-skipped .ritual-step3 {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

.is-skipped .ritual-line {
  border-bottom-color: var(--ink-muted);
  cursor: default;
}

.ritual-skipped[hidden] { display: none; }

/* ---- step 4: the photograph ---- */

/* the flash: the page, white, for a moment */
.ritual-flash {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: var(--mark);
  pointer-events: none;
  animation: ritual-flash 560ms ease-out forwards;
}

@keyframes ritual-flash {
  0%   { opacity: 0; }
  10%  { opacity: 0.95; }
  100% { opacity: 0; }
}

/* the polaroid: white, slightly turned, as wide as the margin allows (room
   round it for the turn and the stamp) */
.ritual-fig--polaroid { padding: 0.8rem 0.8rem 0.6rem 0.1rem; }

.polaroid {
  position: relative;
  width: 15.25rem;
  max-width: 100%;
  padding: 0.55rem 0.55rem 0;
  border: 1.5px solid var(--ink);
  border-radius: 2px;
  background: var(--mark);
  transform: rotate(2.5deg);
}

/* the snapshot: the altar from above, flash on. A picture, drawn 264 units
   square and shown at the polaroid's width; softened by less than a pixel */
.polaroid__photo {
  border: 1.5px solid var(--ink);
  background: var(--paper);
  line-height: 0;
}

.fig .polaroid__shot {
  display: block;
  width: 100%;
  height: auto;
  overflow: hidden;
  filter: blur(0.35px);
}

.fig .polaroid__shot .shot__name { font-size: var(--t-base); }
.fig .polaroid__shot .shot__sparkle { color: var(--ink); }
.fig .polaroid__shot .shot__star { fill: var(--ink); }

/* the date, as the camera prints it: lit segments */
.fig .polaroid__shot .shot__date {
  fill: var(--mark);
  stroke: var(--ink);
  stroke-width: 0.7;
  stroke-linejoin: round;
}

/* under it, by hand, small */
.polaroid .polaroid__note {
  margin: 0;
  padding: 0.45rem 0.15rem 0.65rem;
  font-size: var(--t-meta);
  font-style: italic;
  line-height: 1.3;
  color: var(--ink);
  transform: rotate(-1.5deg);
  transform-origin: 0 50%;
}

/* a rubber stamp across the corner */
.polaroid .polaroid__stamp {
  position: absolute;
  top: -0.55rem;
  right: -0.95rem;
  margin: 0;
  padding: 0.12em 0.4em 0.05em 0.55em;
  border: 4px double var(--ink);
  border-radius: 4px;
  font-size: var(--t-base);
  line-height: 1.2;
  letter-spacing: 0.16em;
  color: var(--ink);
  transform: rotate(-13deg);
}

/* it drops in, turning as it lands; the stamp follows */
.ritual-fig--polaroid.is-dropping .polaroid {
  animation: polaroid-drop 760ms cubic-bezier(0.2, 0.75, 0.3, 1.12) both;
}

@keyframes polaroid-drop {
  from { opacity: 0; transform: translateY(-2.5rem) rotate(-8deg); }
  35%  { opacity: 1; }
  to   { opacity: 1; transform: translateY(0) rotate(2.5deg); }
}

.ritual-fig--polaroid.is-dropping .polaroid__stamp {
  animation: polaroid-stamp 240ms cubic-bezier(0.55, 0, 0.8, 0.3) 820ms both;
}

@keyframes polaroid-stamp {
  from { opacity: 0; transform: rotate(-5deg) scale(1.9); }
  to   { opacity: 1; transform: rotate(-13deg) scale(1); }
}

/* ---------- the ritual complete: the spirits grant you academic success ---------- */
/* Hidden until every step is done (without the script, always). Then it
   is the payoff: larger than the text, centred, glitter either side in the
   old ~*~ way; the reader's sparkles fly over from step 1 and land in it,
   and all of it twinkles. Its small print sits directly under it. */

.ritual-success[hidden],
.ritual-disclaimer[hidden] { display: none !important; }

/* in motion, unseen while the page scrolls to it: it pops when it's there */
.ritual-success.is-due,
.ritual-disclaimer.is-due { opacity: 0; }

.essay .ritual-success {
  position: relative;
  margin-top: 1.6em;
  font-size: var(--t-intro);
  line-height: 1.3;
  letter-spacing: -0.005em;
  text-align: center;
  text-wrap: balance;
}

.ritual-success .glitter { white-space: nowrap; }

.ritual-success .glitter__star {
  display: inline-block;
  margin: 0 0.03em;
  opacity: 0;
  transition: opacity 280ms;
}

.ritual-success .glitter__star.is-here { opacity: 1; }

.ritual-success.is-granted { animation: success-pop 700ms cubic-bezier(0.2, 0.7, 0.3, 1.25) both; }

@keyframes success-pop {
  from { opacity: 0; transform: scale(0.9); }
}

.ritual-success.is-twinkling .glitter__star {
  animation: success-twinkle 1.9s ease-in-out infinite;
  animation-delay: calc(var(--i) * -0.31s);
}

@keyframes success-twinkle {
  0%, 100% { opacity: 1; transform: none; }
  50% { opacity: 0.3; transform: scale(0.7) rotate(20deg); }
}

/* a sparkle in flight, from step 1 to the line */
.sparkle-flyer {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 25;
  font-size: var(--t-base);
  line-height: 1;
  color: var(--ink);
  pointer-events: none;
}

/* the asterisk: a plain one, the size and tone of the raised numerals but
   a little lower (a star sits high by itself) */
.ritual-success .ritual-star {
  position: relative;
  top: -0.25em;
  font-size: var(--t-meta);
  line-height: 0;
  vertical-align: baseline;
  color: var(--ink-muted);
}

/* the small print it marks: directly under the line, centred with it,
   muted, the meta size; in motion it comes a moment after the line */
.essay .ritual-disclaimer {
  margin-top: 0.75em;
  font-size: var(--t-meta);
  line-height: 1.4;
  color: var(--ink-muted);
  text-align: center;
  text-wrap: balance;
}

.ritual-disclaimer.is-granted { animation: disclaimer-in 600ms ease-out 350ms both; }

@keyframes disclaimer-in {
  from { opacity: 0; }
}

/* ---------- motion ---------- */
/* Reduced: no flicker, no flips, no flash, no slide (the planchette jumps),
   nothing falls, flies or twinkles; the smoke stands still, the polaroid,
   the line and its small print are simply there. */

@media (prefers-reduced-motion: reduce) {
  .essay__standfirst .wave { animation: none; }
  .ritual-altar.is-lit .altar__fire,
  .ritual-altar.is-incense .altar__smoke { animation: none; }
  .ritual-altar .altar__fire,
  .ritual-altar .altar__smoke { transition: none; }
  .ritual-altar.is-snuffed .altar__wisp { animation: altar-wisp-still 1.9s ease-in forwards; }
  .ritual-spread .tarot__flip,
  .ritual-spread .tarot__flip.is-opening { transition: none; }
  .ritual-spread.is-lifting .tarot__lift { animation: none; }
  .fig .ritual-board .board__word { transition: none; }
  .material__ink .material__tick { transition: none; }
  .sparkle,
  .sparkle.is-falling { animation: none; }
  .ritual-fig--polaroid.is-dropping .polaroid,
  .ritual-fig--polaroid.is-dropping .polaroid__stamp { animation: none; }
  .ritual-flash { display: none; }
  .ritual-success.is-granted,
  .ritual-disclaimer.is-granted,
  .ritual-success.is-twinkling .glitter__star { animation: none; }
  .ritual-success .glitter__star { transition: none; }
}
