:root {
  --ink: #4b3b2d;
  --ink-wet: #30251c;
  --ink-diary: #2a221c;
  --faded: #a08a66;
  --print: #6e5a40;
  --hand: 'Cedarville Cursive', 'Zhi Mang Xing', 'Ma Shan Zheng', 'PingFang SC', 'Noto Sans CJK SC', cursive;
  /* A dip pen, a little uneven, the way the diary writes back. Not the hand they write in. */
  --hand-diary: 'La Belle Aurore', 'Ma Shan Zheng', 'Zhi Mang Xing', 'PingFang SC', 'Noto Sans CJK SC', cursive;
  --size: clamp(1.6rem, 7vw, 2.15rem);
  --size-diary: clamp(2rem, 8.2vw, 2.55rem);
  color-scheme: light;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  background: #120c09;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

/* ---------- the desk and the book ---------- */

.desk {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    radial-gradient(ellipse at 50% 40%, rgb(70 45 25 / .55), transparent 70%),
    #120c09;
  opacity: 0;
  transition: opacity 1.4s ease;
}
.ready .desk { opacity: 1; }

/* Phone: the right-hand page fills the screen, the leather cover peeks round the edge. */
.book {
  position: relative;
  display: flex;
  width: 100%;
  height: 100%;
  padding:
    max(.5rem, env(safe-area-inset-top, 0px))
    max(.55rem, env(safe-area-inset-right, 0px))
    max(.5rem, env(safe-area-inset-bottom, 0px))
    0;
  background: url(/img/leather.webp) #221915;
  background-size: 192px;
}
.verso { display: none; }

.page {
  position: relative;
  flex: 1;
  overflow: hidden;
  background: url(/img/paper.webp) #e5d3aa;
  background-size: 320px;
  cursor: text;
}

/* Age: darker edges, foxing, the gutter where the pages meet the spine. */
.page::before,
.page::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.page::before {
  background:
    radial-gradient(ellipse 60% 45% at 50% 48%, transparent 55%, rgb(120 78 32 / .30) 100%),
    radial-gradient(circle at 82% 14%, rgb(140 90 40 / .16), transparent 3.5rem),
    radial-gradient(circle at 12% 88%, rgb(130 85 35 / .14), transparent 5rem),
    radial-gradient(circle at 68% 76%, rgb(150 100 45 / .10), transparent 1.2rem),
    radial-gradient(circle at 30% 30%, rgb(150 100 45 / .07), transparent .6rem);
  box-shadow: inset 0 0 2.5rem rgb(90 55 20 / .35);
}
.recto::after {
  background: linear-gradient(90deg, rgb(40 24 10 / .42), rgb(60 38 15 / .12) 1.6rem, transparent 4.5rem);
}
.verso::after {
  background: linear-gradient(270deg, rgb(40 24 10 / .42), rgb(60 38 15 / .12) 1.6rem, transparent 4.5rem);
}

/* The stack of pages under this one. */
.recto {
  box-shadow:
    1px 0 0 #cdb98f, 2px 0 0 #a8926a, 3px 0 0 #d6c49c, 4px 0 0 #9d8761,
    5px 0 0 #d1bf96, 6px 1px 0 #8f7a56,
    0 1px 0 #cdb98f, 0 2px 0 #a8926a, 0 3px 0 #d3c199;
}

/* Desktop: an open book on the desk. */
@media (min-width: 52rem) and (min-height: 32rem) {
  .book {
    width: min(94vw, 72rem, calc(88vh * 1.45));
    height: auto;
    aspect-ratio: 1.45;
    padding: .7rem .8rem .8rem;
    gap: 0;
    border-radius: .5rem;
    box-shadow: 0 2.2rem 4rem rgb(0 0 0 / .65), 0 .4rem 1rem rgb(0 0 0 / .5), inset 0 0 0 1px rgb(255 255 255 / .04);
  }
  .verso { display: block; }
  .verso {
    box-shadow:
      -1px 0 0 #cdb98f, -2px 0 0 #a8926a, -3px 0 0 #d6c49c, -4px 0 0 #9d8761,
      -5px 0 0 #d1bf96, -6px 1px 0 #8f7a56,
      0 1px 0 #cdb98f, 0 2px 0 #a8926a, 0 3px 0 #d3c199;
  }
  .page { border-radius: 2px; }
  :root { --size: clamp(1.9rem, 2.6vw, 2.7rem); --size-diary: clamp(2.2rem, 3vw, 3rem); }
}

/* ---------- printed date ---------- */

.date {
  position: absolute;
  top: max(2.2rem, 6%);
  left: 12%;
  right: 9%;
  padding-bottom: .45rem;
  border-bottom: 3px double rgb(110 90 64 / .45);
  font: 1.05rem/1 'IM Fell English SC', Georgia, serif;
  letter-spacing: .14em;
  color: var(--print);
  text-align: center;
  opacity: .8;
  user-select: none;
}

/* How to begin, in small print at the foot of the page. Gone after the first line. */
.whisper {
  position: absolute;
  bottom: max(1.6rem, 5%);
  left: 12%;
  right: 9%;
  font: .85rem/1 'IM Fell English SC', Georgia, serif;
  letter-spacing: .18em;
  color: var(--print);
  text-align: center;
  opacity: 0;
  transition: opacity 2s ease;
  user-select: none;
}
.whisper.shown { opacity: .55; }

/* ---------- writing ---------- */

/* The quill's line stays put. The diary's line stays put, under it.
   They are never on the page together: the answer fades out when typing starts,
   and their ink fades out before the answer fades in. */
.writing {
  position: absolute;
  top: 12%;
  left: 8%;
  right: 8%;
  bottom: 4%;
}

.line {
  position: absolute;
  left: 0;
  right: 0;
  margin: 0;
  min-height: 1.5em;
  font-size: var(--size);
  line-height: 1.35;
  text-align: center;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  /* Ink sits in the paper: its grain shows through the strokes. */
  mix-blend-mode: multiply;
}
.you {
  top: 16%;
  /* Room for the script's loops inside the box, so a mask never clips them. */
  padding: .7em .2em;
  font-family: var(--hand);
  color: var(--ink);
}
.diary,
.you.out {
  top: 44%;
  padding: .55em .35em .4em;
}
.diary {
  font-family: var(--hand-diary);
  font-size: var(--size-diary);
  line-height: 1.35;
  color: var(--ink-diary);
}
.diary a { color: inherit; font: .55em var(--hand); margin-left: .5em; }


/* Their ink goes on wet and dries. */
.g { animation: ink .7s ease-out both, dry 2.6s ease-out; }
@keyframes ink {
  0% { opacity: 0; text-shadow: 0 0 .35em rgb(48 37 28 / .8); }
  30% { opacity: 1; text-shadow: 0 0 .14em rgb(48 37 28 / .6); }
  100% { opacity: 1; text-shadow: 0 0 .02em rgb(48 37 28 / .35); }
}
@keyframes dry { from { color: var(--ink-wet); } }

/* A letter waits for the quill, then appears under the nib as it moves across. */
.g.pending { opacity: 0; animation: none; }
.g.done { animation: none; }
.g.inking {
  /* Room for loops and swashes that overhang the letter's box; the margins cancel it in layout. */
  padding: .7em .3em;
  margin: 0 -.3em;
  -webkit-mask: linear-gradient(90deg, #000 40%, transparent 60%) no-repeat;
  mask: linear-gradient(90deg, #000 40%, transparent 60%) no-repeat;
  -webkit-mask-size: 250% 100%;
  mask-size: 250% 100%;
  animation: pen var(--d, 200ms) linear both, dry 2.6s ease-out;
}
@keyframes pen {
  from { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
  to { -webkit-mask-position: 0 0; mask-position: 0 0; }
}

/* The page drinks their line; the diary's words ooze up from the middle. Every browser gets the
   eased fade and blur. Where CSS masks work (all current browsers, iOS included) the ink also
   breaks up in blots, stepped through a 30-frame sprite. */
.soak { animation: sink 1.7s ease-in-out forwards; }
@keyframes sink {
  0% { opacity: 1; filter: blur(0); color: var(--ink); }
  45% { color: var(--faded); }
  100% { opacity: 0; filter: blur(1.2px); color: var(--faded); }
}
.veiled { opacity: 0; }
.emerge { animation: surface var(--dur, 2s) ease-out both; }
@keyframes surface {
  0% { opacity: 0; filter: blur(1.4px); color: var(--ink-wet); }
  30% { opacity: 1; filter: blur(.5px); }
  55% { filter: blur(0); }
  70% { color: var(--ink-wet); }
  100% { opacity: 1; filter: blur(0); color: var(--ink-diary); }
}
@supports (mask-image: url(#m)) or (-webkit-mask-image: url(#m)) {
  .soak {
    -webkit-mask: url(/img/dissolve.png) 0 0 / 3000% 100% no-repeat;
    mask: url(/img/dissolve.png) 0 0 / 3000% 100% no-repeat;
    animation: sink 1.7s ease-in-out forwards, frames 1.7s steps(30, jump-none) forwards;
  }
  .emerge {
    -webkit-mask: url(/img/ooze.png) 0 0 / 3000% 100% no-repeat;
    mask: url(/img/ooze.png) 0 0 / 3000% 100% no-repeat;
    animation: surface var(--dur, 2s) ease-out both, frames-in var(--dur, 2s) steps(27, jump-none) both;
  }
}
/* The reveal skips the sprite's first, nearly empty frames so the first blots show at once. */
@keyframes frames-in {
  from { -webkit-mask-position: 10.3% 0; mask-position: 10.3% 0; }
  to { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
}
@keyframes frames {
  from { -webkit-mask-position: 0 0; mask-position: 0 0; }
  to { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
}
.hint { --ink-diary: #8d7b66; --ink-wet: #6c5b4a; }

/* Letters in flight during a reshuffle. */
.flying {
  position: absolute;
  margin: 0;
  font-size: var(--size);
  white-space: pre;
  pointer-events: none;
  will-change: transform;
}
.settled { animation: glow 2.4s ease-out; }
@keyframes glow {
  0% { text-shadow: 0 0 .5em rgb(120 20 10 / .5); }
  100% { text-shadow: none; }
}

/* ---------- the quill ---------- */

.quill {
  position: absolute;
  left: 0;
  top: 0;
  width: 3.3rem;
  height: auto;
  transform-origin: 50% 99.3%;
  rotate: 34deg;
  pointer-events: none;
  filter: drop-shadow(.6rem .7rem .3rem rgb(40 22 8 / .45)) drop-shadow(0 0 1px rgb(60 40 20 / .6));
  transition: left .25s ease-out, top .25s ease-out, opacity .8s, translate 1s cubic-bezier(.3, .7, .3, 1), rotate 1s;
}
.quill.up { translate: 1.4rem -2.6rem; rotate: 40deg; opacity: 0; }
/* About to hand the line in after a pause: the nib rises a little. Any key puts it back. */
.quill.poised { translate: .25rem -.7rem; transition: translate .4s ease-out, opacity .8s; }
.quill.tracing { transition: opacity .8s; }
.quill.idle { animation: idle 3.2s ease-in-out infinite; }
@keyframes idle {
  0%, 100% { translate: 0 0; }
  50% { translate: .1rem -.35rem; }
}

/* The real input is an invisible layer over the whole writing area: a touch anywhere lands on it,
   so phones open the keyboard natively. 16px keeps iOS from zooming. It is never seen. */
.pen {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  outline: 0;
  opacity: 0;
  font-size: 16px;
  color: transparent;
  -webkit-text-fill-color: transparent;
  caret-color: transparent;
  background: transparent;
  cursor: text;
}
/* A reply carrying a link sits above the input so the link can be tapped. */
.line:has(a) { z-index: 3; }

.caret { display: inline-block; width: 0; }

@media (prefers-reduced-motion: reduce) {
  .g, .soak, .emerge, .settled, .quill.idle { animation-duration: .01s !important; }
  .quill { transition: none; }
}
