/* Product face. Debug families stay off this sheet (loaded with the dock). */
@font-face {
  font-family: "Iosevka Aile";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/iosevka-aile/iosevka-aile-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Iosevka Aile";
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("../fonts/iosevka-aile/iosevka-aile-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Source Code Pro";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/source-code-pro/source-code-pro-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Source Code Pro";
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("../fonts/source-code-pro/source-code-pro-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/manrope/manrope-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("../fonts/manrope/manrope-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("../fonts/manrope/manrope-latin-600-normal.woff2") format("woff2");
}

:root {
  /* Flat dark — one surface; structure via hairlines, not nested gray cards */
  --bg: #181818;
  --paper: #181818;
  --ink: #f2f2f2;
  --muted: #a8a8a8;
  --line: #333333;
  --accent: #c45c5c; /* errors / destructive only */
  --chrome: #b8b8b8; /* inactive UI chrome — never competes with score colors */
  /* One OKLCH ramp: 0% red, 25% orange, 50% yellow, 100% green.
     Score % interpolates these in js/main.js (SCORE_RAMP). Trust marks
     use the red / yellow / green stops. */
  --ramp-red: oklch(58% 0.170 27);
  --ramp-orange: oklch(70% 0.160 64);
  --ramp-yellow: oklch(84% 0.150 102);
  --ramp-green: oklch(72% 0.150 150);
  --good: var(--ramp-green);
  --warn: var(--ramp-yellow);
  --bad: var(--ramp-red);
  --chip: #2a2a2a;
  /* Product face is Manrope. Iosevka stays in the stack for glyphs Manrope lacks. */
  --font-sans: "Manrope", "Noto Sans", "Segoe UI", system-ui, sans-serif;
  --font-mono: "Manrope", "Iosevka Aile", "Noto Sans", "Segoe UI", system-ui, sans-serif;
  --font-ui: var(--font-sans);
  /* Lautschrift. Defaults to the product face; the debug dock can swap it. */
  --font-ipa: var(--font-mono);
  --ui-text-scale: 1;
  /* Hairline further down from the input/results boundary (rem). */
  --divider-offset: 0.5rem;
  /* Extra air below the hairline (rem; does not move the rule). */
  --input-results-gap: 0.5rem;
  --score-col: max(4.35rem, 44px);
  /* Trust frame: hairline around syl group + IPA */
  --trust-frame: 38%;
  --trust-outline: 1px;
  --trust-outline-offset: 2px;
  /* How far the colored frame sits outside the analysis content box */
  --trust-outset: calc(var(--trust-outline) + var(--trust-outline-offset));
  --content-inline: 0.85rem;
  /* Gap between E-014 Auftakt and match span (hairline sits in the middle). */
  --auftakt-gap: 0.32rem;
  /* Centered content column: phone ≈ full width; larger screens capped. */
  --content-side: max(0.85rem, 2.5vmin);
  --content-col-cap: 24rem;
  --content-col-width: min(100%, var(--content-col-cap));
  /* Input first-line metrics (chrome align + flex underlay pull). */
  --composer-pad-top: 0.55rem;
  --composer-line: calc(1.1rem * 1.2);
  --input-text-band: calc(1.1rem * 1.2);
  --input-text-block: var(--composer-line);
  /* Multi-reading stacked mark rows */
  --reading-stack-gap: 0.18rem;
  /* Debug dock open height (vh); default ≈ ⅓ viewport. */
  --debug-dock-height: 33.333vh;
  --chrome-right: 0.35rem;
  /* Larger press target; glyph size shared by the gear and menu icons. */
  --chrome-btn: 2.05rem;
  --chrome-icon: 1.45rem;
  --chrome-gap: 0.1rem;
  /* Gear only; live width from JS (--chrome-cluster / --chrome-fade-ramp) */
  --chrome-cluster: 2.4rem;
  --chrome-fade-ramp: 1.75rem;
  --analysis-pair-gap: 0.72rem;
  /* Clear air between stacked trust outlines */
  --analysis-stack-gap: calc(var(--trust-outset) * 2 + 0.45rem);
  /* Horizontal air between trust outlines (outsets + a sliver of clear) */
  --analysis-word-gap: calc(var(--trust-outset) * 2 + 0.4rem);
  /* One vertical step between rhyme/result blocks */
  --rhyme-air: 0.28rem;
  /* Within a block: word→bars a bit tighter; bars→IPA closer still */
  /* Target visual air (overridden in px by font-ink.js per face). */
  --brace-air: 0.06rem;
  --brace-ipa-air: 0.06rem;
  /* Debug ±rem nudges (0 = leave product defaults). */
  --brace-air-nudge: 0rem;
  --brace-ipa-air-nudge: 0rem;
  --rhyme-air-nudge: 0rem;
  --brace-air-eff: calc(var(--brace-air) + var(--brace-air-nudge));
  --brace-ipa-air-eff: calc(var(--brace-ipa-air) + var(--brace-ipa-air-nudge));
  --rhyme-air-eff: calc(var(--rhyme-air) + var(--rhyme-air-nudge));
  --ortho-ink-below: 0px;
  --ipa-ink-above: 0px;
}

* { box-sizing: border-box; }

html {
  /*
    Product text scale via root rem (not CSS zoom). Zoom on .page broke
    hit-testing against the input iframe (settings + composer clicks died
    whenever --ui-text-scale ≠ 1).
  */
  font-size: calc(16px * var(--ui-text-scale, 1));
}

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  /* Manrope = UI Latin; Noto Sans = IPA / rare glyphs. */
  font-family: var(--font-ui);
  line-height: 1.45;
  direction: ltr;
  color-scheme: dark;
  font-feature-settings: "kern" 1, "liga" 1;
}

body {
  font-size: 1rem;
}

/* Bottom debug strip — own scroll; page scroll stops above it.
   No CSS zoom here: zoom breaks grid row sizing (controls spill into
   neighboring rows). Lengths in this block are px (16px design base).
   rem would follow html font-size and scale the text-size slider with
   the setting it controls, until the thumb is clipped and unusable. */
.debug-dock {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: var(--debug-dock-height, 33.333vh);
  min-height: 25vh;
  max-height: 50vh;
  margin: 0;
  padding: 0;
  background: var(--surface-1, #1e1e1e);
  border-top: 0;
  border-bottom: 0;
  color: var(--ink);
  font-family: var(--font-mono);
  /* Fixed px — independent of --ui-text-scale / root rem. */
  font-size: 12.5px;
  line-height: 1.35;
  z-index: 40;
  overflow: hidden;
  box-sizing: border-box;
}

.debug-dock-resize {
  position: relative;
  z-index: 5;
  flex: 0 0 auto;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--bg);
  cursor: ns-resize;
  touch-action: none;
  user-select: none;
}

.debug-dock-resize::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  border-top: 1px dashed var(--line);
}

.debug-dock-resize:hover,
.debug-dock-resize:focus-visible,
html[data-dock-resize="1"] .debug-dock-resize {
  background: var(--surface-2, #242424);
  outline: 1px solid var(--focus, color-mix(in srgb, var(--ink) 70%, transparent));
  outline-offset: -1px;
}

html[data-debug="1"] .debug-dock,
html[data-debug="1"] .debug-dock[hidden] {
  display: flex !important;
  flex-direction: column;
}

html[data-debug="1"],
html[data-debug="1"] body {
  height: 100%;
  overflow: hidden;
}

html[data-debug="1"] .page {
  /* Page scrolls in its own pane — never into the dock. */
  height: calc(100dvh - var(--debug-dock-height, 33.333vh));
  max-height: calc(100dvh - var(--debug-dock-height, 33.333vh));
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 1.4rem;
  box-sizing: border-box;
}

.debug-dock-bar {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10.4px;
  width: 100%;
  max-width: min(576px, 100%);
  margin: 0 auto;
  padding: 8.8px 16px 13.6px;
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  box-sizing: border-box;
}

/* Never let flex shrink rows — that crushed controls into each other. */
.debug-dock-bar > * {
  flex: 0 0 auto;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

.debug-dock-head {
  display: block;
  position: static;
  margin: 0;
  padding: 0;
  background: transparent;
}

.debug-dock-tag {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 100%;
  min-height: 44px;
  margin: 0;
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: center;
  color: var(--muted);
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  padding: 0 12px;
  cursor: pointer;
  z-index: 4;
}

.debug-dock-tag:hover,
.debug-dock-tag:focus-visible {
  color: var(--ink);
  background: transparent;
  outline: 1px solid var(--focus, color-mix(in srgb, var(--ink) 70%, transparent));
  outline-offset: -1px;
}

.debug-dock-tag:active {
  color: var(--ink);
  background: var(--surface-2, #242424);
}

.debug-font-controls {
  flex-wrap: nowrap;
  align-items: stretch;
  justify-content: flex-end;
  gap: 8px;
}

/* Horizontal pair: ▲ (prev) left, ▼ (next) right — large separate targets */
.debug-font-cycle {
  display: inline-flex;
  flex-direction: row;
  flex: 0 0 auto;
  align-items: stretch;
  gap: 5.6px;
  border: 0;
  overflow: visible;
}

.debug-font-controls .debug-font-step {
  flex: 0 0 auto;
  min-width: 44px;
  min-height: 44px;
  padding: 5.6px 8px;
  font-size: 18.4px;
  line-height: 1;
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--surface-2, #242424);
}

.debug-font-controls .debug-font-step + .debug-font-step {
  border-left: 1px solid var(--line);
}

.debug-font-controls .debug-select {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  max-width: none;
  min-height: 44px;
  align-self: stretch;
}

.debug-font-controls .debug-font-disable {
  flex: 0 0 auto;
  min-width: 52px;
  min-height: 44px;
  padding: 5.6px 11.2px;
  align-self: stretch;
  margin-right: 0;
  order: 0;
}

.debug-row {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr);
  align-items: center;
  column-gap: 13.6px;
  row-gap: 5.6px;
  min-height: 44px;
  height: auto;
  overflow: visible;
}

.debug-row > .debug-field-label {
  grid-column: 1;
  justify-self: start;
  align-self: center;
}

.debug-row-controls {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 6.4px 10.4px;
  min-width: 0;
  max-width: 100%;
}

.debug-field {
  display: inline-flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6.4px 8.8px;
  margin: 0;
}

.debug-field-label {
  color: var(--muted);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 11px;
  flex: 0 0 auto;
  line-height: 1.2;
}

.debug-select {
  font: inherit;
  font-size: 12.5px;
  color: var(--ink);
  background: var(--surface-2, #242424);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 4.48px 7.2px;
  min-width: 192px;
  min-height: 44px;
  max-width: min(352px, 100%);
  flex: 1 1 auto;
}

.debug-select:focus-visible {
  outline: 1px solid var(--focus, color-mix(in srgb, var(--ink) 70%, transparent));
  outline-offset: 2px;
}

.debug-seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 2px;
  flex: 0 0 auto;
  min-height: 44px;
}

.debug-seg-btn {
  font: inherit;
  font-size: 12.5px;
  color: var(--muted);
  background: var(--surface-2, #242424);
  border: 0;
  padding: 4.48px 11.2px;
  min-height: 44px;
  min-width: 44px;
  cursor: pointer;
  white-space: nowrap;
}

.debug-seg-btn + .debug-seg-btn {
  border-left: 1px solid var(--line);
}

.debug-seg-btn:hover {
  color: var(--ink);
}

.debug-seg-btn:focus-visible {
  outline: 1px solid var(--focus, color-mix(in srgb, var(--ink) 70%, transparent));
  outline-offset: 2px;
}

.debug-seg-btn.is-on {
  color: var(--bg);
  background: var(--ink);
}

.debug-tog-btn {
  border: 1px solid var(--line);
  border-radius: 2px;
}

.debug-slider {
  display: grid;
  grid-template-columns: 8.75rem 3.6rem 2.5rem;
  align-items: center;
  column-gap: 0.4rem;
  margin: 0;
  flex: 0 0 auto;
  width: calc(8.75rem + 3.6rem + 2.5rem + 0.8rem);
}

.debug-slider:has(.debug-scale-prefix) {
  grid-template-columns: 1rem 8.75rem 3.6rem 2.5rem;
  width: calc(1rem + 8.75rem + 3.6rem + 2.5rem + 1.2rem);
}

.debug-slider input[type="range"] {
  width: 8.75rem;
  height: 1.35rem;
  min-height: 1.35rem;
  margin: 0;
  accent-color: var(--ink);
  justify-self: stretch;
}

.debug-slider output,
.debug-slider .debug-val-input {
  font: inherit;
  font-variant-numeric: tabular-nums;
  width: 3.6rem;
  min-width: 3.6rem;
  max-width: 3.6rem;
  text-align: right;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid transparent;
  padding: 0;
  margin: 0;
  border-radius: 0;
  appearance: none;
  -moz-appearance: textfield;
  box-sizing: border-box;
}

.debug-slider .debug-val-input:hover {
  border-bottom-color: var(--line);
  cursor: text;
}

.debug-slider .debug-val-input:focus {
  outline: none;
  border-bottom-color: var(--muted);
  color: var(--ink);
}

.debug-slider .debug-val-input::-webkit-outer-spin-button,
.debug-slider .debug-val-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.debug-px-unit {
  color: var(--muted);
  width: 2.5rem;
  text-align: left;
  white-space: nowrap;
}

.debug-row-toggles {
  gap: 12px 22.4px;
}

.debug-slider[hidden] {
  display: none !important;
}

.debug-scale-prefix {
  color: var(--muted);
}

.page {
  max-width: none;
  width: 100%;
  min-height: 100dvh;
  margin: 0 auto;
  /* Tight top once results are up — idle centering uses .workspace pad */
  /* No shared max-prefix gutter (0.10.187). Safe pad is only the *deficit*
     when per-row hang would clip past the viewport (iPhone). JS remeasures
     after the pad, because a centered column only shifts partway. */
  --auftakt-safe-pad: 0px;
  padding-top: 0.65rem;
  padding-bottom: 1.4rem;
  padding-left: calc(
    var(--content-side) + env(safe-area-inset-left, 0px) + var(--auftakt-safe-pad)
  );
  padding-right: calc(var(--content-side) + env(safe-area-inset-right, 0px));
  display: flex;
  flex-direction: column;
  /* Text scale = html rem (--ui-text-scale). Do not zoom .page — see html{}. */
  box-sizing: border-box;
}

.page.is-hero {
  --hero-page-pad: 1.2rem;
  padding-top: var(--hero-page-pad);
}

.lang-switch {
  display: inline-flex;
  gap: 0.15rem;
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 0.1rem;
}

.lang-btn {
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0.15rem 0.45rem;
  cursor: pointer;
}

.lang-btn:hover {
  color: var(--ink);
}

.lang-btn.is-active {
  color: var(--bg);
  background: var(--ink);
}

.ver {
  flex-shrink: 0;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  letter-spacing: 0.04em;
}

.site-foot {
  width: var(--content-col-width);
  max-width: 100%;
  margin-top: auto;
  margin-inline: auto;
  padding-top: 1.1rem;
  padding-bottom: max(0.55rem, env(safe-area-inset-bottom, 0px));
  border-top: 0;
  font-size: 0.55rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 1.1rem;
  color: color-mix(in srgb, var(--muted) 26%, transparent);
  min-height: 0;
  flex-shrink: 0;
  box-sizing: border-box;
}

/* Idle: a bit more air above the whisper link */
.page.is-hero .site-foot {
  padding-top: 2.2rem;
}

.legal-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 0;
}

.legal-link:hover,
.legal-link:focus-visible {
  color: color-mix(in srgb, var(--muted) 58%, transparent);
}

/* In-app impressum. Same document, so the lexicon stays in memory. */
.legal-view {
  display: none;
  width: min(36rem, calc(100% - 2.4rem));
  margin: 0 auto;
  padding: 2.4rem 0 3.2rem;
  box-sizing: border-box;
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 1rem;
  line-height: 1.5;
}

html[data-view="impressum"] .page,
html[data-view="impressum"] #debug-dock {
  display: none !important;
}

html[data-view="impressum"] .legal-view {
  display: block;
}

.legal-view a { color: inherit; }

.legal-view .back {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.82rem;
}

.legal-view .back:hover,
.legal-view .back:focus-visible {
  color: var(--ink);
}

.legal-view h1 {
  margin: 1.6rem 0 0.2rem;
  font-size: 1.45rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}

.legal-view .lead {
  margin: 0 0 1.6rem;
  color: var(--muted);
  font-size: 0.92rem;
}

.legal-view h2 {
  margin: 1.8rem 0 0.55rem;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.legal-view address { font-style: normal; }
.legal-view p { margin: 0.4rem 0; }

.legal-view .contact {
  display: grid;
  gap: 0.15rem;
}

.legal-view ul {
  margin: 0.2rem 0 0;
  padding: 0;
  list-style: none;
}

.legal-view li {
  margin: 0;
  padding: 0.7rem 0;
  border-top: 1px solid var(--line);
}

.legal-view li strong { font-weight: 500; }

.legal-view .lic {
  display: block;
  margin-top: 0.15rem;
  color: var(--muted);
  font-size: 0.92rem;
}

.composer-row {
  display: flex;
  align-items: stretch;
  gap: 0;
  width: 100%;
}

.workspace {
  width: var(--content-col-width);
  max-width: 100%;
  margin-inline: auto;
  box-sizing: border-box;
  border: 0;
  border-radius: 0;
  background: transparent;
  /* visible: E-014 Auftakt hang uses negative margin into .page gutter */
  overflow: visible;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  min-height: 0;
  /* Idle: float input toward mid-viewport (thumb / mouse reach) */
  padding-top: 0.15rem;
  /* Width never transitions by default — subpixel L/R jitter on typing.
     Random-word calm path enables transition via html.is-col-animating. */
  transition: padding-top 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

html.is-col-animating .workspace,
html.is-col-animating .site-foot {
  transition:
    width 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    padding-top 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

/* While the column eases, keep old ink from wrapping/jittering horizontally. */
html.is-col-animating .composer,
html.is-col-animating .input-host,
html.is-col-animating #q {
  overflow-x: hidden;
}

/* Random-word swap: hide input + results until one width ease finishes. */
html.is-random-swap #q,
html.is-random-swap #q-ghost,
html.is-random-swap #units,
html.is-random-swap #results {
  opacity: 0 !important;
  pointer-events: none !important;
  transition: none !important;
}

.page.is-hero .workspace {
  /* Opener line, gear, and loader bar share one center: viewport mid. */
  padding-top: max(
    0px,
    calc(
      50dvh
      - var(--hero-page-pad, 1.2rem)
      - var(--pad-top, var(--composer-pad-top, 0.55rem))
      - (var(--input-text-band, var(--composer-line, calc(1.1rem * 1.2))) / 2)
    )
  );
}

/* Input + optional toolbar + input-analysis */
.query-shell {
  position: relative;
}

.composer {
  position: relative;
  z-index: 2;
  isolation: isolate;
  flex: 1 1 auto;
  min-width: 0;
  /* pad-top + 1.1rem/1.2 line — no bottom pad (marks supply --brace-air) */
  --composer-pad-top: 0.55rem;
  --composer-line: calc(1.1rem * 1.2);
  height: calc(var(--composer-pad-top) + var(--composer-line));
  min-height: calc(var(--composer-pad-top) + var(--composer-line));
  border: 0;
  border-radius: 0;
  background: transparent;
  overflow: visible;
  /* Height snaps — avoids clipping the previous line while growing downward. */
  transition: border-color 0.15s ease;
}

.composer.is-loading {
  /* Same box as the ready field, so the bar and the opener share one line. */
  height: calc(
    var(--pad-top, var(--composer-pad-top, 0.55rem)) +
      var(--input-text-band, var(--composer-line))
  );
  min-height: calc(
    var(--pad-top, var(--composer-pad-top, 0.55rem)) +
      var(--input-text-band, var(--composer-line))
  );
  border-color: transparent;
}

.composer.is-loading .lex-load {
  position: absolute;
  inset: 0;
  overflow: visible;
  justify-content: flex-start;
}

.composer.is-error {
  height: auto;
  min-height: 9.25rem;
  box-shadow: none;
}

.composer.is-ready {
  /* Never collapse: absolute CE/host do not stretch auto height. */
  height: calc(
    var(--composer-pad-top) + var(--input-text-band, var(--composer-line))
  );
  min-height: calc(
    var(--composer-pad-top) + var(--input-text-band, var(--composer-line))
  );
  border-color: transparent;
  background: transparent;
  overflow: visible;
}

.input-host {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-height: none;
  overflow: visible;
  opacity: 1;
  pointer-events: none;
}

.input-host[hidden] {
  display: none;
}

.input-host.is-entering {
  animation: input-enter 0.42s ease both;
}

@keyframes input-enter {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Single-ink: contenteditable is the only glyph layer. */
.q-ce {
  position: absolute;
  inset: 0;
  z-index: 1;
  box-sizing: border-box;
  margin: 0;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--ink);
  caret-color: var(--ink);
  /* Avoid font-shorthand unitless line-height — it can collapse composer math. */
  font-family: var(--font-mono);
  font-size: calc(1.1rem * var(--input-text-scale, 1));
  font-weight: 400;
  line-height: var(--input-text-band, calc(1.1rem * 1.2));
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  padding: var(--pad-top, var(--composer-pad-top, 0.55rem))
    var(--chrome-cluster, 2.85rem) 0 var(--pad-left, 0.85rem);
  white-space: pre-wrap;
  overflow-wrap: normal;
  word-break: keep-all;
  overflow: hidden;
  pointer-events: auto;
  cursor: text;
  -webkit-user-modify: read-write-plaintext-only;
}

.q-ce:focus,
.q-ce:focus-visible {
  outline: none;
}

.q-ce::selection {
  background: transparent;
  color: var(--ink);
}

/* Decorations sit above CE only for mark hit-targets (pe none elsewhere). */
.q-decor.units {
  position: absolute;
  inset: 0;
  z-index: 2;
  margin: 0;
  padding: 0;
  pointer-events: none;
  overflow: visible;
}

.decor-word {
  position: absolute;
  left: 0;
  top: 0;
  box-sizing: border-box;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.decor-word .units-readings,
.decor-word .unit-choice.is-solo,
.decor-word .analysis-stack {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* Syllable cells: flex row sized to CE advances in JS (same brace→IPA as results). */
.decor-word .syl-track,
.decor-word .syl-word {
  position: relative;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
  width: 100%;
  min-height: 0;
}

.decor-word .syl-cell {
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.q-sel-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}

.q-sel-layer > i {
  position: fixed;
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 1px;
  background: color-mix(in srgb, #6ea8fe 45%, transparent);
  pointer-events: none;
}

.q-ghost {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: auto;
  height: calc(
    var(--pad-top, var(--composer-pad-top, 0.55rem)) +
      var(--input-text-band, calc(1.1rem * 1.2))
  );
  z-index: 4;
  box-sizing: border-box;
  padding: var(--pad-top, var(--composer-pad-top, 0.55rem))
    var(--chrome-cluster, 2.85rem) 0 var(--pad-left, 0.85rem);
  pointer-events: none;
  color: color-mix(in srgb, var(--ink) 72%, transparent);
  font-family: var(--font-mono);
  font-size: calc(1.1rem * var(--input-text-scale, 1));
  font-weight: 400;
  line-height: var(--input-text-band, calc(1.1rem * 1.2));
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  white-space: nowrap;
  overflow: hidden;
  /* Class-driven visibility — NOT [hidden], which used display:none!important
     and silently killed the finished typewriter. */
  display: none;
}

.q-ghost.is-live {
  display: block;
  height: auto;
  white-space: pre-wrap;
  overflow: visible;
}

.q-ghost-caret {
  display: inline-block;
  width: 1.5px;
  height: 1.05em;
  margin-left: 1px;
  background: color-mix(in srgb, var(--ink) 55%, transparent);
  vertical-align: -0.1em;
  animation: ghost-blink 1.05s step-end infinite;
}

@keyframes ghost-blink {
  50% { opacity: 0; }
}

.qframe {
  display: none;
}

/*
  Fade ramp + chrome sit on the first input line (optical center with glyphs),
  not a taller 2.75rem strip that drifts above/below the text.
*/
.input-fade {
  position: absolute;
  z-index: 2;
  /* Optical center of the first text band (JS sets --chrome-top from glyphs). */
  top: var(
    --chrome-top,
    calc(
      var(--pad-top, var(--composer-pad-top, 0.55rem)) +
        (var(--input-text-band, var(--composer-line, 1.1rem * 1.2)) - var(--chrome-btn)) /
          2
    )
  );
  bottom: auto;
  height: var(--chrome-btn);
  right: var(--chrome-cluster);
  width: var(--chrome-fade-ramp);
  pointer-events: none;
  background: linear-gradient(
    to right,
    transparent 0%,
    color-mix(in srgb, var(--paper) 40%, transparent) 40%,
    var(--paper) 92%
  );
  opacity: 1;
  transition:
    right 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    width 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.18s ease;
}

/* While editing, show the caret end — hide the idle fade */
.composer.is-focused .input-fade,
.input-host.is-focused ~ .input-fade {
  opacity: 0;
}

.input-chrome {
  position: absolute;
  z-index: 30;
  /* Center gear on first-line glyphs — --chrome-top from syncChromeToFirstGlyph. */
  top: var(
    --chrome-top,
    calc(
      var(--pad-top, var(--composer-pad-top, 0.55rem)) +
        (var(--input-text-band, var(--composer-line, 1.1rem * 1.2)) - var(--chrome-btn)) /
          2
    )
  );
  bottom: auto;
  height: var(--chrome-btn);
  right: var(--chrome-right);
  left: auto;
  width: max-content;
  max-width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: var(--chrome-gap);
  pointer-events: auto;
}

/* Opaque plate under icons (= invisible divider from the text lane) */
.input-chrome::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: auto;
  height: 100%;
  left: 0;
  right: calc(-1 * var(--chrome-right));
  background: var(--paper);
  pointer-events: none;
}

.input-chrome > * {
  pointer-events: auto;
}

.input-settings {
  position: relative;
  flex: 0 0 auto;
  width: var(--chrome-btn);
  height: var(--chrome-btn);
  margin: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: color-mix(in srgb, var(--ink) 72%, transparent);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
}

.input-settings:hover,
.input-settings:focus-visible {
  color: color-mix(in srgb, var(--muted) 88%, var(--ink));
  outline: none;
}

.input-settings:active {
  color: var(--ink);
}

.input-settings[aria-expanded="true"] {
  color: var(--ink);
}

.input-settings-icon,
.tool-icon {
  width: var(--chrome-icon);
  height: var(--chrome-icon);
  display: block;
  overflow: visible;
  flex: 0 0 auto;
  opacity: 1;
  shape-rendering: geometricPrecision;
}

.tool-icon .icon-fill,
.input-settings-icon .icon-fill {
  fill: currentColor;
  stroke: none;
}

.input-settings-icon .icon-knob {
  fill: var(--paper);
  stroke: currentColor;
}

/* Multi-reading hint while analysis is off: muted ↔ ink */
@keyframes chrome-attention {
  0%,
  100% {
    color: color-mix(in srgb, var(--muted) 62%, transparent);
  }
  50% {
    color: var(--ink);
  }
}

.input-settings.is-attention,
.tool-btn.is-attention {
  animation: chrome-attention 1.55s ease-in-out infinite;
}

.input-settings.is-attention:hover,
.input-settings.is-attention:focus-visible,
.tool-btn.is-attention:hover,
.tool-btn.is-attention:focus-visible {
  animation: none;
  color: var(--ink);
}

/*
  Tools expand left from the settings cluster (no second row / no divider).
  Closed: width 0. Open: slide out beside the gear.
*/
/* Gear menu. Width stays out of the icon cluster — the panel is absolute. */
.settings-menu {
  position: absolute;
  top: calc(100% + 0.45rem);
  right: 0;
  z-index: 41;
  width: max-content;
  min-width: 12.5rem;
  max-width: calc(100vw - 1.5rem);
  box-sizing: border-box;
  margin: 0;
  padding: 0.28rem;
  display: flex;
  flex-direction: column;
  gap: 0.08rem;
  background: var(--paper);
  color: var(--ink);
  border: 0;
  border-radius: 2px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent),
    0 0.6rem 1.4rem color-mix(in srgb, var(--ink) 8%, transparent);
}

.settings-menu[hidden] {
  display: none !important;
}

.settings-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.65rem;
  width: 100%;
  white-space: nowrap;
  min-height: 44px;
  margin: 0;
  padding: 0.35rem 0.55rem 0.35rem 0.7rem;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 0.84rem;
  line-height: 1.2;
  text-align: left;
  cursor: pointer;
}

.settings-item:disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}

.settings-item:hover,
.settings-item:focus-visible {
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  outline: none;
}

.settings-item.is-on {
  color: var(--ink);
}

.settings-item .tool-icon {
  width: var(--chrome-icon);
  height: var(--chrome-icon);
  flex: 0 0 auto;
}

/* Opacity on a <g>, not on the shape. Chrome drops SVG-shape opacity when a
   transform is on the same element, which left circle and crescent both drawn. */
.moon-icon .moon-layer {
  transition: opacity 0.32s ease;
}

.moon-icon .moon-full {
  opacity: 1;
}

.moon-icon .moon-crescent {
  opacity: 0;
  visibility: hidden;
}

#toggle-ultra.is-on .moon-full {
  opacity: 0;
  visibility: hidden;
}

#toggle-ultra.is-on .moon-crescent {
  opacity: 1;
  visibility: visible;
}

.tool-btn {
  flex: 0 0 auto;
  width: var(--chrome-btn);
  height: var(--chrome-btn);
  margin: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 2px;
  background: transparent;
  /* Same muted ink for every tool — no fill-heavy icon looking darker. */
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}

.tool-btn:hover,
.tool-btn:focus-visible {
  color: color-mix(in srgb, var(--muted) 88%, var(--ink));
  outline: none;
}

.tool-btn.is-on {
  color: var(--ink);
}

.tool-btn.is-on:hover,
.tool-btn.is-on:focus-visible {
  color: var(--ink);
}

.tool-btn:disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}

/* Apple HIG ~44×44 hit, glyph stays the chrome size. */
.tool-btn,
.input-settings,
.lex-reload {
  position: relative;
}

.tool-btn::before,
.input-settings::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

.tool-btn:focus-visible,
.input-settings:focus-visible,
.lex-reload:focus-visible {
  outline: 1px solid color-mix(in srgb, var(--ink) 70%, transparent);
  outline-offset: 2px;
}

.algo-panel {
  position: absolute;
  top: calc(100% + 0.4rem);
  right: 0;
  z-index: 40;
  width: min(17.5rem, calc(100vw - 1.5rem));
  min-width: 14rem;
  max-width: min(22.5rem, calc(100vw - 1.5rem));
  box-sizing: border-box;
  margin: 0;
  padding: 0.5rem 0.55rem 0.4rem;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.18rem;
  text-align: left;
  background: var(--paper);
  color: var(--ink);
  border: 0;
  border-radius: 2px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent),
    0 0.6rem 1.4rem color-mix(in srgb, var(--ink) 8%, transparent);
}

.algo-panel[hidden] {
  display: none;
}

.algo-panel-title {
  margin: 0 0 0.1rem;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
}

.algo-mode {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  justify-content: flex-end;
  width: 100%;
  margin: 0.1rem 0 0.25rem;
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
  border-radius: 2px;
  overflow: hidden;
}

.algo-mode-chip {
  flex: 1 1 0;
  margin: 0;
  padding: 0.42rem 0.45rem;
  min-height: 2.4rem;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 0.78rem;
  line-height: 1.15;
  letter-spacing: 0.01em;
  text-align: center;
  cursor: pointer;
}

.algo-mode-chip + .algo-mode-chip {
  border-left: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}

.algo-mode-chip:hover,
.algo-mode-chip:focus-visible {
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  outline: none;
}

.algo-mode-chip.is-on {
  color: var(--paper);
  background: var(--ink);
}

.algo-mode-chip.is-on:hover,
.algo-mode-chip.is-on:focus-visible {
  color: var(--paper);
  background: var(--ink);
}

.algo-opt-group {
  display: flex;
  flex-direction: column;
  gap: 0.14rem;
  margin-top: 0.2rem;
  padding-top: 0.35rem;
  border-top: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}

.algo-opt {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0;
  min-height: 1.85rem;
  font-size: 0.82rem;
  line-height: 1.25;
  text-align: left;
  cursor: pointer;
}

.algo-opt input {
  margin: 0;
  flex: 0 0 auto;
  order: 2;
}

.algo-opt > span {
  flex: 1 1 auto;
  order: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.05rem;
  text-align: left;
  min-width: 0;
}

.algo-opt.is-nested {
  padding-left: 0.9rem;
}

.algo-opt.is-disabled {
  color: var(--faint);
  cursor: default;
}

.algo-opt.is-disabled input {
  opacity: 0.45;
  cursor: default;
}

.algo-opt > span.lang-opt-line {
  flex-direction: row;
  align-items: baseline;
  gap: 0.4rem;
}

.lang-germanized {
  margin: 0.05rem 0 0.1rem;
  font-size: 0.75rem;
  line-height: 1.35;
  color: var(--faint);
}

.lang-germanized[hidden] {
  display: none;
}

.algo-opt-sub {
  display: none;
}

.algo-opt-hint {
  display: none;
}

.algo-opt-select {
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
  margin-top: 0.2rem;
  padding-top: 0.4rem;
  border-top: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
  cursor: default;
}

.algo-opt-select > span {
  flex: 0 0 auto;
}

.algo-opt-mirror {
  margin: 0.05rem 0 0.1rem;
  padding-bottom: 0.1rem;
}

.algo-opt-mirror[hidden] {
  display: none !important;
}

.debug-panel .algo-opt-group {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.algo-select {
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 0.28rem 0.4rem;
  font: inherit;
  font-size: 0.82rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-radius: 2px;
  text-align: left;
}

.algo-opt.is-debug {
  margin-top: 0.15rem;
  padding-top: 0.4rem;
  border-top: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}

.combo-combine {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.75rem;
  margin: 0 0 0.35rem;
  color: var(--muted);
  font-size: 0.78rem;
}

.combo-combine[hidden] {
  display: none !important;
}

.combo-combine-count {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  color: var(--ink);
  font-size: 0.82rem;
}

.combo-combine-count[hidden] {
  display: none !important;
}

.combo-combine button,
.combo-combine-primary {
  margin: 0;
  padding: 0.2rem 0;
  min-height: 2rem;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.combo-combine-primary {
  color: var(--ink);
  font-weight: 600;
}

.combo-combine-primary.is-on {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.combo-combine button:hover,
.combo-combine button:focus-visible,
.combo-combine-primary:hover,
.combo-combine-primary:focus-visible {
  color: var(--ink);
  outline: none;
}

.combo-combine-out {
  margin: 0;
  flex: 1 1 12rem;
  min-width: 0;
  font-size: 0.72rem;
  opacity: 0.8;
}

.combo-combine-mode {
  margin: 0;
  flex: 1 1 100%;
  font-size: 0.72rem;
  opacity: 0.7;
}

.combo-combine-mode[hidden] {
  display: none !important;
}

.combo-combine-semantics {
  margin: 0;
  flex: 0 0 auto;
  font-size: 0.72rem;
  opacity: 0.85;
}

.combo-combine-semantics[hidden] {
  display: none !important;
}

.combo-combine-llm-help {
  margin: 0.25rem 0 0;
  padding: 0 0 0 1.1rem;
  flex: 1 1 100%;
  font-size: 0.72rem;
  opacity: 0.75;
  line-height: 1.35;
}

.combo-combine-llm-help[hidden] {
  display: none !important;
}

.combo-combine-paste {
  flex: 1 1 100%;
  box-sizing: border-box;
  min-height: 2.4rem;
  margin: 0.35rem 0 0;
  padding: 0.35rem 0.45rem;
  border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-radius: 2px;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  color: var(--ink);
  font: inherit;
  font-size: 0.75rem;
  resize: vertical;
}

.combo-combine-expert {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.35rem 0.5rem;
  width: 100%;
}

.debug-scheme-label {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.5rem;
  flex: 1 1 100%;
  font-size: 0.78rem;
  color: var(--muted);
}

.debug-lattice-expert-row[hidden] {
  display: none !important;
}

.debug-lattice-metrics {
  margin: 0;
  padding: 0.25rem 0;
  max-width: 100%;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, "Iosevka Aile", monospace;
  font-size: 0.7rem;
  line-height: 1.35;
  color: var(--muted);
}

.debug-hint {
  color: var(--muted);
  font-size: 0.72rem;
}

.debug-metrics-row .debug-row-controls {
  flex: 1 1 12rem;
  min-width: 0;
}

.rhyme[data-medial-stretch="1"] {
  box-shadow: inset 2px 0 0 color-mix(in srgb, var(--ink) 45%, transparent);
}

.prefs-toggle {
  flex: 0 0 auto;
  width: 3.35rem;
  align-self: stretch;
  min-height: 3.35rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--paper);
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.15s ease;
}

.composer-row.is-loading .prefs-toggle,
.composer-row.is-error .prefs-toggle {
  border-color: var(--line);
}

.prefs-toggle:hover {
  color: var(--ink);
  border-color: var(--chrome);
}

.prefs-toggle[aria-expanded="true"] {
  color: var(--bg);
  background: var(--ink);
  border-color: var(--ink);
}

.prefs-toggle-icon {
  display: block;
}

.status {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.composer.is-loading .input-chrome,
.composer.is-error .input-chrome,
.composer:has(.lex-load:not([hidden])) .input-chrome {
  visibility: hidden;
  pointer-events: none;
}

/* Progress covers the composer. The bar is pinned to the opener line. */
.lex-load {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  gap: 1.2rem;
  margin: 0;
  /* Same lane as the opener: left pad, right gear cluster. */
  padding: 0.45rem var(--chrome-cluster, 2.85rem) 0.55rem var(--pad-left, 0.85rem);
  border: 0;
  background: transparent;
  pointer-events: none;
  opacity: 1;
  text-align: center;
  transition: opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Fade ramp would soft-clip the bar’s right edge — keep it off while the
   loader is on screen (including the exit dissolve into the text field). */
.composer.is-loading .input-fade,
.composer.is-error .input-fade,
.composer:has(.lex-load:not([hidden])) .input-fade,
/* Overlay words already clear the chrome cluster — fade would ghost them. */
html[data-flex-input="1"] .input-fade {
  opacity: 0;
}

.lex-load.is-exiting {
  opacity: 0;
}

/* Finish: fill flashes to ink, then the bar collapses to a caret at the left. */
.lex-load.is-morph .lex-load-brand,
.lex-load.is-morph .lex-load-label {
  opacity: 0;
  transition: opacity 140ms linear;
}

.lex-load.is-morph .lex-load-fill {
  background: var(--ink);
}

.lex-load.is-morph .lex-load-track {
  transform-origin: left center;
  transform: scaleX(0.01);
  transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1);
}

.lex-load[hidden] {
  display: none;
}

.composer.is-ready .lex-load:not(.is-exiting) {
  display: none;
}

.lex-load-label {
  margin: 0;
  font-size: 0.82rem;
  letter-spacing: 0.01em;
  color: var(--muted);
  text-align: center;
}

.lex-load-label[hidden] {
  display: none;
}

.lex-load-track {
  position: relative;
  /* Integer px — rem heights blur to uneven thickness on DPR screens */
  width: 100%;
  height: 4px;
  border: 0;
  background: var(--chip);
  overflow: hidden;
  flex-shrink: 0;
  border-radius: 0;
}

.lex-load-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 4px;
  width: 100%;
  background: color-mix(in srgb, var(--ink) 55%, var(--muted));
  transform-origin: left center;
  transform: scaleX(0);
  /* CSS transition keeps moving if the main thread stalls briefly. */
  transition: transform var(--dur-3, 340ms) cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}

.lex-load-track.is-indeterminate .lex-load-fill {
  /* Sweep via left (not translate) so height stays crisp */
  width: 32%;
  transform: none;
  transition: none;
  /* Ease in-out sweep — accel at entry, soft exit past the track end */
  animation: lex-indeterminate 1.7s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
}

/* Hidden until fonts and the field width have settled (data-boot=loading). */
html:not([data-boot="loading"]):not([data-boot="error"]) .lex-load-track,
html:not([data-boot="loading"]):not([data-boot="error"]) .lex-load-brand,
html:not([data-boot="loading"]):not([data-boot="error"]) .lex-load-label {
  visibility: hidden;
}

/* Remote engine: no lexicon download. Skip the bar/brand/hint chrome and
   show the input immediately (meta wake is a short /api/v1 round-trip). */
html[data-engine="remote"] .lex-load:not(.is-error) {
  display: none !important;
}
html[data-engine="remote"] .composer.is-loading .input-chrome,
html[data-engine="remote"] .composer:has(.lex-load:not([hidden])) .input-chrome {
  visibility: visible;
  pointer-events: auto;
}
html[data-engine="remote"] .composer.is-loading .input-fade,
html[data-engine="remote"] .composer:has(.lex-load:not([hidden])) .input-fade {
  opacity: unset;
}

/* Brand stays blank until the head script confirms the product face. */
html:not([data-font-ready="1"]) .lex-load-brand {
  visibility: hidden;
}

.lex-load-brand {
  display: block;
  margin: 0;
  max-width: 100%;
  font-family: var(--font-mono);
  font-size: 1.45rem;
  line-height: 1.2;
  font-weight: 400;
  letter-spacing: 0.01em;
  text-align: center;
  color: var(--ink);
}

/* Bar center = opener line. Same left/right as .results::before (Trennstich). */
.composer.is-loading .lex-load-track,
.composer.is-error .lex-load-track {
  position: absolute;
  left: var(--content-inline, 0.85rem);
  right: var(--content-inline, 0.85rem);
  width: auto;
  max-width: none;
  margin: 0;
  top: calc(
    var(--pad-top, var(--composer-pad-top, 0.55rem)) +
      (var(--input-text-band, var(--composer-line)) / 2) - 2px
  );
}

.composer.is-loading .lex-load-brand {
  position: absolute;
  left: var(--pad-left, var(--content-inline, 0.85rem));
  right: var(--pad-left, var(--content-inline, 0.85rem));
  width: auto;
  top: calc(
    var(--pad-top, var(--composer-pad-top, 0.55rem)) +
      (var(--input-text-band, var(--composer-line)) / 2) - 2px - 1.85rem -
      (1.45rem * 1.2)
  );
}

.lex-reload {
  pointer-events: auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0.15rem 0 0;
  padding: 0 1.15rem;
  min-width: 44px;
  min-height: 44px;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--surface-1, #1e1e1e);
  color: var(--ink);
  font: inherit;
  font-size: 0.82rem;
  cursor: pointer;
}

.lex-reload[hidden] {
  display: none;
}

.lex-load.is-error {
  gap: 0.7rem;
}

.lex-load.is-error .lex-load-track,
.lex-load-track.is-failed {
  display: none;
}

.lex-load.is-error .lex-load-fill,
.lex-load-track.is-failed .lex-load-fill {
  display: none;
}

.lex-load.is-error .lex-load-label {
  display: block;
  color: var(--accent);
}

@keyframes lex-indeterminate {
  0% { left: -34%; }
  100% { left: 104%; }
}

.panels[hidden],
.results[hidden] {
  display: none;
}

.prefs-drawer {
  margin: 0.75rem 0 0.15rem;
}

.prefs-drawer[hidden] {
  display: none;
}

.prefs {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin: 0;
}

.prefs-panel {
  border: 1px solid var(--line);
  background: var(--paper);
}

.prefs-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4rem 0.65rem;
  border-bottom: 1px solid var(--line);
}

.prefs-panel-title {
  font-size: 0.82rem;
  color: var(--muted);
  letter-spacing: 0.02em;
}

.pref {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.82rem;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
  min-width: 0;
}

.pref.check {
  display: grid;
  grid-template-columns: 1.1rem 1fr;
  align-items: start;
  gap: 0.45rem;
  margin: 0;
  line-height: 1.35;
}

.pref.check input[type="checkbox"] {
  margin: 0.15rem 0 0;
  accent-color: var(--ink);
}

.prefs-sliders > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  font-size: 0.82rem;
  color: var(--muted);
  padding: 0.4rem 0.65rem;
  letter-spacing: 0.02em;
}

.prefs-sliders > summary::-webkit-details-marker {
  display: none;
}

.prefs-sliders > summary::before {
  content: "▸";
  display: inline-block;
  width: 1em;
  color: var(--muted);
}

.prefs-sliders[open] > summary::before {
  content: "▾";
}

.prefs-sliders > summary:hover {
  color: var(--ink);
}

.prefs-matrix {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.55rem 1.4rem;
  padding: 0.65rem;
}

.prefs-sliders .prefs-matrix {
  padding: 0.65rem;
  border-top: 1px solid var(--line);
}

@media (max-width: 620px) {
  .prefs-matrix {
    grid-template-columns: 1fr;
  }
}

.pref.range {
  display: grid;
  grid-template-columns: minmax(7.5rem, 9.5rem) 1fr 2.4rem;
  align-items: center;
  gap: 0.55rem;
  margin: 0;
}

.pref.range input[type="range"] {
  width: 100%;
  min-width: 0;
  accent-color: var(--ink);
}

.pref-reset {
  border-bottom: 1px dotted transparent;
}

.pref-reset:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

.pref-val {
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--ink);
  font-size: 0.8rem;
}

.prefs-reset-all {
  font: inherit;
  font-size: 0.78rem;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  padding: 0.15rem 0.5rem;
  cursor: pointer;
  border-radius: 2px;
  flex-shrink: 0;
}

.prefs-reset-all:hover {
  color: var(--ink);
  border-color: var(--chrome);
}

.results {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 0;
  border-top: 0;
  overflow: visible;
  /* Offset = space above the rule; gap = space below the rule (before content). */
  padding-top: calc(
    var(--divider-offset, 0rem) + var(--input-results-gap, 0rem)
  );
}

/* Soft section cut: input → rhyme results (full content width).
   top tracks --divider-offset only — gap below does not move the hairline. */
.results::before {
  content: "";
  position: absolute;
  z-index: 1;
  top: var(--divider-offset, 0rem);
  left: var(--content-inline);
  right: var(--content-inline);
  height: 1px;
  background: color-mix(in srgb, var(--line) 55%, transparent);
  pointer-events: none;
}

/* Before the list exists, the flow bar stands in for the hairline.
   Once results are up, that bar is the full column and pushes the first
   word down. The hairline itself sweeps instead — same inset, same gap. */
html.is-searching:not([data-results="ready"]) .results::before,
html.is-phrase-searching:not([data-results="ready"]) .results::before {
  opacity: 0;
}

html.is-searching[data-results="ready"] .results::before,
html.is-phrase-searching[data-results="ready"] .results::before {
  opacity: 1;
  overflow: hidden;
  background-color: color-mix(in srgb, var(--line) 55%, transparent);
  background-image: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--ink) 82%, transparent) 45%,
    color-mix(in srgb, var(--ink) 82%, transparent) 55%,
    transparent 100%
  );
  background-repeat: no-repeat;
  background-size: 28% 100%;
  animation: hairline-load-sweep 1.15s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

.panel-rhymes {
  position: relative;
  z-index: 1;
  min-height: 0;
  border-top: 0;
  /* Same air below the rule as panel-units leaves above it */
  padding: var(--rhyme-air-eff) 0 0;
  overflow: visible;
}

.panel {
  background: transparent;
  border: 0;
  /* No horizontal pad — borders stay full-bleed; content pads itself */
  padding: 0;
  min-height: 0;
}

/*
  Input analysis decorations live inside .input-host (#units.q-decor).
  panel-units is a legacy aria shell — keep out of flow.
*/
.panel-units {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  margin: 0;
  padding: 0;
  border: 0;
  pointer-events: none;
}

.panel-units[hidden] {
  display: none;
}

.panel-rhymes .rhymes {
  padding-top: 0;
  overflow: visible;
}

.panel h2 {
  margin: 0 0 0.7rem;
  font-size: 0.82rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}

.meta { letter-spacing: 0; text-transform: none; font-weight: 400; }

/*
  Analysis stack: continuous ortho, horizontal syllable marks (inset under letters),
  IPA under a shared baseline. No side boxes, no /slashes/.
*/
.analysis-stack {
  /* Same stroke weight for all; stress = opacity only */
  --brace-stroke: 1.6px;
  --brace-slot: 1.6px;
  --brace-inset: 0.07em;
  /* --brace-air / --brace-ipa-air come from :root */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  direction: ltr;
  unicode-bidi: isolate;
  min-width: 0;
}

.syl-track {
  display: inline-flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  align-content: flex-start;
  gap: 0;
  max-width: 100%;
}

/* Word = flex group of syllable cells.
   Results may wrap between syllables; underlay never — wrap is per info-block
   on .units-row so marks/IPA stay glued to their word. */
.syl-word {
  display: inline-flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  max-width: 100%;
}

/*
  Results: grow the content column first. Wrap syllables only when the column
  already sits at the screen max (data-col-at-max from syncContentColumn).
*/
#rhymes .syl-track,
#rhymes .syl-word {
  flex-wrap: nowrap;
  max-width: none;
}

html[data-col-at-max="1"] #rhymes .syl-track,
html[data-col-at-max="1"] #rhymes .syl-word {
  flex-wrap: wrap;
  max-width: 100%;
}

.analysis-stack.is-underlay .syl-track,
.analysis-stack.is-underlay .syl-word {
  flex-wrap: nowrap;
  max-width: none;
}

.syl-cell {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex: 0 0 auto;
  width: fit-content;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

/* Flex mode: fixed syllable fields; glyphs fill via axes + scaleX. */
html[data-font-mode="flex"] .analysis-stack,
html[data-font-mode="flex"] .syl-track,
html[data-font-mode="flex"] .syl-word {
  justify-content: flex-start;
  align-items: flex-start;
}

/*
  FOFT / flex flash: hide result-list syllable ink until axes applied.
  Never gate #units underlay — that flash was visible as letter flicker
  next to the stable .unit-surface while marks rebuilt.
*/
html[data-font-mode="flex"]:not([data-flex-eq="1"]) #rhymes .syl-ortho,
html[data-font-mode="flex"]:not([data-flex-eq="1"]) #rhymes .syl-brace,
html[data-font-mode="flex"]:not([data-flex-eq="1"]) #rhymes .syl-ipa {
  opacity: 0;
}

/*
  Ortho must read as one flowing word (no artificial letter gaps).
  Join air lives only on the braces — see --flex-brace-gap below.
*/
html[data-font-mode="flex"] .syl-word {
  --flex-brace-gap: 0.22em;
  column-gap: 0;
  row-gap: 0;
  align-items: flex-start;
}

html[data-font-mode="flex"] .syl-cell[data-syl-col] {
  flex: 0 0 auto;
  align-items: stretch;
  overflow: visible;
}

html[data-font-mode="flex"] .syl-ortho {
  display: block;
  box-sizing: border-box;
  text-align: left;
  letter-spacing: 0 !important;
  line-height: 1.2;
  height: 1.2em;
  overflow: visible;
  white-space: pre;
  /* Default axis before JS equalize — avoids static→flex glyph jump. */
  font-variation-settings: "wdth" 100;
  font-stretch: 100%;
}

/* Brace-only joins (override product --brace-inset when cells abut). */
html[data-font-mode="flex"] .syl-cell .syl-brace {
  margin-left: 0;
}
html[data-font-mode="flex"] .syl-cell:not(.is-syl-last) .syl-brace {
  width: calc(100% - var(--flex-brace-gap, 0.22em));
  margin-left: 0;
}
html[data-font-mode="flex"] .syl-cell.is-syl-last .syl-brace {
  width: 100%;
  margin-left: 0;
}
html[data-font-mode="flex"] .syl-cell:not(.is-syl-first) .syl-brace {
  margin-left: 0;
  width: 100%;
}
html[data-font-mode="flex"] .syl-cell:not(.is-syl-first):not(.is-syl-last) .syl-brace {
  margin-left: 0;
  width: calc(100% - var(--flex-brace-gap, 0.22em));
}

html[data-font-mode="flex"] .syl-ipa {
  display: block;
  text-align: center;
  letter-spacing: normal;
  line-height: 1.25;
  min-height: 1.25em;
}

/*
  Overlay input: typed surface is a stable full-word layer (no chip reflow
  blink). Syllable ortho stays height-0 for brace width only.
*/
.unit-surface {
  display: none;
}

.units-literal {
  display: none;
}

html[data-flex-input="1"] .unit-surface {
  display: block;
  color: var(--ink);
  -webkit-text-fill-color: var(--ink);
  font-size: 1.1rem;
  font-weight: 400;
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  line-height: 1.2;
  white-space: pre;
  letter-spacing: 0;
  pointer-events: none;
  /* Own compositor layer — analysis DOM swaps must not invalidate glyphs. */
  position: relative;
  z-index: 1;
  contain: paint;
  isolation: isolate;
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* Punctuation / symbols: visible ink, no marks/IPA (algorithm ignores). */
html[data-flex-input="1"] .units-literal {
  display: block;
  flex: 0 0 auto;
  align-self: flex-start;
  color: var(--ink);
  -webkit-text-fill-color: var(--ink);
  font-size: 1.1rem;
  font-weight: 400;
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  line-height: 1.2;
  white-space: pre;
  letter-spacing: 0;
  pointer-events: none;
}

html[data-flex-input="1"] .unit-choice.is-solo,
html[data-flex-input="1"] .units-readings,
html[data-flex-input="1"] .unit-cluster {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Underlay ortho: keep letter runs for brace width, but never paint them
   (opacity/color only — visibility:hidden collapsed marks/IPA). Flex-eq
   still skips #units so these runs are not mutated into view. */
html[data-flex-input="1"] .analysis-stack.is-underlay .syl-ortho,
html[data-flex-input="1"] #units .syl-ortho {
  display: block;
  height: 0 !important;
  line-height: 0 !important;
  overflow: hidden !important;
  margin: 0 !important;
  padding: 0 !important;
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  opacity: 0 !important;
  transform: none !important;
  font-size: 1.1rem;
  white-space: pre;
  pointer-events: none;
}

html[data-flex-input="1"] .panel-units {
  /* Shell only — decorations are in .input-host #units */
  margin: 0;
  padding: 0;
}

/* Multi-reading mark rows: no second surface word. */
html[data-flex-input="1"]
  .units-readings
  .reading-marks
  .unit-choice
  .syl-ortho {
  height: 0 !important;
  line-height: 0 !important;
  overflow: hidden !important;
  opacity: 0 !important;
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
}

/* IPA-only stacks never show ortho. */
.analysis-stack.is-ipa-only .syl-ortho,
.units-readings .reading-ipa .syl-ortho {
  display: block;
  height: 0 !important;
  line-height: 0 !important;
  overflow: hidden !important;
  margin: 0 !important;
  padding: 0 !important;
  opacity: 0 !important;
  color: transparent !important;
}

html[data-flex-input="1"] .panel-units {
  /* Shell only — decorations are in .input-host #units */
  margin: 0;
  padding: 0;
}

/*
  Input underlay brace air = same global rule as #rhymes / .is-underlay:
  margin-top: calc(var(--brace-air-eff) - var(--ortho-ink-below)).
  Never override to full --brace-air-eff here — that doubled the ink→mark gap.
*/

/* Mid marks only: ortho → brace → IPA */
.syl-ortho { order: 2; }
.syl-brace { order: 3; }
.syl-ipa { order: 4; }

.syl-gap {
  /* Real space glyph — matches inter-word gap; no brace spans this. */
  flex: 0 0 auto;
  width: auto;
  white-space: pre;
  align-self: stretch;
  font-size: inherit;
  line-height: 0;
  pointer-events: none;
}

.analysis-stack.is-primary .syl-gap,
.analysis-stack.is-underlay .syl-gap {
  font-size: 1.1rem;
}

.syl-ortho {
  font-size: 0.78rem;
  font-weight: 400;
  line-height: 1.15;
  color: var(--muted);
  /* pre: never wrap mid-syllable */
  white-space: pre;
  letter-spacing: 0;
}

/* Result row: ortho IS the name — braces hang directly under it */
.analysis-stack.is-primary .syl-ortho {
  font-size: 1.1rem;
  line-height: 1.2;
  color: var(--ink);
  font-weight: 400;
}

/*
  Underlay: ortho only sizes brace width — zero height (word lives in
  .unit-surface). Never visibility:hidden — that collapses brace width.
*/
.analysis-stack.is-underlay .syl-ortho {
  display: block;
  font-size: 1.1rem;
  line-height: 0;
  white-space: pre;
  height: 0;
  overflow: hidden;
  margin: 0;
  padding: 0;
  opacity: 0;
  color: transparent;
  -webkit-text-fill-color: transparent;
  pointer-events: none;
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}

.analysis-stack.is-underlay .syl-brace {
  margin-top: calc(var(--brace-air-eff) - var(--ortho-ink-below, 0px));
  margin-bottom: calc(var(--brace-ipa-air-eff) - var(--ipa-ink-above, 0px));
}

.units-word-gap {
  flex: 0 0 auto;
  white-space: pre;
  font-size: 1.1rem;
  line-height: 0;
  pointer-events: none;
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}

html[data-flex-input="1"] .units-word-gap {
  /* Match mono space advance (textarea). */
  align-self: flex-start;
  box-sizing: content-box;
  width: 1ch;
  min-width: 1ch;
  max-width: 1ch;
  flex: 0 0 1ch;
  height: 1.2em;
  line-height: 1.2;
  font-size: 1.1rem;
  font-family: var(--font-mono);
  color: transparent;
  overflow: hidden;
}

/*
  Horizontal syllable marks: full width on outer edges and mono syllables.
  Only shorten toward inter-syllable joins (gap = --brace-inset each side).
*/
.syl-brace {
  --brace-color: color-mix(in srgb, var(--chrome) 55%, transparent);
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: var(--brace-slot);
  /* Subtract line-box slack so air is ink→mark / mark→ink, not box→box. */
  margin-top: calc(var(--brace-air-eff) - var(--ortho-ink-below, 0px));
  margin-bottom: calc(var(--brace-ipa-air-eff) - var(--ipa-ink-above, 0px));
  margin-left: 0;
  padding: 0;
  border: none;
  border-radius: 1px;
  background: linear-gradient(var(--brace-color), var(--brace-color))
    center / 100% var(--brace-stroke) no-repeat;
  opacity: 0.42;
  pointer-events: none;
}

/* Join: shorten the right edge of every non-final syllable */
.syl-cell:not(.is-syl-last) .syl-brace {
  width: calc(100% - var(--brace-inset));
}

/* Join: shorten the left edge of every non-first syllable */
.syl-cell:not(.is-syl-first) .syl-brace {
  margin-left: var(--brace-inset);
  width: calc(100% - var(--brace-inset));
}

/* Middle: shortened on both sides of the joins */
.syl-cell:not(.is-syl-first):not(.is-syl-last) .syl-brace {
  margin-left: var(--brace-inset);
  width: calc(100% - 2 * var(--brace-inset));
}

.syl-cell.is-stress .syl-brace {
  opacity: 1;
}

.analysis-stack.q-syl-good .syl-brace {
  --brace-color: color-mix(in srgb, var(--good) 88%, transparent);
}
.analysis-stack.q-syl-warn .syl-brace {
  --brace-color: color-mix(in srgb, var(--warn) 88%, transparent);
}
.analysis-stack.q-syl-bad .syl-brace {
  --brace-color: color-mix(in srgb, var(--bad) 88%, transparent);
}

.syl-ipa {
  /* Don't expand the cell: hang under the ortho width */
  width: 0;
  min-width: 100%;
  box-sizing: border-box;
  font-family: var(--font-ipa);
  font-feature-settings: "kern" 1;
  font-size: 0.58rem;
  /* Stable box so IPA glyphs share one baseline */
  line-height: 1.35;
  color: var(--muted);
  direction: ltr;
  unicode-bidi: isolate;
  margin-top: 0;
  /* Always centered under the brace / syllable */
  display: flex;
  justify-content: center;
  text-align: center;
  white-space: pre;
  overflow: visible;
}

/*
  Center under the brace without changing cell width.
  Keep width:0;min-width:100% (max-content was expanding syllables when
  IPA was longer than ortho — visible especially on iOS).
  flex + justify-content works on WebKit where text-align alone failed.
*/

.ipa-fallback {
  font-family: var(--font-ipa);
  font-feature-settings: "kern" 1;
  font-size: 0.62rem;
  line-height: 1.2;
  color: var(--muted);
  direction: ltr;
  unicode-bidi: isolate;
  word-break: break-word;
  margin-top: 0;
  text-align: left;
  max-width: 100%;
}

.analysis-stack.q-ipa-good .syl-ipa,
.analysis-stack.q-ipa-good .ipa-fallback {
  color: color-mix(in srgb, var(--muted) 70%, var(--good));
}
.analysis-stack.q-ipa-warn .syl-ipa,
.analysis-stack.q-ipa-warn .ipa-fallback {
  color: color-mix(in srgb, var(--muted) 70%, var(--warn));
}
.analysis-stack.q-ipa-bad .syl-ipa,
.analysis-stack.q-ipa-bad .ipa-fallback {
  color: color-mix(in srgb, var(--muted) 70%, var(--bad));
}

/*
  Default face is Manrope (UI, brand, input, analysis).
  Iosevka Aile remains available from the debug font cycle.
*/
html {
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}

.analysis-stack,
.analysis-stack .syl-ortho,
.score-pct {
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}

.analysis-stack .syl-ipa,
.ipa-fallback {
  font-family: var(--font-ipa);
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}

.site-foot,
.site-foot .legal-link {
  font-family: var(--font-sans);
  font-variant-ligatures: normal;
  font-feature-settings: "kern" 1, "liga" 1;
}

.ipa-tok.is-diff {
  background: color-mix(in srgb, var(--muted) 28%, transparent);
  border-radius: 0.15em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

.sentence-bits {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem 0.65rem;
  direction: ltr;
  unicode-bidi: isolate;
}

.units {
  display: flex;
  flex-direction: column;
  gap: calc(var(--rhyme-air-eff) + 0.35rem);
}

.name-line {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  min-width: 0;
  max-width: 100%;
}

.lang-mark {
  font-size: 0.55em;
  line-height: 0;
  color: var(--faint);
  margin-left: 0.15em;
  vertical-align: super;
  font-weight: 550;
  letter-spacing: 0;
}
button.lang-mark {
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  font-size: 0.55em;
  color: var(--faint);
}

/* Input/understood word: kennzeichen top-right of the ortho track. */
.analysis-stack.is-underlay .syl-track {
  position: relative;
}
.analysis-stack.is-underlay .lang-mark-input {
  position: absolute;
  top: -0.05em;
  right: -0.05em;
  margin-left: 0;
  line-height: 1;
  pointer-events: none;
}
.lang-hint {
  color: var(--faint);
  font-size: 0.85em;
}
.why-origin {
  margin: 0.4rem 0 0;
  color: var(--faint);
  font-size: var(--fs-note, 0.82rem);
}
.name-line .name {
  min-width: 0;
}

/* Reading picker: opacity only — no fill/border fighting trust outlines */
.unit-choice {
  appearance: none;
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.unit-choice.is-solo {
  cursor: default;
}

/* Multi-word row: gap = one space glyph (must match textarea, not 0.85rem). */
.units-row {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 0;
  max-width: 100%;
}

/* Never let word clusters expand to row width. */
.units-row > .unit-cluster {
  flex: 0 0 auto;
  width: max-content;
  max-width: 100%;
}

.unit-cluster {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 100%;
}

.unit-cluster > .unit-analysis {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow: visible;
  pointer-events: none;
  contain: paint;
}

/* Selection highlight on underlay glyphs (textarea ::selection is transparent). */
#units {
  position: relative;
}

.flex-sel-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}

.flex-sel-layer > i {
  position: fixed;
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 1px;
  background: color-mix(in srgb, #6ea8fe 45%, transparent);
  pointer-events: none;
}

html.is-lesart-hover,
html.is-lesart-hover * {
  cursor: pointer !important;
}

html[data-flex-input="1"] .unit-cluster {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Multi-reading: single stack + pronunciation dropdown (no tap-cycle). */
.units-readings {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  max-width: 100%;
  -webkit-tap-highlight-color: transparent;
  pointer-events: none;
}

.units-readings.is-multi {
  pointer-events: none;
  position: relative;
}

.units-readings.is-multi .analysis-stack {
  pointer-events: none;
}

.units-readings.is-multi .syl-cell,
.units-readings.is-multi .syl-brace,
.units-readings.is-multi .syl-ipa {
  pointer-events: none;
  cursor: inherit;
}

.reading-picker {
  position: absolute;
  top: -0.15rem;
  right: -1.15rem;
  z-index: 3;
  pointer-events: auto;
}

.reading-picker-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--faint);
  font: inherit;
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
}

.reading-picker-toggle:hover,
.reading-picker-toggle:focus-visible,
.reading-picker-toggle[aria-expanded="true"] {
  color: var(--ink);
  outline: none;
}

.reading-picker-menu {
  position: absolute;
  top: calc(100% + 0.2rem);
  left: 0;
  z-index: 5;
  min-width: 7.5rem;
  max-width: min(16rem, 70vw);
  margin: 0;
  padding: 0.22rem;
  display: flex;
  flex-direction: column;
  gap: 0.06rem;
  background: var(--paper);
  border-radius: 2px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent),
    0 0.45rem 1.1rem color-mix(in srgb, var(--ink) 8%, transparent);
}

.reading-picker-menu[hidden] {
  display: none !important;
}

.reading-picker-option {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  width: 100%;
  margin: 0;
  padding: 0.28rem 0.45rem;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 0.82rem;
  line-height: 1.25;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}

.reading-picker-option:hover,
.reading-picker-option:focus-visible {
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  outline: none;
}

.reading-picker-dot {
  flex: 0 0 0.55rem;
  width: 0.55rem;
  text-align: center;
  color: var(--ink);
  font-size: 1.05em;
  line-height: 1;
}

.reading-picker-dot.is-empty {
  visibility: hidden;
}

.reading-picker-ipa {
  font-family: var(--font-ipa, var(--font-mono));
  font-size: 0.9em;
}

/* Legacy stacked-mark styles kept inert; picker replaced tap-cycle. */
.units-readings .reading-marks {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--reading-stack-gap, 0.18rem);
  max-width: 100%;
  pointer-events: auto;
  padding: 0.15rem 0 0.35rem;
  margin: -0.15rem 0 -0.1rem;
  box-sizing: content-box;
}

.units-readings .reading-marks .unit-choice {
  width: auto;
  max-width: 100%;
  padding: 0;
  margin: 0;
  box-sizing: content-box;
}

.units-readings .reading-marks .unit-choice .analysis-stack.is-underlay .syl-brace {
  margin-bottom: 0;
}

.units-readings .reading-marks .unit-choice:not(:first-child) .analysis-stack.is-underlay .syl-brace {
  margin-top: 0;
}

.units-readings .reading-ipa {
  margin-top: calc(var(--brace-ipa-air-eff) - var(--ipa-ink-above, 0px));
  padding-top: 0;
  pointer-events: auto;
  max-width: 100%;
}

.units-readings .reading-ipa .analysis-stack.is-ipa-only.is-underlay .syl-ipa,
.units-readings .reading-ipa .ipa-fallback {
  margin-top: 0;
}

.units-readings .unit-choice:not(.is-active) {
  opacity: 0.55;
}

.units-readings .unit-choice.is-active {
  opacity: 1;
}

.unit-choice:not(.is-solo):not(.is-active) {
  opacity: 0.55;
}

.unit-choice:not(.is-solo):not(.is-active):hover,
.unit-choice:not(.is-solo):not(.is-active):focus-visible {
  opacity: 0.88;
  outline: none;
}

.unit-choice.is-active {
  opacity: 1;
  background: transparent;
}

.rhyme {
  /*
    Between blocks: --rhyme-air (consistent).
    Within a block: equal --brace-air above and below the syllable marks.
    Score sits in a fixed right column (under chrome) so % stays assigned.
    Vertically center % against the whole analysis stack (wrap-aware).
  */
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--score-col);
  column-gap: 0.65rem;
  align-items: center;
  padding-top: calc(var(--rhyme-air-eff) + 0.14rem);
  padding-bottom: calc(var(--rhyme-air-eff) + 0.14rem);
  padding-left: var(--content-inline);
  padding-right: var(--content-inline);
  border-bottom: 0;
  overflow: visible;
}

/* Rows stay painted. content-visibility:auto left blank bands on
   iPhone and Mac while the next slice was still offscreen. */
html[data-col-frozen="1"] #rhymes .rhyme {
  content-visibility: visible;
  contain: none;
}

.rhyme-sentinel {
  height: 1px;
  overflow: hidden;
  pointer-events: none;
}

.rhyme-end {
  position: relative;
  margin: 0;
  padding: 0;
  height: calc(var(--divider-offset, 0rem) + 1px);
  border: 0;
  pointer-events: none;
}

.rhyme-end::before {
  content: "";
  position: absolute;
  top: var(--divider-offset, 0rem);
  left: var(--content-inline);
  right: var(--content-inline);
  height: 1px;
  background: color-mix(in srgb, var(--line) 55%, transparent);
}

#rhymes .rhyme-main {
  cursor: pointer;
}

.word-menu {
  position: fixed;
  z-index: 70;
  width: max-content;
  min-width: 11rem;
  max-width: calc(100vw - 1rem);
  box-sizing: border-box;
  margin: 0;
  padding: 0.28rem;
  display: flex;
  flex-direction: column;
  gap: 0.08rem;
  background: color-mix(in srgb, var(--ink) 10%, var(--paper));
  color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 42%, transparent);
  border-radius: 2px;
  box-shadow: 0 0.65rem 1.6rem color-mix(in srgb, #000 55%, transparent);
}

.word-menu[hidden] {
  display: none !important;
}

.word-menu-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  min-height: 44px;
  margin: 0;
  padding: 0.35rem 0.7rem;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--ink);
  -webkit-text-fill-color: var(--ink);
  font: inherit;
  font-size: 0.92rem;
  font-weight: 560;
  line-height: 1.2;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}

.word-menu-icon {
  display: inline-flex;
  flex: 0 0 1rem;
  width: 1rem;
  height: 1rem;
  align-items: center;
  justify-content: center;
  color: var(--muted);
}

.word-menu-icon svg {
  width: 1rem;
  height: 1rem;
  display: block;
}

.word-menu-label {
  flex: 1 1 auto;
  min-width: 0;
}

.word-menu-item:hover .word-menu-icon,
.word-menu-item:focus-visible .word-menu-icon {
  color: var(--ink);
}

.word-menu-item:hover,
.word-menu-item:focus-visible {
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  outline: none;
}

.rhyme-info {
  position: relative;
  align-self: flex-start;
  width: max-content;
  max-width: 100%;
}

.speak-pip {
  position: absolute;
  left: calc(100% + 0.38rem);
  top: 50%;
  width: 0.9rem;
  height: 0.9rem;
  margin-top: -0.45rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  opacity: 0;
  pointer-events: none;
  transition: opacity 280ms ease;
}

.speak-pip svg {
  width: 0.85rem;
  height: 0.85rem;
  display: block;
}

#rhymes .rhyme.is-speaking .speak-pip,
#rhymes .rhyme-slot.is-speaking .speak-pip {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .speak-pip {
    transition: none;
  }
}

.rhyme.is-combo {
  display: flex;
  align-items: stretch;
  gap: 0;
}

/* Product lattice: one readable line + score, like a rhyme row. */
.rhyme.is-combo.is-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--score-col);
  column-gap: 0.65rem;
  align-items: center;
  outline: none;
}

.rhyme.is-combo.is-line .name {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* The result-word menu is the affordance. A row outline is not a menu. */

.rhyme.is-lattice.is-cross-word:not(.is-line) {
  outline: 1px solid color-mix(in srgb, var(--accent, #8f8) 35%, transparent);
  outline-offset: 2px;
  border-radius: 2px;
}

.rhyme.is-lattice:not(.is-line) {
  position: relative;
  flex-wrap: wrap;
  row-gap: 0.2rem;
}

html[data-debug="0"] .lattice-badges {
  display: none !important;
}

.lattice-badges {
  flex: 1 0 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.45rem;
  align-items: center;
  min-width: 0;
  font-size: 0.68rem;
  line-height: 1.2;
  color: var(--muted);
  opacity: 0.9;
}

.lattice-badge {
  display: inline-block;
  padding: 0.05rem 0.28rem;
  border: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
  border-radius: 2px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.lattice-badge.is-fingerprint {
  font-family: ui-monospace, "Iosevka Aile", monospace;
  color: var(--ink);
  opacity: 0.85;
}

.lattice-badge.is-variants {
  opacity: 0.7;
}

.lattice-badge.is-semantic {
  border-color: color-mix(in srgb, var(--accent, #8f8) 45%, transparent);
  color: var(--ink);
}

.lattice-badge.is-top {
  opacity: 0.75;
}

.rhyme.is-lattice.is-semantic:not(.is-line) {
  outline: 1px solid color-mix(in srgb, var(--accent, #8f8) 28%, transparent);
  outline-offset: 2px;
}

.rhyme-slot.is-span-merge {
  flex: 1.35 1 0;
}

.rhyme-slot.is-span-merge::before {
  content: "⟷";
  position: absolute;
  left: 0.15rem;
  top: 0.1rem;
  font-size: 0.65rem;
  opacity: 0.55;
  pointer-events: none;
}

/* Shrink the ink inside the slot. The slot itself keeps its share of the row. */
.rhyme-slot .rhyme-main,
.rhyme-slot .rhyme-meta {
  zoom: var(--combo-fit);
}

html[data-word-combo="1"] #rhymes .rhyme.is-combo .syl-track,
html[data-word-combo="1"] #rhymes .rhyme.is-combo .syl-word {
  flex-wrap: nowrap;
  max-width: none;
}

.rhyme-slot {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 0.55rem;
  align-items: center;
  overflow: hidden;
}

.rhyme-slot + .rhyme-slot {
  margin-left: 0.75rem;
  padding-left: 0.75rem;
  border-left: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
}

.combo-gap {
  position: absolute;
  z-index: 3;
  width: 1px;
  margin-left: -0.5px;
  background: color-mix(in srgb, var(--line) 55%, transparent);
  pointer-events: none;
}

.rhyme-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/*
  E-014 Auftakt hang: per-row margin-left is set inline in syncAuftaktHang
  (negative shift = that row's prefix + gap). Match stays under the query.
  No shared max-prefix column, no boundary hairline.
*/
.rhyme-main.has-auftakt-hang .analysis-stack,
.rhyme-main.has-auftakt-hang .name-line {
  overflow: visible;
}

/* E-014 Auftakt cue: quieter ink. The match boundary is the gap only. */
.syl-cell.is-auftakt .syl-ortho {
  color: color-mix(in srgb, var(--muted) 78%, transparent);
}

.analysis-stack.is-primary .syl-cell.is-auftakt .syl-ortho {
  color: color-mix(in srgb, var(--muted) 92%, var(--ink));
}

.syl-cell.is-auftakt .syl-ipa {
  color: color-mix(in srgb, var(--muted) 62%, transparent);
}

.syl-cell.is-auftakt .syl-brace {
  opacity: 0.28;
  --brace-color: color-mix(in srgb, var(--line) 55%, transparent);
}

.syl-cell.is-auftakt.is-stress .syl-brace {
  opacity: 0.4;
}

.syl-cell.is-auftakt-end {
  /* Visual Zwischenraum — hang shift includes this so match stays under query. */
  margin-right: var(--auftakt-gap);
}

.name-line.has-auftakt-hang .auftakt-hang {
  color: color-mix(in srgb, var(--muted) 92%, var(--ink));
  margin-right: var(--auftakt-gap);
}

.rhyme-meta {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.35rem;
  flex: 0 0 auto;
  width: 100%;
  padding-top: 0;
}

.score-bar {
  --p: 0;
  --score-fill: var(--bad);
  width: 2.35rem;
  height: 0.3rem;
  border-radius: 1px;
  display: inline-block;
  flex: 0 0 auto;
  vertical-align: middle;
  background: linear-gradient(
    to right,
    var(--score-fill) calc(var(--p) * 1%),
    color-mix(in srgb, var(--line) 60%, transparent) 0
  );
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--line) 70%, transparent);
}

.score-pct {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  line-height: 1;
  flex: 0 0 auto;
  white-space: nowrap;
  color: var(--score-fill, var(--muted));
}

/* Quiet hit target on the percent. Same ink as the old span. */
.score-hit {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  cursor: pointer;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
}

.score-hit:focus {
  outline: none;
}

.score-hit:focus-visible {
  outline: 1px solid color-mix(in srgb, var(--ink) 55%, transparent);
  outline-offset: 2px;
}

.rhyme-combo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.05rem;
  height: 1.05rem;
  color: var(--muted);
  flex: 0 0 auto;
}

.rhyme-combo svg {
  width: 100%;
  height: 100%;
  display: block;
}

.rhyme .name {
  font-size: 1.1rem;
  /* Tight line box → padding-top measures to letter tops, not half-leading */
  line-height: 1;
}

.rhyme .sub {
  direction: ltr;
  unicode-bidi: isolate;
  margin-top: 0;
}

/*
  Results reveal: never flash mid-render. pending = invisible buffer;
  ready = opacity + staggered row roll-out.
  Input analysis (.panel-units) stays visible — it is the live underlay while
  typing (hero / empty / pending). Only the rhyme list is gated.
*/
html[data-results="pending"] #results {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.16s ease;
}

html[data-results="ready"] #results {
  opacity: 1;
  transition: opacity 0.22s ease;
}

html[data-results="empty"] #results {
  opacity: 0;
  transition: opacity 0.16s ease;
}

html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme {
  animation: result-row-in 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
}

html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(1) { animation-delay: 0.02s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(2) { animation-delay: 0.05s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(3) { animation-delay: 0.08s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(4) { animation-delay: 0.11s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(5) { animation-delay: 0.14s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(6) { animation-delay: 0.17s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(7) { animation-delay: 0.2s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(8) { animation-delay: 0.23s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(9) { animation-delay: 0.26s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(10) { animation-delay: 0.29s; }
html[data-results-anim="cascade-down"][data-results="ready"] #rhymes .rhyme:nth-child(n + 11) { animation-delay: 0.32s; }

/* Staggered opacity only — no horizontal motion. */
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme {
  animation: result-fade 0.32s ease both;
}
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(1) { animation-delay: 0.02s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(2) { animation-delay: 0.05s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(3) { animation-delay: 0.08s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(4) { animation-delay: 0.11s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(5) { animation-delay: 0.14s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(6) { animation-delay: 0.17s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(7) { animation-delay: 0.2s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(8) { animation-delay: 0.23s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(9) { animation-delay: 0.26s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(10) { animation-delay: 0.29s; }
html[data-results-anim="cascade-fade"][data-results="ready"] #rhymes .rhyme:nth-child(n + 11) { animation-delay: 0.32s; }

/* Left→right uncover (clip), glyphs stay put. */
html[data-results-anim="wipe-right"][data-results="ready"] #rhymes .rhyme {
  animation: result-wipe-right 0.38s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: 0s !important;
}

html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme {
  animation: result-wipe-right 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
}
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(1) { animation-delay: 0.02s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(2) { animation-delay: 0.05s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(3) { animation-delay: 0.08s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(4) { animation-delay: 0.11s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(5) { animation-delay: 0.14s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(6) { animation-delay: 0.17s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(7) { animation-delay: 0.2s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(8) { animation-delay: 0.23s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(9) { animation-delay: 0.26s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(10) { animation-delay: 0.29s; }
html[data-results-anim="wipe-right-stagger"][data-results="ready"] #rhymes .rhyme:nth-child(n + 11) { animation-delay: 0.32s; }

html[data-results-anim="fade"][data-results="ready"] #rhymes .rhyme {
  animation: result-fade 0.28s ease both;
  animation-delay: 0s !important;
}

html[data-results-anim="blur-in"][data-results="ready"] #rhymes .rhyme {
  animation: result-blur-in 0.36s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: 0s !important;
}

html[data-results-anim="none"][data-results="ready"] #rhymes .rhyme {
  animation: none !important;
}

@keyframes result-row-in {
  from {
    opacity: 0;
    transform: translateY(-0.35rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes result-wipe-right {
  from {
    clip-path: inset(0 100% 0 0);
    opacity: 1;
  }
  to {
    clip-path: inset(0 0 0 0);
    opacity: 1;
  }
}

@keyframes result-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes result-blur-in {
  from {
    opacity: 0;
    filter: blur(4px);
  }
  to {
    opacity: 1;
    filter: blur(0);
  }
}

/* Follow-up crossfade: only the rhyme list, underlay stays put. */
#rhymes {
  transition: opacity 0.16s ease;
}

#rhymes.is-crossfading {
  opacity: 0;
}

.empty { color: var(--muted); }

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

/* Opus skin — revert with html[data-ui="classic"] / pref lyrika-uiDesign. */
html[data-ui="opus"] {
  --surface-1: #1e1e1e;
  --surface-2: #242424;
  --line-soft: color-mix(in srgb, var(--line) 55%, transparent);
  --faint: color-mix(in srgb, var(--muted) 72%, transparent);
  --focus: color-mix(in srgb, var(--ink) 70%, transparent);
  --score-hi: var(--ramp-green);
  --score-lo: var(--ramp-red);
  /* Trust (braces + IPA) sits on the score ramp: clean green, hybrid yellow, algo red. */
  --trust-clean: var(--ramp-green);
  --trust-hybrid: var(--ramp-yellow);
  --trust-algo: var(--ramp-red);
  --trust-good: var(--trust-clean);
  --trust-warn: var(--trust-hybrid);
  --trust-bad: var(--trust-algo);
  --fs-ipa: 0.66rem;
  --dur-1: 140ms;
  --dur-2: 220ms;
  --dur-3: 340ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --hit: 44px;
}

/* Ultra Dark: gray surfaces become black. Ink, score, and trust stay. */
html[data-ultra="1"],
html[data-ultra="1"][data-ui="opus"] {
  --bg: #000000;
  --paper: #000000;
  --surface-1: #000000;
  --surface-2: #000000;
  --chip: #0a0a0a;
}

html[data-ui="opus"] .lex-load-brand {
  display: block;
}

html[data-ui="opus"] .algo-panel {
  background: var(--surface-1);
  border: 1px solid var(--line);
  box-shadow: none;
  padding: 0.7rem 0.75rem 0.55rem;
}

html[data-ui="opus"] .algo-panel-title {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
}

html[data-ui="opus"] .algo-opt {
  min-height: var(--hit);
  align-items: center;
  justify-content: space-between;
}

html[data-ui="opus"] .algo-opt input {
  accent-color: var(--ink);
  width: 1.05rem;
  height: 1.05rem;
  margin-top: 0;
}

html[data-ui="opus"] .algo-opt-select {
  align-items: stretch;
}

html[data-ui="opus"] .algo-select {
  accent-color: var(--ink);
}

/* Trust buckets. Solid strokes — no dash/dot pattern. */
html[data-ui="opus"] .syl-brace {
  background: linear-gradient(var(--brace-color), var(--brace-color))
    center / 100% var(--brace-stroke) no-repeat;
  height: var(--brace-slot);
  border: 0;
  opacity: 1;
}

html[data-ui="opus"] .analysis-stack[data-trust-syl="clean"] .syl-brace,
html[data-ui="opus"] .analysis-stack.q-syl-good .syl-brace {
  --brace-color: var(--trust-clean);
}
html[data-ui="opus"] .analysis-stack[data-trust-syl="hybrid"] .syl-brace,
html[data-ui="opus"] .analysis-stack.q-syl-warn .syl-brace {
  --brace-color: var(--trust-hybrid);
}
html[data-ui="opus"] .analysis-stack[data-trust-syl="algo"] .syl-brace,
html[data-ui="opus"] .analysis-stack.q-syl-bad .syl-brace {
  --brace-color: var(--trust-algo);
}

html[data-ui="opus"] .syl-ipa,
html[data-ui="opus"] .ipa-fallback {
  font-size: var(--fs-ipa);
  letter-spacing: 0.02em;
}

html[data-ui="opus"] .analysis-stack[data-trust-ipa="clean"] .syl-ipa,
html[data-ui="opus"] .analysis-stack[data-trust-ipa="clean"] .ipa-fallback,
html[data-ui="opus"] .analysis-stack.q-ipa-good .syl-ipa,
html[data-ui="opus"] .analysis-stack.q-ipa-good .ipa-fallback {
  color: var(--trust-clean);
}
html[data-ui="opus"] .analysis-stack[data-trust-ipa="hybrid"] .syl-ipa,
html[data-ui="opus"] .analysis-stack[data-trust-ipa="hybrid"] .ipa-fallback,
html[data-ui="opus"] .analysis-stack.q-ipa-warn .syl-ipa,
html[data-ui="opus"] .analysis-stack.q-ipa-warn .ipa-fallback {
  color: var(--trust-hybrid);
}
html[data-ui="opus"] .analysis-stack[data-trust-ipa="algo"] .syl-ipa,
html[data-ui="opus"] .analysis-stack[data-trust-ipa="algo"] .ipa-fallback,
html[data-ui="opus"] .analysis-stack.q-ipa-bad .syl-ipa,
html[data-ui="opus"] .analysis-stack.q-ipa-bad .ipa-fallback {
  color: var(--trust-algo);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-1: 0ms;
    --dur-2: 120ms;
    --dur-3: 120ms;
  }

  .lex-load-track.is-indeterminate .lex-load-fill,
  .q-ghost-caret,
  .tool-btn.is-attention,
  .input-settings.is-attention {
    animation: none;
  }

  .lex-load.is-morph .lex-load-track,
  .moon-icon .moon-layer {
    transform: none;
    transition: none;
  }

  .lex-load,
  .lex-load-fill,
  #rhymes {
    transition-duration: 120ms;
  }

  .why-backdrop,
  .why-panel {
    transition: none;
  }
}

/* Why sheet — one chart at a time, scaled to the viewport. No matrix scroll. */
html.why-sheet-open {
  overflow: hidden;
}

.why-backdrop {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.65rem;
  background: color-mix(in srgb, #000 58%, transparent);
}

.why-panel {
  position: relative;
  width: fit-content;
  max-width: min(40rem, calc(100vw - 1.3rem));
  min-width: min(16rem, calc(100vw - 1.3rem));
  max-height: calc(100svh - 1.3rem);
  max-height: calc(100dvh - 1.3rem);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: 0 18px 50px color-mix(in srgb, #000 45%, transparent);
}

.why-phrase-meta {
  margin: 0.35rem 0 0.55rem;
  padding: 0.45rem 0.55rem;
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--muted);
  text-align: left;
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  border-radius: 2px;
}

.why-phrase-k {
  display: inline-block;
  min-width: 4.2rem;
  color: var(--ink);
  font-weight: 560;
}

.why-phrase-slots {
  margin: 0.35rem 0 0;
  padding: 0;
  list-style: none;
}

.why-phrase-slots li {
  display: flex;
  gap: 0.45rem;
  align-items: baseline;
}

.why-phrase-pb {
  min-width: 2.4rem;
  color: var(--ink);
  font-variant: all-small-caps;
  letter-spacing: 0.03em;
}

.why-phrase-pct {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.why-phrase-note {
  margin: 0.2rem 0 0;
  font-size: 0.72rem;
  color: var(--muted);
}

.why-compare {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: 0.45rem 0.7rem;
  max-width: 100%;
  padding: 0.7rem 2.6rem 0.35rem 0.85rem;
}

.why-block {
  min-width: 0;
  max-width: 100%;
}

.why-block .syl-track,
.why-block .syl-word {
  flex-wrap: nowrap;
  max-width: none;
}

.why-arrow {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  height: calc(1.1rem * 1.2);
  font-family: var(--font-sans);
  font-size: 1.1rem;
  line-height: 1;
  color: var(--muted);
}

/* Popup braces stay gray; stress is brightness, not the list's trust hue. */
.why-block .analysis-stack .syl-brace,
html[data-ui="opus"] .why-block .analysis-stack .syl-brace {
  --brace-color: var(--chrome);
  opacity: 0.4;
}

.why-block .syl-cell.is-stress .syl-brace,
html[data-ui="opus"] .why-block .syl-cell.is-stress .syl-brace {
  --brace-color: var(--chrome);
  opacity: 1;
}

.why-block .analysis-stack .syl-ipa,
.why-block .analysis-stack .ipa-fallback,
html[data-ui="opus"] .why-block .analysis-stack .syl-ipa,
html[data-ui="opus"] .why-block .analysis-stack .ipa-fallback {
  color: var(--ink);
}

.why-phone {
  color: var(--phone-fill, var(--score-fill, var(--ink)));
}

.why-close {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  min-width: 44px;
  min-height: 44px;
  margin: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 1.15rem;
  cursor: pointer;
}

.why-close:hover,
.why-close:focus-visible {
  color: var(--ink);
  outline: 1px solid var(--focus, color-mix(in srgb, var(--ink) 70%, transparent));
  outline-offset: -1px;
}

.why-stage {
  min-height: 0;
  overflow: hidden;
  flex: 0 1 auto;
}

.why-main {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
  padding: 0.45rem 0.7rem 0.35rem;
}

.why-matrix-scroll {
  width: auto;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

.why-matrix {
  display: block;
  max-width: 100%;
  height: auto;
}

.why-path-slot {
  flex: 0 0 auto;
  border-bottom: 1px solid var(--line);
  min-width: 0;
}

.why-path {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: center;
  gap: 0.15rem 0;
  overflow: hidden;
  padding: 0.55rem 0.7rem 0.65rem;
}

.why-step {
  position: relative;
  flex: 0 0 auto;
  min-width: 5.2rem;
  max-width: 11rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.28rem;
  padding: 0.35rem 0.55rem;
  text-align: center;
}

.why-step::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}

.why-step-name,
.why-step-num {
  position: relative;
  z-index: 1;
  background: var(--paper);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.why-step-name {
  padding: 0 0.25rem;
  font-family: var(--font-ipa), var(--font-mono), sans-serif;
  font-size: 0.72rem;
  line-height: 1.3;
  color: var(--ink);
}

.why-step-num {
  padding: 0 0.2rem;
  font-size: 0.68rem;
  color: var(--phone-fill, var(--muted));
}

.why-step.is-sum .why-step-name {
  color: var(--ink);
}

.why-step.is-sum .why-step-num {
  color: var(--score-fill, var(--muted));
}

.why-cell {
  fill: none;
  stroke: #333333;
  stroke-width: 1;
}

.why-edge {
  fill: none;
  stroke: var(--phone-fill, var(--score-fill, #c8c8c8));
  stroke-width: 1.25;
  stroke-linecap: butt;
}

.why-edge-head {
  fill: var(--phone-fill, var(--score-fill, #c8c8c8));
  stroke: none;
}

.why-node {
  fill: var(--paper);
  stroke: #8d8d8d;
  stroke-width: 1.25;
}

.why-node.is-c,
.why-node.is-both {
  stroke: #f2f2f2;
  stroke-width: 1.5;
}

.why-glyph {
  fill: var(--phone-fill, var(--score-fill, var(--ink)));
  font-family: var(--font-ipa), var(--font-mono), sans-serif;
  font-size: 13px;
  text-anchor: middle;
  dominant-baseline: central;
}

.why-axis {
  fill: var(--muted);
  font-family: var(--font-mono), sans-serif;
  font-size: 10px;
  dominant-baseline: central;
}

.why-chip-bg {
  fill: var(--paper);
  stroke: var(--phone-fill, #3a3a3a);
  stroke-width: 1.25;
}

.why-chip-stem {
  stroke: var(--phone-fill, var(--muted));
  stroke-width: 1.25;
  fill: none;
}

.why-chip-text {
  fill: var(--phone-fill, var(--muted));
  font-family: var(--font-mono), sans-serif;
  font-size: 10px;
  text-anchor: middle;
  dominant-baseline: central;
}

.why-note {
  margin: 0;
  padding: 0.85rem 0.35rem 0.45rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--muted);
  text-align: center;
}

@media (min-width: 720px) {
  .why-backdrop {
    padding: 1.25rem;
  }

  .why-panel {
    border-radius: 2px;
  }
}

html[data-ipa-font] .syl-ipa,
html[data-ipa-font] .ipa-fallback,
html[data-ipa-font] .why-glyph,
html[data-ipa-font] .why-step-name {
  font-weight: var(--font-ipa-weight, 400);
  font-stretch: var(--font-ipa-stretch, 100%);
  letter-spacing: 0;
}

@media (prefers-reduced-motion: reduce) {
  .why-backdrop,
  .why-panel {
    animation: none;
  }
}

/* Phrasenreim: load indicator = animated sweep on the input/results hairline.
   Stays visible while searching even if the text field blurs.
   Same horizontal inset as .results::before (Trennstich) — never wider. */
.phrase-search-status {
  display: none;
  position: relative;
  width: auto;
  max-width: none;
  margin: 0.55rem var(--content-inline) 0;
  height: 1px;
  min-height: 1px;
  padding: 0;
  box-sizing: border-box;
  overflow: hidden;
  background: color-mix(in srgb, var(--line) 55%, transparent);
  justify-content: unset;
  align-items: unset;
}

html.is-searching .phrase-search-status,
html.is-phrase-searching .phrase-search-status,
#root.is-phrase-searching .phrase-search-status {
  display: block;
}

/* Results already on screen: the hairline sweeps. This node stays for
   aria-live and must not widen the rule or open the gap under it. */
html.is-searching[data-results="ready"] .phrase-search-status,
html.is-phrase-searching[data-results="ready"] .phrase-search-status,
#root.is-phrase-searching[data-results="ready"] .phrase-search-status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  border: 0;
  pointer-events: none;
}

.phrase-search-status[hidden] {
  display: none !important;
}

/* Shard reload: same hairline as Phrasenreim. Input stays typable. */
.shard-load-status {
  display: none;
}

html.is-shard-loading .shard-load-status:not([hidden]) {
  display: block;
  position: relative;
  /* Match .results::before / .phrase-search-status width. */
  width: auto;
  max-width: none;
  margin: 0.55rem var(--content-inline) 0;
}

.shard-load-status[hidden] {
  display: none !important;
}

.shard-load-line {
  position: relative;
  height: 1px;
  min-height: 1px;
  overflow: hidden;
  background: color-mix(in srgb, var(--line) 55%, transparent);
}

html.is-shard-loading .results::before {
  opacity: 0;
}

.shard-load-slow {
  margin: 0.35rem 0 0;
  font-size: 0.75rem;
  line-height: 1.3;
  text-align: center;
  color: var(--faint);
}

.shard-load-slow[hidden] {
  display: none;
}

.phrase-search-spinner {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 28%;
  border-radius: 0;
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  opacity: 1;
  transform: translateX(-120%);
  animation: phrase-load-sweep 1.15s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

@keyframes phrase-load-sweep {
  0% {
    transform: translateX(-120%);
    opacity: 0.35;
  }
  35% {
    opacity: 1;
  }
  100% {
    transform: translateX(420%);
    opacity: 0.35;
  }
}

@keyframes hairline-load-sweep {
  0% { background-position: -30% 0; }
  100% { background-position: 130% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .phrase-search-spinner {
    animation: none;
    left: 0;
    width: 100%;
    transform: none;
    opacity: 0.7;
  }

  html.is-searching[data-results="ready"] .results::before,
  html.is-phrase-searching[data-results="ready"] .results::before {
    animation: none;
    background-image: none;
  }
}

.rhyme.is-phrase.is-line .name {
  font-weight: 500;
}

/* Phrase rows: mono grid; column grows to fit — never horizontal scroll. */
.rhyme.is-phrase.is-line .rhyme-info {
  min-width: 0;
  width: 100%;
  max-width: 100%;
  overflow-x: visible;
}

.rhyme.is-phrase.is-line .analysis-stack.is-primary {
  max-width: none;
}

.phrase-empty {
  margin: 0.5rem 0 0;
  color: var(--muted);
  font-size: 0.95rem;
}

/* Phrasenreim: true monospace (Source Code Pro) — not Iosevka Aile (proportional). */
.phrase-source-strip,
.phrase-grid,
.phrase-grid .analysis-stack,
.phrase-grid .syl-ortho,
.phrase-grid .syl-ipa,
.phrase-grid .syl-brace,
.phrase-source-strip .analysis-stack,
.phrase-source-strip .syl-ortho,
.phrase-source-strip .syl-ipa,
.phrase-source-strip .syl-brace,
.phrase-col-gap {
  font-family: "Source Code Pro", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-variant-ligatures: none;
  font-feature-settings: "calt" 0, "liga" 0;
  letter-spacing: 0;
}

.phrase-source-strip {
  display: block;
  margin: 0 0 0.65rem;
  padding-left: var(--content-inline);
  padding-right: calc(var(--content-inline) + var(--score-col, 3.2rem));
  color: var(--muted);
  font-size: 1em;
  line-height: 1.35;
  overflow-x: visible;
}

.phrase-grid {
  display: inline-flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  white-space: pre;
  max-width: none;
}

.phrase-source-strip .phrase-col.is-lead {
  color: var(--muted);
  opacity: 0.78;
}

.phrase-source-strip .phrase-col.is-chunk {
  color: var(--ink);
  opacity: 1;
}

.phrase-col {
  display: inline-block;
  box-sizing: border-box;
  flex: 0 0 auto;
  overflow: visible;
  white-space: nowrap;
  vertical-align: top;
}

.phrase-col.is-spacer {
  color: transparent;
  user-select: none;
  pointer-events: none;
  min-height: 1.2em;
}

.phrase-col-gap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  width: 1ch;
  flex: 0 0 1ch;
  /* Match ortho line only — never the full syl+IPA stack (that pushed "-" high). */
  height: 1.2em;
  line-height: 1.2;
  color: inherit;
  user-select: none;
  position: relative;
}

.phrase-col-gap.is-hyphen {
  color: var(--ink);
  opacity: 1;
  font-weight: 600;
}

/* Word group wrapper — hyphens mark belonging. */
.phrase-span {
  display: inline-flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  flex: 0 0 auto;
  color: inherit;
}

.phrase-syl {
  display: block;
  min-width: 0;
  max-width: 100%;
}

.phrase-syl.analysis-stack {
  gap: 0;
  outline: none;
  box-shadow: none;
}

.phrase-syl .syl-cell {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  min-width: 0;
}

.phrase-syl .syl-ortho {
  display: block;
  font-family: inherit;
  white-space: pre;
  color: inherit;
  line-height: 1.2;
  height: 1.2em;
}

.phrase-syl .syl-ipa {
  /* Trust colors via .analysis-stack[data-trust-ipa] / .q-ipa-* (not --accent). */
  color: var(--muted);
  font-family: inherit;
  font-size: 0.78em;
  width: auto;
  min-width: 0;
  justify-content: center;
}

.phrase-syl.is-plain .syl-brace,
.phrase-syl.is-plain .syl-ipa {
  display: none;
}

.phrase-teilsatz-label {
  display: block;
  font-size: 0.72em;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.2em;
}

.rhyme.is-phrase.is-teilsatz.is-line {
  opacity: 0.92;
}

/* Phrasenreim: no analysis underlay on the input line */
html[data-phrase-rhyme="1"] #units,
html[data-phrase-rhyme="1"] .panel-units {
  display: none !important;
}
