/* ==========================================================================
   Mirai mini app — Sugar Paper
   The web twin of the iOS design system (Mirai/DesignSystem/Theme.swift):
   a warm paper canvas, white feather-shadow cards, pastel sticker accents,
   serif screen titles and rounded everything else.

   Every screen fits the viewport. Nothing here scrolls the page; a collection
   that cannot be bounded (the card grid, a chat transcript) carries its own
   .scroll-panel instead. See STYLE.md for the component vocabulary.
   ========================================================================== */

:root {
  /* Palette — Theme.swift, hex for hex. */
  --bg: #faf3ef;
  --surface: #ffffff;
  --ink: #3d3835;
  --ink-soft: #6f6660;
  --accent: #3d3835;
  --tab-tint: #9e6dd9;
  --sage: #5f7f66;
  --success: #4d7e5b;
  --danger: #b05252;
  --caution: #a8842c;

  /* The five pastels, in Theme.pastels order. */
  --butter: #f5f293;
  --mint: #ccecd6;
  --lilac: #d7ccf3;
  --powder: #cfe3f5;
  --pink: #f7d1dc;

  --line: rgba(61, 56, 53, 0.1);
  --line-strong: rgba(61, 56, 53, 0.18);
  --wash: rgba(61, 56, 53, 0.05);

  /* Shadows — featherShadow / stickerShadow / actionShadow. */
  --shadow-feather: 0 8px 16px rgba(61, 56, 53, 0.08);
  --shadow-sticker: 0 6px 14px rgba(61, 56, 53, 0.14);
  --shadow-action: 0 8px 13px rgba(61, 56, 53, 0.22);

  --radius-card: 28px;
  --radius-row: 24px;
  --radius-tile: 22px;
  --radius-sm: 14px;
  --radius-pill: 999px;

  --font-serif: "Source Serif 4", "Iowan Old Style", Georgia, serif;
  --font-round: "Nunito", ui-rounded, "SF Pro Rounded", system-ui, sans-serif;

  /* Legacy aliases: the feature stylesheets that still ship the old blue
     vocabulary re-tint through these instead of breaking. Delete as each
     feature file is repainted. */
  --bg-strong: #f3e9e2;
  --surface-strong: #ffffff;
  --surface-soft: rgba(255, 255, 255, 0.78);
  --surface-tinted: var(--powder);
  --blue: var(--accent);
  --blue-deep: var(--accent);
  --blue-soft: var(--powder);
  --peach: var(--pink);
  --peach-soft: var(--pink);
  --amber: var(--caution);
  --amber-soft: var(--butter);
  --mint-soft: rgba(204, 236, 214, 0.5);
  --shadow-xs: 0 2px 6px rgba(61, 56, 53, 0.06);
  --shadow-sm: var(--shadow-feather);
  --shadow-md: var(--shadow-feather);
  --shadow-lg: var(--shadow-sticker);
  --radius-xl: var(--radius-card);
  --radius-lg: var(--radius-tile);
  --radius-md: 18px;

  /* Telegram fullscreen mode: the client draws its own controls over the
     top edge and reports them through the --tg-* variables (Bot API 8.0);
     the device notch/home indicator arrive via env() and --tg-safe-area.
     Every screen pads with these two, so content never sits under either. */
  --device-safe-top: max(env(safe-area-inset-top, 0px), var(--tg-safe-area-inset-top, 0px));
  --device-safe-bottom: max(env(safe-area-inset-bottom, 0px), var(--tg-safe-area-inset-bottom, 0px));
  --content-safe-top: var(--tg-content-safe-area-inset-top, 0px);
  --content-safe-bottom: var(--tg-content-safe-area-inset-bottom, 0px);
  --safe-top: calc(var(--device-safe-top) + var(--content-safe-top));
  --safe-bottom: calc(var(--device-safe-bottom) + var(--content-safe-bottom));
  /* Bottom tab bar: the icons/labels row, plus the home-indicator inset it
     sits on top of. --tab-bar-space is 0 until the shell marks a screen as
     carrying the bar, so every screen can reserve room with one expression. */
  --tab-bar-height: 74px;
  --tab-bar-space: 0px;
}

* {
  box-sizing: border-box;
}

html,
body {
  min-height: 100%;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  /* Refuses double-tap zoom without touching the tap itself. The JS guard this
     replaces called preventDefault() on a second touchend inside 300 ms, which
     also cancelled that tap's click — a fast reveal → rate lost the rating. */
  touch-action: manipulation;
}

body {
  margin: 0;
  color: var(--ink);
  background: var(--bg);
  font-family: var(--font-round);
  font-size: 15px;
  -webkit-font-smoothing: antialiased;
}

button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
  touch-action: manipulation;
}

button {
  border: 0;
  cursor: pointer;
  background: transparent;
}

input,
textarea,
select {
  width: 100%;
  border: 0;
  outline: none;
  color: var(--ink);
  background: transparent;
  font-size: 16px;
}

textarea {
  resize: none;
}

a {
  color: inherit;
  text-decoration: none;
}

/* --------------------------------------------------------------- the page */

#app {
  position: relative;
  max-width: 430px;
  height: 100dvh;
  min-height: 100dvh;
  margin: 0 auto;
  padding: calc(var(--safe-top) + 8px) 16px calc(var(--safe-bottom) + 12px);
  overflow: hidden;
  background: var(--bg);
}

/* The two-tone Sugar Paper dot grid, drawn as one repeating pair so the warm
   and cool dots alternate the way Theme.DotGrid does on iOS. */
#app::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image:
    radial-gradient(circle, #ead0c8 1px, transparent 1.2px),
    radial-gradient(circle, #cbd9cf 1px, transparent 1.2px);
  background-size: 56px 56px, 56px 56px;
  background-position: 0 0, 28px 28px;
}

#app.allow-scroll {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
}

#app.has-tab-bar {
  --tab-bar-space: calc(var(--tab-bar-height) + var(--safe-bottom));
  padding-bottom: 0;
}

.app-shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
  min-height: 0;
}

#app.has-tab-bar .app-shell {
  height: calc(100% - var(--tab-bar-space));
}

#app.allow-scroll .app-shell {
  height: auto;
  min-height: calc(100% - var(--tab-bar-space));
  padding-bottom: 18px;
}

/* -------------------------------------------------------------- typography */

.serif-title {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 27px;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.section-title {
  margin: 0;
  font-size: 19px;
  font-weight: 800;
  color: var(--ink);
}

.label {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.eyebrow {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.muted,
.state-note {
  margin: 0;
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.42;
}

.state-note {
  text-align: center;
  max-width: 30ch;
}

.text-link {
  padding: 0;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
  background: transparent;
}

.text-link:active {
  opacity: 0.6;
}

.shell-topline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 18px;
  margin-bottom: -4px;
}

.shell-topline .text-link:only-child {
  margin-left: auto;
}

/* ------------------------------------------------------------- containers */

.card,
.panel,
.empty-card,
.hero-panel {
  position: relative;
  padding: 18px;
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
}

.panel-title {
  margin: 0;
  text-align: center;
  font-size: 18px;
  font-weight: 800;
  color: var(--ink);
}

.empty-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
  text-align: center;
}

.empty-card h2 {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 22px;
}

.inline-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* A bounded scroller — the ONE place inner scrolling is allowed: a collection
   with no ceiling (the card grid, a chat transcript, legal text). */
.scroll-panel {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: none;
}

.scroll-panel::-webkit-scrollbar {
  display: none;
}

/* Centred state block — sign-in, empty, error, maintenance, "all caught up". */
.state-shell,
.signin-shell {
  justify-content: center;
}

.state-block {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 0;
  text-align: center;
}

.state-block .serif-title {
  text-align: center;
}

/* ------------------------------------------------------------------ mascot */

.mascot {
  display: block;
  margin: 0 auto;
  flex: none;
}

.mascot-fallback {
  width: var(--mascot-size, 96px);
  height: var(--mascot-size, 96px);
  border-radius: 50%;
  background: var(--lilac);
  box-shadow: var(--shadow-sticker);
}

/* ----------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex: 1;
  min-height: 52px;
  padding: 0 20px;
  border-radius: 26px;
  font-size: 16px;
  font-weight: 800;
  color: var(--ink);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
  transition: transform 120ms ease, box-shadow 120ms ease, opacity 120ms ease;
}

.btn:active {
  transform: translateY(2px);
}

/* The ink keycap: a flat dark face on a warm lighter lip that thins as it
   sinks (iOS InkDepthButtonStyle). */
.btn.primary {
  color: #fff;
  background: var(--ink);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.14),
    inset 0 -3px 0 #6d6461,
    var(--shadow-action);
}

.btn.primary:active {
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.1),
    inset 0 -1px 0 #6d6461,
    0 4px 8px rgba(61, 56, 53, 0.18);
}

.btn.secondary {
  color: var(--ink);
  background: var(--surface);
}

.btn.butter {
  background: var(--butter);
  box-shadow: inset 0 -3px 0 rgba(61, 56, 53, 0.14), var(--shadow-feather);
}

.btn.ghost {
  color: var(--danger);
  background: transparent;
  box-shadow: none;
}

.btn.muted {
  color: var(--ink-soft);
  background: var(--wash);
  box-shadow: none;
}

.btn[disabled] {
  opacity: 0.42;
  transform: none;
  cursor: not-allowed;
}

.btn.short-btn {
  flex: 0 0 auto;
  min-width: 108px;
}

.btn-spinner {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: buttonSpin 700ms linear infinite;
}

.action-bar {
  display: flex;
  gap: 10px;
  margin-top: auto;
  padding-top: 2px;
}

.action-bar .btn {
  flex: 1;
}

/* Round chrome button — back, close, add, edit (iOS CircleIconButton). */
.circle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  color: var(--ink);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
  transition: transform 120ms ease;
}

.circle-btn:active {
  transform: scale(0.93);
}

.circle-btn svg {
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.circle-btn.is-dark {
  color: #fff;
  background: var(--ink);
  box-shadow: var(--shadow-action);
}

.circle-btn.is-on {
  color: var(--tab-tint);
  background: var(--lilac);
}

.circle-btn.is-danger {
  color: var(--danger);
}

.circle-btn.is-small {
  width: 30px;
  height: 30px;
}

.circle-btn.is-small svg {
  width: 15px;
  height: 15px;
}

/* Small pastel/neutral chip button — audio speed, editor tools. */
.chip-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 32px;
  padding: 0 12px;
  border-radius: var(--radius-pill);
  font-size: 12.5px;
  font-weight: 800;
  color: var(--ink);
  background: var(--wash);
  transition: transform 120ms ease, opacity 120ms ease;
}

.chip-btn:active {
  transform: scale(0.95);
}

.chip-btn.is-disabled,
.chip-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ------------------------------------------------------- pills & stickers */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  font-size: 12.5px;
  font-weight: 800;
  color: var(--ink);
  background: var(--wash);
  white-space: nowrap;
}

.pill[data-tone="butter"],
.pill-butter {
  background: var(--butter);
}

.pill[data-tone="mint"] {
  background: var(--mint);
}

.pill[data-tone="lilac"] {
  background: var(--lilac);
}

.pill[data-tone="powder"],
.pill-powder {
  background: var(--powder);
}

.pill[data-tone="pink"] {
  background: var(--pink);
}

.pill-center {
  align-self: center;
}

/* Old tag vocabulary, kept for the feature files that still emit it. */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  font-size: 12.5px;
  font-weight: 800;
  color: var(--ink);
  background: var(--wash);
}

.tag.active {
  background: var(--butter);
}

.tag.success {
  background: var(--mint);
}

.tag.warning {
  background: var(--pink);
}

/* A die-cut sticker: white halo, soft shadow, a couple of degrees of tilt. */
.sticker-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: var(--ink);
  background: var(--surface);
  box-shadow: var(--shadow-sticker);
}

.sticker-chip svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.sticker-tag {
  position: absolute;
  top: -8px;
  right: -6px;
  padding: 3px 8px;
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: 900;
  color: var(--ink);
  background: var(--butter);
  box-shadow: 0 0 0 3px var(--surface), var(--shadow-feather);
  transform: rotate(7deg);
}

/* LVL badge — the puck that hangs off the aperture ring. */
.lvl-badge {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sticker);
  line-height: 1;
}

.lvl-badge span {
  font-size: 8px;
  font-weight: 900;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
}

.lvl-badge strong {
  font-size: 19px;
  font-weight: 900;
  color: var(--ink);
}

.lvl-badge.is-small {
  width: 40px;
  height: 40px;
}

.lvl-badge.is-small strong {
  font-size: 16px;
}

.lvl-badge.is-next {
  background: transparent;
  border: 1.5px dashed var(--line-strong);
  box-shadow: none;
}

.lvl-badge.is-next span,
.lvl-badge.is-next strong {
  color: var(--ink-soft);
}

/* ------------------------------------------------------------------ inputs */

.text-input,
.text-area,
.field-select {
  padding: 13px 16px;
  border-radius: var(--radius-tile);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
  font-size: 16px;
  line-height: 1.4;
}

.text-area {
  min-height: 84px;
}

.field-rows {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}

.field-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 8px 6px 18px;
  border-radius: var(--radius-row);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.field-label {
  flex: none;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-soft);
}

.field-select {
  box-shadow: none;
  text-align: right;
  font-weight: 700;
  padding: 10px 6px;
}

.search-field {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  padding: 0 18px;
  min-height: 46px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.search-icon {
  display: inline-flex;
  color: var(--ink-soft);
}

.search-icon svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.search-input {
  font-size: 15px;
  font-weight: 600;
}

.search-input::placeholder {
  color: var(--ink-soft);
  opacity: 0.7;
}

/* ------------------------------------------------------------- screen bars */

/* Back · serif title · actions — the header on every pushed screen. */
.screen-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}

.screen-bar-title {
  flex: 1;
  min-width: 0;
  font-size: 25px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.screen-bar-count {
  font-family: var(--font-round);
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-soft);
}

.screen-bar-spacer {
  width: 38px;
  flex: none;
}

/* Legacy header slots (feature files). */
.screen-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.header-link {
  padding: 0;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
  background: transparent;
}

.header-spacer {
  display: block;
  flex: 1;
}

.home-toolbar {
  display: flex;
  justify-content: flex-end;
}

/* ------------------------------------------------------------------- tabbar */

.tab-bar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-bottom) + 8px);
  transform: translateX(-50%);
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 2px;
  width: min(398px, calc(100vw - 24px));
  padding: 6px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(14px);
  box-shadow: var(--shadow-feather);
}

.tab-bar-item {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 2px;
  border-radius: var(--radius-pill);
  color: var(--ink);
  transition: background 160ms ease, color 160ms ease;
}

.tab-bar-icon {
  display: inline-flex;
  width: 23px;
  height: 23px;
}

.tab-bar-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tab-bar-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.tab-bar-item.is-active {
  color: var(--tab-tint);
  background: rgba(61, 56, 53, 0.055);
}

.tab-bar-item.is-active .tab-bar-icon svg {
  stroke-width: 2.2;
}

/* --------------------------------------------------------------------- home */

/* One number drives the whole hero — the ring box, the ghostie inside it and
   where the two stickers ride the ring's diagonals. 188px on a 375-wide phone
   is iOS's 196-of-393 ring; 52vw keeps that proportion on a narrower phone.
   vh rather than dvh here: Telegram's WebView has no collapsing browser chrome
   (vh == dvh) and a WebView that rejects dvh would void the whole custom
   property and collapse the hero to nothing.
   The calc gives the height back on a short one: Home never scrolls, so on a
   667-tall screen the ring shrinks rather than pushing the doors under the tab
   bar. 485px is everything else the column needs (greeting, XP pair, streak,
   doors, review row, the gap above the tab bar), so the band between the
   streak pill and the doors comes out the same on every phone. */
.home-shell {
  --hero-size: clamp(
    96px,
    min(52vw, calc(100vh - var(--safe-top) - var(--safe-bottom) - 485px)),
    188px
  );
  gap: 0;
  align-items: center;
  text-align: center;
}

.home-shell .shell-topline {
  align-self: stretch;
}

.home-greeting {
  margin-top: 4px;
  font-size: 26px;
}

.home-hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--hero-size);
  height: var(--hero-size);
  margin-top: 6px;
  flex: none;
}

.aperture-ring {
  position: absolute;
  inset: 0;
  transform: rotate(-90deg);
  animation: ringSpin 34s linear infinite;
}

.ring-arc {
  fill: none;
  /* viewBox units, so this is 14px at a 188px ring and scales with the box. */
  stroke-width: 14;
  stroke-linecap: round;
  opacity: 0.28;
}

.ring-arc.is-lit {
  opacity: 1;
}

.ring-arc[data-tone="butter"] { stroke: var(--butter); }
.ring-arc[data-tone="mint"] { stroke: var(--mint); }
.ring-arc[data-tone="lilac"] { stroke: var(--lilac); }
.ring-arc[data-tone="powder"] { stroke: var(--powder); }
.ring-arc[data-tone="pink"] { stroke: var(--pink); }

/* The ghostie is a share of the ring, not the px the renderer stamps inline,
   so it follows --hero-size. 79.2% / 89.4% is the 1.55 x 1.75 ghostie frame
   measured against the ring box: the ghost body itself then lands at 96px
   inside a 188px ring — iOS's 98pt mascot in its 196pt ring. The !important
   is the only way past that inline width/height. */
.home-hero-ghostie {
  position: relative;
  z-index: 2;
  width: 79.2% !important;
  height: 89.4% !important;
}

/* Both stickers ride the ring's stroke centreline at 45 degrees, as on iOS.
   17.28% of the box is where that circle crosses the diagonal
   ((188 - 14) / 2 / sqrt(2), as a share of 188); half the sticker comes back
   off so it is the sticker's centre that lands there, at any ring size. */
.home-hero-pencil {
  position: absolute;
  top: calc(17.28% - 16px);
  left: calc(17.28% - 16px);
  z-index: 3;
  transform: rotate(-8deg);
}

.home-hero .lvl-badge {
  position: absolute;
  top: calc(82.72% - 23px);
  left: calc(82.72% - 23px);
  z-index: 3;
}

/* A short phone gives the ring back some diameter, so the two stickers come
   down with it — left at full size they swallow a 116px ring. Half of each
   sticker is still what comes off the diagonal. */
@media (max-height: 760px) {
  .home-hero-pencil {
    width: 26px;
    height: 26px;
    top: calc(17.28% - 13px);
    left: calc(17.28% - 13px);
  }

  .home-hero-pencil svg {
    width: 13px;
    height: 13px;
  }

  .home-hero .lvl-badge {
    width: 36px;
    height: 36px;
    top: calc(82.72% - 18px);
    left: calc(82.72% - 18px);
  }

  .home-hero .lvl-badge span {
    font-size: 6.5px;
  }

  .home-hero .lvl-badge strong {
    font-size: 15px;
  }
}

.home-xp-line {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin-top: 16px;
}

.home-xp-total {
  /* Reads under the ring the way iOS's 22pt total does, now that the ring is
     the biggest thing on the screen. */
  font-size: 24px;
  font-weight: 900;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.home-xp-next {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
}

.home-streak {
  position: relative;
  margin-top: 10px;
}

.home-streak-pill {
  display: inline-flex;
  align-items: center;
  padding: 7px 18px;
  border-radius: var(--radius-pill);
  font-size: 15px;
  font-weight: 900;
  color: var(--ink);
  background: var(--butter);
  box-shadow: var(--shadow-feather);
  transform: rotate(-2deg);
}

.home-streak-flame {
  position: absolute;
  top: -13px;
  right: -14px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  font-size: 14px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sticker);
}

/* The block sits off the tab bar rather than on it: the shell ends flush with
   the bar, so the margin is the whole gap the student sees under the review
   row. Anything left over after the hero has taken its share falls into the
   padding above the doors. */
.home-bottom {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-self: stretch;
  margin-top: auto;
  margin-bottom: 22px;
  padding-top: 16px;
}

/* Door tiles — the pastel gummy row (iOS DoorTile + GummyButtonStyle). */
.door-row {
  display: flex;
  gap: 11px;
}

.door-tile {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding: 13px 10px 12px;
  border-radius: var(--radius-tile);
  background: var(--wash);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.5),
    inset 0 -3px 0 rgba(61, 56, 53, 0.14),
    var(--shadow-feather);
  transition: transform 120ms ease, box-shadow 120ms ease;
}

.door-tile:active {
  transform: translateY(2px);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.4),
    inset 0 -1px 0 rgba(61, 56, 53, 0.14),
    0 3px 8px rgba(61, 56, 53, 0.1);
}

.door-tile[data-tone="lilac"] { background: var(--lilac); }
.door-tile[data-tone="butter"] { background: var(--butter); }
.door-tile[data-tone="mint"] { background: var(--mint); }
.door-tile[data-tone="powder"] { background: var(--powder); }
.door-tile[data-tone="pink"] { background: var(--pink); }

.door-disc {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.door-disc svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.door-disc img {
  width: 24px;
  height: 24px;
  object-fit: contain;
}

.door-title {
  font-size: 14px;
  font-weight: 800;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.door-detail {
  font-size: 11.5px;
  font-weight: 700;
  color: rgba(61, 56, 53, 0.55);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Wide link row — one tap target across the shell (iOS WideLinkRow). */
.wide-row {
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  padding: 13px 18px;
  border-radius: var(--radius-row);
  text-align: left;
  background: var(--mint);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.45),
    inset 0 -3px 0 rgba(61, 56, 53, 0.12),
    var(--shadow-feather);
  transition: transform 120ms ease;
}

.wide-row:active {
  transform: translateY(2px);
}

.wide-row[data-tone="powder"] { background: var(--powder); }
.wide-row[data-tone="lilac"] { background: var(--lilac); }

.wide-row-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
}

.wide-row-icon img {
  width: 28px;
  height: 28px;
  object-fit: contain;
}

.wide-row-icon svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: var(--sage);
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.wide-row-copy {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1;
  min-width: 0;
}

.wide-row-title {
  font-size: 17px;
  font-weight: 800;
  color: var(--ink);
}

.wide-row-detail {
  font-size: 13px;
  font-weight: 600;
  color: rgba(61, 56, 53, 0.58);
}

.wide-row-chevron svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: rgba(61, 56, 53, 0.4);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --------------------------------------------------------------- homework */

.homework-shell {
  gap: 12px;
}

.stage-chrome {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: none;
}

.stage-head {
  display: flex;
  align-items: center;
  gap: 9px;
}

.stage-title {
  font-size: 19px;
  font-weight: 800;
  color: var(--ink);
}

.stage-counter {
  margin-left: auto;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink-soft);
}

.stage-steps {
  display: flex;
  gap: 8px;
  padding: 0 2px;
}

.stage-step {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: var(--line);
}

.stage-step.is-on {
  background: var(--ink);
}

.stage-dots {
  display: flex;
  gap: 7px;
  justify-content: center;
}

.stage-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
}

.stage-dot.is-done {
  background: rgba(61, 56, 53, 0.28);
  box-shadow: none;
}

.stage-dot.is-current {
  background: var(--ink);
  box-shadow: none;
}

.stage-ticks {
  display: flex;
  gap: 3px;
  justify-content: center;
}

.stage-tick {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--line);
}

.stage-tick.is-done {
  background: var(--ink);
}

/* Verdict banner (production / listening). */
.feedback-card {
  padding: 11px 14px;
  border-radius: var(--radius-tile);
  background: var(--wash);
}

.feedback-card.success { background: var(--mint); }
.feedback-card.warning { background: var(--butter); }
.feedback-card.info { background: var(--powder); }
.feedback-card.coach { background: var(--lilac); }
.feedback-card.error { background: var(--pink); }

.feedback-title {
  margin: 0 0 2px;
  font-size: 13px;
  font-weight: 900;
  color: var(--ink);
}

.feedback-note {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--ink);
}

/* The composer: a white pill holding the field and the round send button. */
.hw-composer {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex: none;
  margin-top: auto;
}

.hw-composer.is-action {
  display: block;
}

.hw-composer.is-action .btn {
  width: 100%;
}

.composer-field {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  padding: 8px 8px 8px 18px;
  border-radius: 26px;
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

/* The auto-growing field: an invisible ::after mirror of the typed text
   occupies the same grid cell, so the textarea is exactly as tall as its
   content — one line when empty, up to four before it scrolls. */
.composer-grow {
  display: grid;
  flex: 1;
  min-width: 0;
  max-height: 92px;
  overflow-y: auto;
  scrollbar-width: none;
}

.composer-grow::-webkit-scrollbar {
  display: none;
}

.composer-grow::after {
  content: attr(data-value) " ";
  visibility: hidden;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.composer-input,
.composer-grow::after {
  grid-area: 1 / 1;
  min-width: 0;
  padding: 6px 0;
  font-family: inherit;
  font-size: 15.5px;
  line-height: 1.35;
  overflow: hidden;
}

.composer-input::placeholder {
  color: var(--ink-soft);
  opacity: 0.72;
}

.composer-hint {
  flex: none;
  padding: 7px 12px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 800;
  color: var(--ink);
  background: var(--wash);
}

.composer-hint.is-hidden {
  display: none;
}

.composer-send {
  display: grid;
  place-items: center;
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  color: #fff;
  background: var(--ink);
  box-shadow: var(--shadow-action);
  transition: transform 120ms ease;
}

.composer-send:active {
  transform: scale(0.94);
}

.composer-send[disabled] {
  opacity: 0.45;
}

.composer-send svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Listening. */
.audio-player {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: none;
  padding: 14px 16px;
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.play-button {
  display: grid;
  place-items: center;
  flex: none;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  color: #fff;
  background: var(--ink);
  box-shadow: var(--shadow-action);
  transition: transform 120ms ease;
}

.play-button:active {
  transform: scale(0.94);
}

.play-button svg {
  width: 26px;
  height: 26px;
  fill: currentColor;
  stroke: none;
  margin-left: 3px;
}

.play-button.playing svg {
  animation: audioPulse 1.4s ease-in-out infinite;
}

.audio-meta {
  display: flex;
  flex-direction: column;
  gap: 9px;
  flex: 1;
  min-width: 0;
}

.audio-title {
  font-size: 16px;
  font-weight: 800;
  color: var(--ink);
}

.audio-control-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.audio-rate-readout {
  min-width: 34px;
  padding: 5px 0;
  border-radius: var(--radius-pill);
  text-align: center;
  font-size: 12.5px;
  font-weight: 800;
  color: var(--ink);
  background: var(--pink);
}

.cloze-panel {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}

.cloze-panel::-webkit-scrollbar {
  display: none;
}

.cloze-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  row-gap: 9px;
  column-gap: 0;
  font-size: 17px;
  line-height: 1.5;
  color: var(--ink);
}

.cloze-text,
.cloze-word {
  font-weight: 600;
  white-space: pre-wrap;
}

.cloze-input {
  min-height: 38px;
  padding: 0 10px;
  border-radius: var(--radius-sm);
  text-align: center;
  font-size: 15px;
  font-weight: 800;
  color: var(--ink);
  background: var(--bg);
  box-shadow: inset 0 0 0 1.5px var(--line-strong);
}

.cloze-input.locked {
  background: var(--mint);
  box-shadow: none;
  opacity: 1;
  -webkit-text-fill-color: var(--ink);
}

.cloze-input.revealed.locked {
  background: var(--butter);
}

.cloze-input.wrong {
  background: var(--pink);
  box-shadow: none;
}

.cloze-diagnostic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 0 10px;
  border-radius: var(--radius-sm);
  font-size: 15px;
  font-weight: 800;
  background: var(--pink);
}

.cloze-diagnostic-segment {
  letter-spacing: 0.01em;
}

.cloze-diagnostic-segment.match { color: var(--ink); }
.cloze-diagnostic-segment.wrong { color: var(--danger); text-decoration: line-through; }
.cloze-diagnostic-segment.missing { color: var(--danger); opacity: 0.55; }

/* Read-only "previous item" review. */
.review-quote {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 11px 14px;
  border-radius: var(--radius-tile);
  background: var(--powder);
}

.review-quote.is-good {
  background: var(--mint);
}

.review-quote q {
  font-size: 15px;
  font-weight: 700;
  quotes: "\201C" "\201D";
}

.review-answer {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
}

/* Homework complete. */
.hw-done-shell {
  gap: 10px;
  align-items: center;
}

.hw-done-title {
  text-align: center;
  font-size: 28px;
}

.hw-done-mascot {
  margin: 2px 0 4px;
}

/* Title and mascot are fixed; the stats card and the "What you did" list share
   one scroller below them, so opening the list never squeezes the summary. */
.hw-done-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-self: stretch;
  padding: 2px 0;
}

/* Cards inside a column scroller keep their natural height — otherwise flex
   squashes them and the panel clips instead of scrolling. */
.hw-done-body > * {
  flex: none;
}

.hw-done-shell .action-bar {
  align-self: stretch;
}

.hw-summary-card {
  gap: 4px;
  padding: 12px 16px;
}

.hw-summary-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  font-size: 15px;
  font-weight: 700;
}

.hw-review-card {
  padding: 0;
  overflow: hidden;
}

.hw-review-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 15px 18px;
  text-align: left;
}

.hw-review-title {
  font-size: 17px;
  font-weight: 800;
}

.hw-review-chevron {
  margin-left: auto;
  display: inline-flex;
  transition: transform 200ms ease;
}

.hw-review-chevron svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: rgba(61, 56, 53, 0.45);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: rotate(90deg);
}

.hw-review-chevron.is-open svg {
  transform: rotate(-90deg);
}

.hw-review-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 0 18px 16px;
}

.hw-review-row {
  display: flex;
  gap: 10px;
}

.hw-review-dot {
  flex: none;
  width: 9px;
  height: 9px;
  margin-top: 5px;
  border-radius: 50%;
  background: var(--butter);
}

.hw-review-dot[data-tone="1"] { background: var(--mint); }
.hw-review-dot[data-tone="2"] { background: var(--lilac); }
.hw-review-dot[data-tone="3"] { background: var(--powder); }
.hw-review-dot[data-tone="4"] { background: var(--pink); }

.hw-review-body {
  min-width: 0;
}

.hw-review-stage {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.hw-review-headline {
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.35;
}

.hw-review-note {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------- wall of fame */

.wall-shell {
  gap: 0;
  align-items: center;
}

.wall-head {
  text-align: center;
}

.wall-head .serif-title {
  font-size: 29px;
}

.wall-sub {
  margin: 3px 0 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
}

.wall-stage {
  position: relative;
  width: 100%;
  height: 356px;
  flex: none;
  margin-top: 14px;
}

/* One photo needs no room for the pair below it. */
.wall-stage[data-count="1"] { height: 216px; }

/* With no third photo the runner-up moves in from the edge, so a two-student
   wall reads as a composition instead of a gap. */
.wall-stage[data-count="2"] .polaroid.rank-2 { left: 30px; }

.polaroid {
  position: absolute;
  padding: 10px 10px 12px;
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-sticker);
}

.polaroid.rank-1 {
  width: 168px;
  left: 50%;
  top: 0;
  transform: translateX(-50%) rotate(-2deg);
  z-index: 3;
}

.polaroid.rank-2 {
  width: 143px;
  left: 2px;
  top: 178px;
  transform: rotate(-5deg);
  z-index: 2;
}

.polaroid.rank-3 {
  width: 143px;
  right: 2px;
  top: 188px;
  transform: rotate(4deg);
  z-index: 1;
}

.polaroid-tape {
  position: absolute;
  top: -9px;
  left: 50%;
  width: 58px;
  height: 17px;
  border-radius: 3px;
  transform: translateX(-50%) rotate(3deg);
  background: rgba(245, 242, 147, 0.75);
}

.polaroid.rank-2 .polaroid-tape {
  background: rgba(207, 227, 245, 0.78);
  transform: translateX(-50%) rotate(-4deg);
}

.polaroid.rank-3 .polaroid-tape {
  background: rgba(204, 236, 214, 0.8);
  transform: translateX(-50%) rotate(5deg);
}

.polaroid-photo {
  position: relative;
  display: grid;
  place-items: center;
  height: 110px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--mint);
}

.polaroid.rank-2 .polaroid-photo { height: 82px; background: var(--lilac); }
.polaroid.rank-3 .polaroid-photo { height: 82px; background: var(--pink); }

.polaroid-medal {
  position: absolute;
  right: 6px;
  bottom: 4px;
  font-size: 19px;
}

/* Written under the photo the way a caption is: the name on its own line with
   the whole width of the card, the month's XP under it. Beside the XP the name
   only had ~90px and a fourteen-letter student came out as "Review Sa…". */
.polaroid-caption {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  margin-top: 7px;
}

.polaroid-name {
  font-family: var(--font-serif);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.15;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.polaroid.rank-1 .polaroid-name {
  font-size: 16px;
}

.polaroid-xp {
  font-size: 11px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ink-soft);
}

.polaroid-prize {
  margin-top: 5px;
  font-size: 10px;
  padding: 4px 9px;
  transform: rotate(-2deg);
}

.polaroid.is-mine {
  box-shadow: 0 0 0 2.5px rgba(61, 56, 53, 0.5), var(--shadow-sticker);
}

.polaroid-you {
  position: absolute;
  top: -7px;
  right: -6px;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  font-size: 9px;
  font-weight: 900;
  color: #fff;
  background: var(--ink);
}

.wall-place {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-top: 10px;
  padding: 12px 16px;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-feather);
  transform: rotate(-1deg);
}

.wall-place-avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--powder);
  font-size: 20px;
}

.wall-place-copy {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.wall-place-title {
  font-family: var(--font-serif);
  font-size: 15.5px;
  font-weight: 700;
}

.wall-place-detail {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
}

.wall-note {
  margin: 12px 0 0;
  font-size: 12.5px;
  color: var(--ink-soft);
  opacity: 0.85;
}

.wall-rules {
  margin-top: 10px;
  font-size: 12.5px;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ------------------------------------------------------------ mirai cards */

.cards-shell,
.editor-shell,
.study-shell {
  gap: 12px;
}

.cards-count {
  margin: -4px 0 0;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
}

.cards-scroll {
  margin: 0 -4px;
  padding: 2px 4px 4px;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

/* The search hides tiles rather than rebuilding the grid, so a keystroke never
   drops an <img> the next keystroke would ask for again. `hidden` is the whole
   mechanism — spelled out here because the grid item would otherwise beat the
   UA rule. The count line and the "nothing matches" note ride along the same
   way, so they are patched in place too. */
.card-tile[hidden],
.cards-count[hidden],
.cards-empty[hidden] {
  display: none;
}

.card-tile {
  position: relative;
  padding: 9px;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.card-tile-art {
  display: grid;
  place-items: center;
  height: 82px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--mint);
}

.card-tile-art[data-tone="mint"] { background: var(--mint); }
.card-tile-art[data-tone="powder"] { background: var(--powder); }
.card-tile-art[data-tone="lilac"] { background: var(--lilac); }
.card-tile-art[data-tone="butter"] { background: var(--butter); }
.card-tile-art[data-tone="pink"] { background: var(--pink); }

.card-tile-art img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card-tile-art {
  position: relative;
}

.card-tile-initial {
  font-size: 34px;
  font-weight: 800;
  color: rgba(61, 56, 53, 0.34);
}

.card-tile-body {
  padding: 9px 5px 3px;
}

.card-tile-body h3,
.card-tile-body p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.card-tile-body h3 {
  margin: 0;
  -webkit-line-clamp: 2;
  font-size: 14.5px;
  font-weight: 800;
  line-height: 1.25;
  color: var(--ink);
}

.card-tile-body p {
  margin: 3px 0 0;
  -webkit-line-clamp: 1;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
}

.card-tile-actions {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  gap: 5px;
}

/* ----------------------------------------------------------- card editor */

.editor-panel {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
}

/* iOS's CardEditorView is one top-anchored stack — photo, fields, tools, then
   the buttons at the same gap — so the editor's action bar rides under the
   panel instead of being pinned to the bottom of the screen. Pinned, it left a
   tall void in the middle and put Save under the keyboard the moment a field
   took focus. */
.editor-shell .action-bar {
  margin-top: 0;
}

.editor-panel::-webkit-scrollbar {
  display: none;
}

.editor-fields {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.editor-input {
  padding: 12px 14px;
  border-radius: var(--radius-tile);
  background: var(--bg);
  font-size: 16px;
  line-height: 1.35;
}

.mirai-field-wrap {
  position: relative;
}

.mirai-field-front {
  padding-right: 54px;
}

.mirai-field-icon-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  cursor: pointer;
  color: var(--ink-soft);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

.mirai-field-icon-btn.has-image {
  color: var(--ink);
  background: var(--mint);
}

.mirai-field-icon-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------------------------------------------------------------- study */

.study-rail {
  display: flex;
  align-items: center;
  gap: 11px;
  flex: none;
}

.study-rail-mid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
}

.track {
  display: block;
  width: 100%;
  height: 9px;
  border-radius: var(--radius-pill);
  background: rgba(61, 56, 53, 0.12);
  overflow: hidden;
}

.track-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--ink);
  transition: width 320ms ease;
}

.study-rail-note {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
}

.mirai-chip-row {
  display: flex;
  gap: 7px;
  justify-content: center;
  flex: none;
}

.mirai-chip {
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  font-weight: 800;
  color: var(--ink);
  background: var(--wash);
}

.mirai-chip[data-tone="powder"] { background: var(--powder); }
.mirai-chip[data-tone="butter"] { background: var(--butter); }
.mirai-chip[data-tone="mint"] { background: var(--mint); }

/* The flip card: one element with two faces, rotated in place.

   Everything below is written for WebKit (Telegram's WKWebView), where a
   rotating layer is only cheap if nothing inside it has to be re-rasterized
   per frame:
   - the drop shadow lives on this static wrapper, not on the rotating faces,
     so the shadow is painted once and the paper turns above it (a shadow on a
     backface-hidden 3D layer is re-rendered every frame of the rotation);
   - the faces carry no overflow clip — a rounded overflow:hidden on a
     3D-transformed layer forces WebKit onto a masked path that re-rasterizes
     as the layer turns. Everything that could paint outside the corners is
     rounded on its own box instead (the dot pattern inherits the radius, the
     art panel and its photo carry theirs);
   - .flip-inner is promoted with will-change, so both faces are rasterized
     once and the 560 ms rotation is a compositor transform;
   - the faces are inset:0 inside a wrapper that is sized by the layout, so
     nothing re-lays-out while the transform runs. */
.flip-card {
  position: relative;
  flex: 1;
  min-height: 0;
  perspective: 1400px;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-feather);
}

.flip-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 560ms cubic-bezier(0.2, 0.8, 0.28, 1);
  will-change: transform;
}

.flip-card.is-flipped .flip-inner {
  transform: rotateY(180deg);
}

/* A rated card leaves in the frame of the tap — before the server answers —
   and its replacement arrives rather than snapping in. Opacity and transform
   only, so both run on the compositor without touching layout.

   The card lifts off its slot rather than taking the slot with it: the wrapper
   keeps its shadow and shows the paper underneath, so the wait has somewhere
   to happen instead of leaving a hole in the screen. The fade sits on the two
   faces (opacity on .flip-inner would flatten the preserve-3d context and
   break the rotation mid-flight). */
.flip-card.is-leaving {
  background: var(--surface);
}

.flip-card.is-leaving .flip-inner {
  transform: translateY(-16px) scale(0.98);
  transition: transform 190ms cubic-bezier(0.4, 0, 0.6, 1);
}

.flip-card.is-flipped.is-leaving .flip-inner {
  transform: rotateY(180deg) translateY(-16px) scale(0.98);
}

.flip-card.is-leaving .flip-face {
  opacity: 0;
  transition: opacity 190ms ease;
}

/* The three dots only reach full strength if the round trip is slow enough to
   notice; a quick answer swaps the card before they are ever seen. */
.flip-wait {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  pointer-events: none;
}

.flip-card.is-leaving .flip-wait {
  opacity: 1;
  transition: opacity 220ms ease 260ms;
}

@keyframes flip-card-enter {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.flip-card.is-entering {
  animation: flip-card-enter 200ms cubic-bezier(0.2, 0.8, 0.28, 1) both;
}

.flip-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 22px;
  border-radius: var(--radius-card);
  text-align: center;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.flip-front {
  color: #fff;
  background:
    radial-gradient(circle at 22% 18%, rgba(255, 255, 255, 0.14), transparent 46%),
    #8b82a0;
  justify-content: flex-end;
  /* Identity transform: an explicit hint that this face is its own layer, so
     the gradient and the dot pattern rasterize once. */
  transform: translateZ(0);
}

.flip-front::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0.5;
  background-image: radial-gradient(circle, rgba(43, 39, 52, 0.55) 0.7px, transparent 0.9px);
  background-size: 13px 13px;
}

/* Long words stay inside the card now that the face itself does not clip.
   A plain rectangular clip on a text box costs nothing; a rounded one on the
   rotating face costs a re-raster per frame. */
.flip-word,
.flip-answer,
.flip-head {
  max-height: 100%;
  overflow: hidden;
}

.flip-art {
  z-index: 1;
  position: absolute;
  top: 18px;
  left: 18px;
  right: 18px;
  bottom: 96px;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.14);
}

.flip-art img {
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: contain;
}

.flip-word {
  position: relative;
  z-index: 1;
  font-size: 30px;
  font-weight: 900;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.flip-state {
  position: relative;
  z-index: 1;
  font-size: 14px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.72);
}

.flip-back {
  align-items: flex-start;
  justify-content: flex-start;
  color: var(--ink);
  background: #fbf7ee;
  transform: rotateY(180deg);
}

.flip-head {
  font-size: 20px;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.flip-rule {
  width: 100%;
  height: 1.5px;
  background: rgba(61, 56, 53, 0.35);
}

.flip-answer {
  margin-top: 8px;
  font-size: 30px;
  font-weight: 900;
  line-height: 1.15;
  text-align: left;
  overflow-wrap: anywhere;
}

.flip-ask {
  margin-top: auto;
  width: 100%;
  text-align: center;
  font-size: 14px;
  color: var(--ink-soft);
}

.flip-coach {
  margin: 0;
  align-self: center;
  padding: 9px 18px;
  border-radius: var(--radius-pill);
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-soft);
  background: var(--surface);
  box-shadow: var(--shadow-feather);
}

/* Both footers ship with every study render and the card's own data-flip picks
   the one that is up, so revealing an answer is an attribute write on the live
   DOM — no rebuild, no re-decoded photo, no two-frame wait for the rotation. */
.flip-card[data-flip="0"] ~ .mirai-rating-row,
.flip-card[data-flip="1"] ~ .flip-coach {
  display: none;
}

.mirai-rating-row {
  display: flex;
  gap: 8px;
  flex: none;
}

.mirai-rating-btn {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  min-width: 0;
  padding: 11px 4px 10px;
  border-radius: 18px;
  box-shadow: inset 0 -3px 0 rgba(61, 56, 53, 0.12), var(--shadow-feather);
  transition: transform 120ms ease;
}

.mirai-rating-btn:active {
  transform: translateY(2px);
}

.mirai-rating-btn[disabled] {
  opacity: 0.5;
}

/* The rating you tapped stays pressed and lit while the other three dim, from
   the frame of the tap until the server answers. */
.mirai-rating-btn.is-chosen {
  transform: translateY(2px);
  box-shadow: inset 0 -1px 0 rgba(61, 56, 53, 0.12), var(--shadow-feather);
}

.mirai-rating-btn[disabled].is-chosen {
  opacity: 1;
}

.mirai-rating-btn.again { background: var(--pink); color: #b05252; }
.mirai-rating-btn.hard { background: var(--butter); color: #7e5117; }
.mirai-rating-btn.good { background: var(--mint); color: #4d7e5b; }
.mirai-rating-btn.easy { background: var(--powder); color: #41709a; }

.mirai-rating-icon svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.mirai-rating-label {
  font-size: 14.5px;
  font-weight: 900;
}

.mirai-rating-step {
  font-size: 11.5px;
  font-weight: 700;
  opacity: 0.85;
}

/* ------------------------------------------------------- loading / sign-in */

.loading-shell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  height: 100%;
}

.loading-mark {
  font-family: var(--font-serif);
  font-size: 34px;
  font-weight: 700;
  color: var(--ink);
}

.loading-dots {
  display: flex;
  gap: 7px;
}

.loading-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ink);
  opacity: 0.25;
  animation: loadingDot 1.1s ease-in-out infinite;
}

.loading-dots span:nth-child(2) { animation-delay: 0.15s; }
.loading-dots span:nth-child(3) { animation-delay: 0.3s; }

.signin-block {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  min-height: 0;
}

.signin-title {
  font-size: 34px;
}

.skeleton {
  height: 14px;
  border-radius: var(--radius-pill);
  background: var(--wash);
}

.skeleton.card {
  height: 84px;
  border-radius: var(--radius-card);
}

/* ------------------------------------------------------------------ toast */

.toast-stack {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-bottom) + 18px);
  transform: translateX(-50%);
  z-index: 60;
  width: min(390px, calc(100vw - 36px));
}

body.has-tab-bar .toast-stack {
  bottom: calc(var(--safe-bottom) + var(--tab-bar-height) + 18px);
}

.toast {
  padding: 12px 16px;
  border-radius: var(--radius-tile);
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  background: var(--surface);
  box-shadow: var(--shadow-sticker);
}

.toast.success { background: var(--mint); }
.toast.warning { background: var(--pink); }
.toast.info { background: var(--powder); }

/* The PNG home-door icon (the leaderboard trophy) inside a .door-disc. */

.icon-badge-image {
  width: 24px;
  height: 24px;
  object-fit: contain;
}

/* -------------------------------------------------------------- keyframes */

@keyframes buttonSpin {
  to { transform: rotate(360deg); }
}

@keyframes ringSpin {
  from { transform: rotate(-90deg); }
  to { transform: rotate(270deg); }
}

@keyframes loadingDot {
  0%, 100% { opacity: 0.2; transform: translateY(0); }
  50% { opacity: 0.75; transform: translateY(-4px); }
}

@keyframes audioPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

@keyframes questionPulseSuccess {
  0% { box-shadow: var(--shadow-feather); }
  40% { box-shadow: 0 0 0 3px rgba(77, 126, 91, 0.35), var(--shadow-feather); }
  100% { box-shadow: var(--shadow-feather); }
}

@keyframes questionPulseWarning {
  0% { box-shadow: var(--shadow-feather); }
  40% { box-shadow: 0 0 0 3px rgba(176, 82, 82, 0.32), var(--shadow-feather); }
  100% { box-shadow: var(--shadow-feather); }
}

.question-card-pulse-success {
  animation: questionPulseSuccess 720ms ease;
}

.question-card-pulse-warning {
  animation: questionPulseWarning 720ms ease;
}

@keyframes xpGainFloat {
  0% { opacity: 0; transform: translateY(10px) scale(0.9); }
  22% { opacity: 1; transform: translateY(0) scale(1); }
  78% { opacity: 1; transform: translateY(-8px) scale(1); }
  100% { opacity: 0; transform: translateY(-22px) scale(0.95); }
}

.xp-gain-overlay {
  position: fixed;
  left: 50%;
  top: calc(var(--safe-top) + 60px);
  transform: translateX(-50%);
  z-index: 55;
  pointer-events: none;
}

.xp-gain-chip {
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  font-size: 15px;
  font-weight: 900;
  color: var(--ink);
  background: var(--butter);
  box-shadow: var(--shadow-sticker);
  animation: xpGainFloat 1600ms ease forwards;
}

/* The XP shell survives for the feature screens that still ask for it. */
.xp-shell {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.xp-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.xp-head strong {
  font-size: 19px;
  font-weight: 900;
}

.xp-meta {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
}

.xp-track {
  height: 9px;
  border-radius: var(--radius-pill);
  background: rgba(61, 56, 53, 0.12);
  overflow: hidden;
}

.xp-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--ink);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ------------------------------------------------------------ parent mode
   Untouched from the previous system apart from the shared tokens it reads;
   the parent screens get their own design pass. */

.parent-screen-head {
  display: grid;
  grid-template-columns: minmax(72px, 1fr) auto minmax(72px, 1fr);
  align-items: center;
  gap: 10px;
}

.parent-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.parent-legend-copy {
  margin-top: 16px;
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1.5;
}

.legend-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 12px;
  font-weight: 800;
}

.legend-pill.scheduled {
  background: rgba(86, 119, 255, 0.16);
  color: var(--blue-deep);
}

.legend-pill.attended,
.legend-pill.complete {
  background: rgba(79, 191, 145, 0.14);
  color: #1f7a57;
}

.legend-pill.skipped {
  background: rgba(255, 122, 122, 0.16);
  color: #b64a4a;
}

.legend-pill.partial {
  background: rgba(255, 184, 77, 0.2);
  color: #9d6400;
}

.legend-pill.mirai-q1 { background: rgba(79, 191, 145, 0.14); color: #226c50; }
.legend-pill.mirai-q2 { background: rgba(79, 191, 145, 0.22); color: #206548; }
.legend-pill.mirai-q3 { background: rgba(79, 191, 145, 0.3); color: #1a5d40; }
.legend-pill.mirai-q4 { background: rgba(79, 191, 145, 0.4); color: #174e36; }
.legend-pill.mirai-q5 { background: rgba(79, 191, 145, 0.54); color: #10412c; }

.parent-metric {
  margin-top: 16px;
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 700;
}

.parent-metric strong {
  color: var(--ink);
  font-family: "Sora", sans-serif;
  font-size: 22px;
}

.parent-metric-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-top: 4px;
}

.parent-metric-card {
  display: grid;
  gap: 3px;
  min-height: 72px;
  padding: 9px 10px;
  border-radius: 18px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.78);
  box-shadow: var(--shadow-sm);
  justify-items: center;
  align-content: center;
  text-align: center;
}

.parent-metric-label {
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.2;
}

.parent-metric-value {
  align-self: center;
  justify-self: center;
  color: var(--ink);
  font-family: "Sora", sans-serif;
  font-size: 24px;
  font-weight: 900;
  letter-spacing: -0.03em;
  line-height: 1;
}

.week-nav {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) 40px;
  align-items: center;
  margin-top: 14px;
  position: relative;
  z-index: 19;
}

.week-nav-spacer {
  min-height: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-align: center;
}

.week-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 40px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.88);
  box-shadow: var(--shadow-sm);
}

.week-arrow-left {
  justify-self: start;
}

.week-arrow-right {
  justify-self: end;
}

.parent-week-stage {
  position: relative;
}

.parent-week-stage.is-swipe-forward {
  animation: parentWeekSlideForward 280ms ease;
}

.parent-week-stage.is-swipe-backward {
  animation: parentWeekSlideBackward 280ms ease;
}

.parent-home-shell {
  position: relative;
  gap: 8px;
}

.parent-home-shell .home-toolbar {
  padding: 0 4px 0;
  margin-bottom: -8px;
}

.parent-home-shell.has-role-switch .home-toolbar {
  margin-bottom: -14px;
  transform: translateY(-6px);
}

.parent-hero {
  gap: 1px;
  padding: 10px 14px 8px;
}

.parent-hero::after {
  width: 70px;
  height: 70px;
  inset: auto -16px -28px auto;
  border-radius: 22px;
}

.parent-hero .section-title {
  margin: 0;
  font-size: 20px;
  line-height: 0.98;
}

.parent-hero .muted {
  margin: 0;
  font-size: 12px;
  line-height: 1.28;
}

.parent-overview-card {
  display: grid;
  gap: 10px;
}

.parent-overview-card.is-sheet-open .week-nav {
  visibility: hidden;
  pointer-events: none;
}

.parent-loading-copy {
  display: grid;
  gap: 6px;
}

.parent-loading-copy h3 {
  margin: 0;
  font-family: "Sora", sans-serif;
  font-size: 24px;
  letter-spacing: -0.04em;
}

.parent-week-rows {
  display: grid;
  gap: 8px;
  margin-top: 8px;
}

.parent-weekday-header {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr);
  align-items: end;
  gap: 8px;
}

.parent-weekday-spacer {
  min-height: 1px;
}

.parent-weekday-strip {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
}

.parent-weekday-label {
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-align: center;
  text-transform: lowercase;
}

.parent-row {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}

.parent-row-label {
  color: var(--ink-soft);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.parent-week-strip {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
  margin-top: 8px;
}

.parent-week-strip-inline {
  margin-top: 0;
}

.parent-day {
  display: grid;
  justify-items: center;
  gap: 3px;
  min-height: 66px;
  padding: 10px 4px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.72);
  box-shadow: var(--shadow-sm);
}

.parent-day-date {
  font-family: "Sora", sans-serif;
  font-size: 18px;
  font-weight: 800;
}

.parent-day-mark {
  font-size: 16px;
  font-weight: 900;
  line-height: 1;
}

.parent-day.is-active {
  box-shadow: 0 0 0 2px rgba(86, 119, 255, 0.2), var(--shadow-sm);
  transform: translateY(-1px);
}

.parent-day-none,
.parent-day-scheduled {
  background: rgba(137, 148, 163, 0.16);
  color: #667185;
}

.parent-day-attended,
.parent-day-complete {
  background: rgba(79, 191, 145, 0.16);
  color: #17523b;
}

.parent-day-skipped,
.parent-day-zero,
.parent-day-missed {
  background: rgba(255, 122, 122, 0.18);
  color: #a73f3f;
}

.parent-day-partial {
  background: rgba(255, 184, 77, 0.2);
  color: #8e5c00;
}

.parent-day-q1 { background: rgba(79, 191, 145, 0.12); color: #276a4f; }
.parent-day-q2 { background: rgba(79, 191, 145, 0.2); color: #216247; }
.parent-day-q3 { background: rgba(79, 191, 145, 0.3); color: #1a5a3f; }
.parent-day-q4 { background: rgba(79, 191, 145, 0.42); color: #164d36; }
.parent-day-q5 { background: rgba(79, 191, 145, 0.56); color: #103f2b; }

.parent-inline-loading {
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: 700;
}

.parent-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 32;
  display: grid;
  align-items: center;
  justify-items: center;
  padding: 18px 12px;
}

.parent-sheet-scrim {
  position: absolute;
  inset: 0;
  border: 0;
  background: rgba(36, 50, 74, 0.18);
  backdrop-filter: blur(8px);
}

.parent-detail-sheet {
  position: relative;
  width: min(100%, 420px);
  display: grid;
  gap: 14px;
  padding: 16px 18px 18px;
  border-radius: 28px;
  box-shadow: var(--shadow-lg);
}

.parent-sheet-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: 12px;
}

.parent-sheet-title {
  margin: 4px 0 0;
  font-family: "Sora", sans-serif;
  font-size: 25px;
  letter-spacing: -0.04em;
  text-transform: capitalize;
}

.parent-sheet-close {
  align-self: center;
}

.parent-detail-list {
  display: grid;
  gap: 14px;
}

.parent-detail-block {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 22px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.78);
}

.parent-detail-heading {
  color: var(--ink);
  font-size: 14px;
  font-weight: 900;
}

.parent-detail-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.parent-detail-label {
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 700;
}

.parent-detail-value {
  color: var(--ink);
  font-size: 15px;
  font-weight: 800;
  text-align: right;
}

.parent-detail-value-with-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.parent-detail-icon {
  font-size: 16px;
  line-height: 1;
}

.parent-detail-value.is-green {
  color: #1f7a4d;
}

.parent-detail-value.is-orange {
  color: #b56a00;
}

.parent-detail-value.is-red {
  color: #be3b3b;
}

.parent-chart {
  width: 100%;
  height: auto;
  margin-top: 8px;
}

.parent-chart-shell {
  position: relative;
}

.parent-chart-summary {
  display: grid;
  gap: 2px;
}

.parent-chart-value {
  font-family: "Sora", sans-serif;
  font-size: 34px;
  font-weight: 800;
  line-height: 1;
  color: var(--ink);
}

.parent-chart-path {
  fill: none;
  stroke: var(--blue);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 420;
  stroke-dashoffset: 420;
  animation: parentChartLine 1s ease forwards;
}

.parent-chart-node circle {
  fill: #fff;
  stroke: var(--peach);
  stroke-width: 3;
}

.parent-chart-node.is-active circle {
  stroke: var(--blue);
  fill: rgba(86, 119, 255, 0.18);
}

.parent-chart-hit {
  position: absolute;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  padding: 0;
}

.parent-chart-hit.is-active {
  background: rgba(86, 119, 255, 0.08);
}

@keyframes parentChartLine {
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes parentWeekSlideForward {
  0% {
    opacity: 0.42;
    transform: translateX(24px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes parentWeekSlideBackward {
  0% {
    opacity: 0.42;
    transform: translateX(-24px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

@media (max-width: 380px) {
  .metric-grid {
    grid-template-columns: 1fr;
  }

  .parent-metric-grid {
    grid-template-columns: 1fr;
  }

  .parent-row {
    grid-template-columns: 52px minmax(0, 1fr);
    gap: 8px;
  }

  .parent-weekday-header {
    grid-template-columns: 52px minmax(0, 1fr);
    gap: 8px;
  }

  .parent-weekday-strip {
    gap: 8px;
  }

  .parent-week-strip {
    gap: 8px;
  }

  .parent-day {
    min-height: 62px;
    padding: 9px 3px;
  }

  .parent-sheet-head {
    grid-template-columns: 1fr;
  }

  .parent-detail-row {
    display: grid;
    gap: 4px;
  }

  .parent-detail-value {
    text-align: left;
  }

  .mirai-masonry {
    columns: 1;
  }

  .mirai-rating-row {
    gap: 8px;
  }

  .mirai-rating-btn {
    min-height: 86px;
    padding-inline: 6px;
    font-size: 14px;
  }

  .mirai-rating-icon svg {
    width: 24px;
    height: 24px;
  }
}

/* ------------------------------------------------------------------ switch
   The one toggle in the app: a 51×31 capsule with a white knob, ink when on
   and --wash when off (iOS's Toggle). Always a <button role="switch"> whose
   aria-checked carries the state — the class list never does. Put it in a
   .field-row next to a .field-label, one row per fact. */

.switch {
  position: relative;
  flex: none;
  width: 51px;
  height: 31px;
  padding: 0;
  border-radius: var(--radius-pill);
  background: var(--wash);
  box-shadow: inset 0 0 0 1px var(--line);
  transition: background 180ms ease, box-shadow 180ms ease;
}

.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-feather);
  transition: transform 180ms cubic-bezier(0.32, 0.72, 0, 1);
}

.switch[aria-checked="true"] {
  background: var(--ink);
  box-shadow: inset 0 0 0 1px transparent;
}

.switch[aria-checked="true"]::after {
  transform: translateX(20px);
}

.switch[disabled] {
  opacity: 0.42;
  cursor: not-allowed;
}

.switch:active::after {
  width: 31px;
}

@media (prefers-reduced-motion: reduce) {
  .switch,
  .switch::after {
    transition: none;
  }
}
