/*
 * THE SUBTITLES — a pure overlay under the eye.
 *
 * THE EYE DOES NOT MOVE. That is the binding constraint of this whole feature
 * and the only way to break `position-eye-on-window-open`, which was closed as
 * working the day before this was asked for. So nothing in this file touches
 * `.eye`, `body`, `#hint` or any panel: the block is `position: fixed`, it is
 * therefore outside body's flex flow entirely, and there is no arrangement of
 * text inside it that can push anything.
 *
 * ANCHORED BY ITS TOP EDGE, always. When the sentence closes, the ruby band
 * appears over the top line and that line gets TALLER — anchored by its bottom
 * or its centre, the block would grow up into the eye. Anchored by its top it
 * can only ever grow downward, into the part of the screen he pointed at when
 * he said the bottom is normally empty anyway.
 *
 * It follows the eye rather than sitting at a fixed height: the eye travels
 * (push-to-talk rests it high, an open window sends it to the top strip), and
 * a caption left behind in the middle of the screen would be a line of text
 * attached to nothing. Same easing as the eye, so they travel together.
 */

#subtitles {
  position: fixed;
  left: 50%;
  translate: -50%;
  /* Under the eye's resting place: its centre plus its own radius, plus a gap.
     The radius is eye.css's `width: min(46vw, 220px)` halved. */
  top: calc(50% + min(23vw, 110px) + 1.5rem);
  /* Clipped before it reaches the hint at the bottom of the screen, so a long
     sentence runs out of room instead of running over the one line that is
     always there. `top` and `bottom` together give the box a definite height,
     which is what makes `overflow` mean anything. */
  bottom: 3.4rem;
  width: min(88vw, 34rem);
  overflow: hidden;

  /* Behind the windows (10) and the eye (20). The panels are opaque and cover
     the screen, so a caption running under an open window is simply not seen
     rather than fighting the window's own text for the same pixels. */
  z-index: 5;

  /* TEXT TO READ, NOT TO TOUCH. The box is tall and mostly empty; without this
     it would swallow every tap in the lower half of the screen — including the
     two flies in the bottom corners. */
  pointer-events: none;

  display: flex;
  flex-direction: column;
  align-items: center;
  /* THE SEPARATION BETWEEN THE TWO LINES IS SPATIAL FIRST. Colour is a second
     aid and never the mechanism: it fails for colour-blind readers and washes
     out against the eye's glow, which changes colour with HAL's state. */
  gap: .6rem;

  text-align: center;
  /* NOT the monospace body font: it has no CJK coverage, so Japanese and
     Chinese would fall back per-glyph and the ruby band would sit crooked over
     characters from a different family. */
  font-family: system-ui, -apple-system, 'Segoe UI', 'Noto Sans', 'Hiragino Sans',
               'Yu Gothic', 'Noto Sans CJK JP', sans-serif;

  transition: top var(--stage-ease);
}

/* `display: flex` above outguns the user agent's `[hidden] { display: none }`,
   so the empty block has to be hidden explicitly — otherwise the gap under the
   eye would be reserved for a caption that is not there, which is the visible
   hole this feature must not leave during the student's turn. */
#subtitles[hidden] { display: none; }

/* The eye's two other resting places, from eye.css. Kept in step by hand: the
   caption has no way to measure the eye without reading layout back, and a
   caption that measured would still be one frame behind the travel. */
html[data-mode="ptt"] #subtitles { top: calc(12dvh + min(46vw, 220px) + 1.5rem); }
html[data-stage="panel"] #subtitles {
  top: calc(var(--stage-strip) / 2 + var(--stage-eye) / 2 + 1rem);
}

/*
 * THE TOP LINE — what HAL is actually saying, in the language being practised.
 * Primary: larger, brighter, and the one the ruby band belongs to.
 *
 * Near-white and neutral on purpose. Every colour here is independent of
 * --eye: the eye's hue is the user's choice and its brightness is driven frame
 * by frame from the audio, so text tinted from it would shift under its own
 * subtitles every time HAL spoke.
 */
#subline {
  /*
   * IT RUNS OUT OF ROOM AT THE TOP, NEVER AT THE BOTTOM.
   *
   * A tutor's turn is several sentences and the caption carries all of them,
   * so on a phone the line outgrows the strip under the eye routinely, not
   * rarely — three lines of Japanese with a ruby band is already more than
   * fits. Clipped the ordinary way, what is hidden is the newest text: the
   * caption freezes on the opening words while HAL talks on, which is the
   * exact opposite of a line that keeps up with the voice.
   *
   * `column-reverse` lays the words out from the bottom edge, so the overflow
   * — and the clip — happens at the top and the words being spoken NOW are
   * always the ones on screen. `min-height: 0` is what allows the shrinking at
   * all: a column flex item defaults to min-height:auto and refuses to go
   * below its own content, which would push the line straight past the block's
   * bottom edge and over the hint.
   *
   * The translation underneath is capped rather than unbounded (see #subtrans):
   * it is the support line, so when a scaffolded turn makes both lines long it
   * is the one that gives room up, not the one being spoken right now.
   */
  display: flex;
  flex-direction: column-reverse;
  min-height: 0;
  overflow: hidden;

  font-size: clamp(1rem, 4.6vw, 1.45rem);
  /* Room for the band to sit over the kanji without the ruby of a wrapped
     second line landing on the first line's characters. */
  line-height: 1.75;
  color: #e9ebf1;
  /* The eye's glow reaches this far when it peaks; the shadow keeps the line
     legible through it without needing a plate behind the text. */
  text-shadow: 0 1px 5px #000, 0 0 16px rgba(0, 0, 0, .8);
  overflow-wrap: anywhere;
}

/*
 * FURIGANA — real ruby, so a reading stays over its own kanji when the line
 * wraps. Small text sitting on the characters, not a line of its own: the
 * block is two lines plus a band, never three lines.
 */
#subline ruby { ruby-position: over; ruby-align: center; }
#subline rt {
  font-size: .5em;
  line-height: 1.1;
  color: #b9bdc7;
  letter-spacing: .02em;
  text-shadow: 0 1px 4px #000;
}

/*
 * THE BOTTOM LINE — the translation into his own language. Secondary by size,
 * by weight and by colour, all three, so the eye is never buried under what
 * reads as a paragraph.
 */
#subtrans {
  /*
   * BOUNDED, BECAUSE IT IS NO LONGER ONE SENTENCE OF MODEL OUTPUT.
   *
   * A beginner turn is spoken in two languages and the gloss HAL says out loud
   * is about as long as the phrase it glosses (see voice/caption-split.js), so
   * this line now grows with the voice too. Left unbounded it would take the
   * block's whole height between them and clip the practice line out of
   * existence — the support line burying the one being read, which is the
   * hierarchy backwards. Capped and clipped the same way the top line is: at
   * the top, so its newest words are the ones on screen.
   */
  display: flex;
  flex-direction: column-reverse;
  min-height: 0;
  max-height: 40%;
  overflow: hidden;

  font-size: clamp(.74rem, 3.1vw, .95rem);
  line-height: 1.45;
  color: #868b95;
  letter-spacing: .03em;
  text-shadow: 0 1px 4px #000;
  overflow-wrap: anywhere;
}
#subtrans[hidden] { display: none; }
