/*
 * The Björn apps wear Björn's design: its fonts, its theme tokens (from Björn's
 * src/shared/styles/stylesTheme.js), the 111° background gradient, squircle
 * corners and the indigo pill buttons. Dark is the default here; light is
 * Björn's own light theme.
 */

@font-face {
  font-family: "Font";
  src: url("/shared/fonts/font-med.woff2") format("woff2");
  font-display: swap;
  font-weight: 500;
}
@font-face {
  font-family: "Font";
  src: url("/shared/fonts/font-semibold.woff2") format("woff2");
  font-display: swap;
  font-weight: 600;
}
@font-face {
  font-family: "Font";
  src: url("/shared/fonts/font-bold.woff2") format("woff2");
  font-display: swap;
  font-weight: 700;
}
@font-face {
  font-family: "Bjorn";
  src: url("/shared/fonts/font-bjorn-bold.woff2") format("woff2");
  font-display: swap;
  font-weight: 700;
}

/* --- Theme tokens ---------------------------------------------------------- */

:root,
:root[data-theme="dark"] {
  --ink: rgb(197 204 217);
  --paper: rgb(47 51 60);
  --shade: rgb(0 0 0);
  --grad-l: rgb(32 28 31);
  --grad-r: rgb(22 17 23);
  --ai: rgb(72 46 75);
  --you: rgb(44 64 96);
  --accent: rgb(74 101 255);
  --ui: rgb(49 46 62);
  --good: rgb(61 227 161);
  --warn: rgb(255 193 58);
  --bad: rgb(255 119 124);
  --on-accent: rgb(248 248 255);
  /* Text on the accent-filled buttons. Björn's gradL is near-black here. */
  --accent-ink: var(--on-accent);
  --surface: color-mix(in srgb, var(--paper) 42%, transparent);
  --raised: color-mix(in srgb, var(--ui) 96%, transparent);
  --glow: color-mix(in srgb, var(--accent) 13%, transparent);
  /* icon-dropdown.svg in --ink-2, for selects (a background can't take currentColor). */
  --dropdown: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 11 6'%3E%3Cpath fill='%23c5ccd9' fill-opacity='.68' d='M0.476358 0.476116C0.213284 0.73919 0.213284 1.16572 0.476358 1.42879L4.76339 5.71583C5.02647 5.9789 5.453 5.9789 5.71607 5.71582C5.97915 5.45275 5.97915 5.02622 5.71607 4.76315L1.42904 0.476113C1.16596 0.213039 0.739432 0.213042 0.476358 0.476116Z M10.0022 0.476116C10.2653 0.73919 10.2653 1.16572 10.0022 1.42879L5.71607 5.71582C5.453 5.9789 5.02647 5.9789 4.76339 5.71583C4.50032 5.45275 4.49939 5.02622 4.76247 4.76315L9.04951 0.476113C9.31258 0.213039 9.73911 0.213042 10.0022 0.476116Z'/%3E%3C/svg%3E");
  color-scheme: dark;
}

:root[data-theme="light"] {
  --ink: rgb(36 21 56);
  --paper: rgb(252 244 241);
  --shade: rgb(36 21 56);
  --grad-l: rgb(255 235 217);
  --grad-r: rgb(253 226 230);
  --ai: rgb(255 211 182);
  --you: rgb(192 196 255);
  --accent: rgb(58 9 221);
  --ui: rgb(242 212 202);
  --good: rgb(0 151 92);
  --warn: rgb(235 69 14);
  --bad: rgb(198 36 30);
  --on-accent: rgb(252 244 241);
  --accent-ink: var(--grad-l);
  --surface: color-mix(in srgb, var(--paper) 55%, transparent);
  --raised: color-mix(in srgb, var(--paper) 94%, transparent);
  --glow: transparent;
  --dropdown: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 11 6'%3E%3Cpath fill='%23241538' fill-opacity='.68' d='M0.476358 0.476116C0.213284 0.73919 0.213284 1.16572 0.476358 1.42879L4.76339 5.71583C5.02647 5.9789 5.453 5.9789 5.71607 5.71582C5.97915 5.45275 5.97915 5.02622 5.71607 4.76315L1.42904 0.476113C1.16596 0.213039 0.739432 0.213042 0.476358 0.476116Z M10.0022 0.476116C10.2653 0.73919 10.2653 1.16572 10.0022 1.42879L5.71607 5.71582C5.453 5.9789 5.02647 5.9789 4.76339 5.71583C4.50032 5.45275 4.49939 5.02622 4.76247 4.76315L9.04951 0.476113C9.31258 0.213039 9.73911 0.213042 10.0022 0.476116Z'/%3E%3C/svg%3E");
  color-scheme: light;
}

/* Björn authors its colours in display-p3; use them where the screen can. */
@supports (color: color(display-p3 1 1 1)) {
  :root,
  :root[data-theme="dark"] {
    --grad-l: color(display-p3 0.1229 0.1105 0.1204);
    --grad-r: color(display-p3 0.0849 0.0693 0.0888);
    --ai: color(display-p3 0.2693 0.1866 0.2858);
    --you: color(display-p3 0.1887 0.2486 0.3683);
    --accent: color(display-p3 0.3125 0.3927 1);
    --ui: color(display-p3 0.1888 0.179 0.2381);
    --good: color(display-p3 0.4549 0.8784 0.651);
    --warn: color(display-p3 1 0.7686 0.3412);
    --bad: color(display-p3 1 0.502 0.502);
  }
  :root[data-theme="light"] {
    --grad-l: color(display-p3 1 0.9244 0.8605);
    --grad-r: color(display-p3 0.9747 0.8882 0.9026);
    --ai: color(display-p3 0.9837 0.8352 0.7291);
    --you: color(display-p3 0.7558 0.7681 0.9961);
    --accent: color(display-p3 0.2087 0.0528 0.8324);
    --ui: color(display-p3 0.9286 0.8351 0.7977);
    --good: color(display-p3 0.1412 0.5804 0.3804);
    --warn: color(display-p3 0.8518 0.3236 0.1629);
    --bad: color(display-p3 0.7151 0.2084 0.1626);
  }
}

:root {
  /* Space above the first thing on a page (its hero), the same in every app. */
  --page-top: 34px;
  --ink-2: color-mix(in srgb, var(--ink) 68%, transparent);
  --ink-3: color-mix(in srgb, var(--ink) 44%, transparent);
  /* Björn's separators: black at 0.08. */
  --line: color-mix(in srgb, var(--ink) 8%, transparent);
  /* The bevel on Björn's raised controls (NavButton's :after). */
  --bevel:
    inset 0 -0.05em 0.1em 0 color-mix(in srgb, var(--accent) 10%, transparent),
    inset 0 0.05em 0.1em 0 var(--ai);
  --err: var(--bad);
  --fix: var(--good);
  --reach: var(--warn);
  --style: var(--accent);
  --font: "Font", -apple-system, BlinkMacSystemFont, sans-serif;
  --text-size: 20px;
  --text-lh: 1.75;
  /* Björn's border-radius multiplier, larger where squircles exist */
  --brm: 1.5;
}
@supports (corner-shape: squircle) {
  :root {
    --brm: 2;
  }
}

/* A page changing view (changeView in ui.js): a quick cross-fade. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.24s;
  animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* No transitions while the theme flips, as in Björn. */
:root.theme-switching *,
:root.theme-switching *::before,
:root.theme-switching *::after {
  transition-duration: 0ms !important;
}

* {
  box-sizing: border-box;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

html {
  min-height: 100%;
  background: linear-gradient(111deg, var(--grad-l) 0%, var(--grad-r) 100%) fixed no-repeat;
  background-color: var(--grad-r);
}
body {
  margin: 0;
  min-height: 100vh;
  color: var(--ink);
  font: 500 15px/1.55 var(--font);
  background: radial-gradient(70% 55% at 12% -10%, var(--glow), transparent 70%) fixed no-repeat;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button,
.field,
#popover,
.modal-card,
.toast {
  corner-shape: superellipse(1.4);
}

/* Björn's NavButton: colorUI with a bevel; hover fades, a press shrinks. */
button {
  border: 0;
  border-radius: calc(0.5em * var(--brm));
  padding: 0.55em 1em;
  background: var(--ui);
  color: var(--ink);
  box-shadow: var(--bevel);
  font-weight: 700;
  cursor: pointer;
  transition: 0.15s;
}
button:hover:not(:disabled) {
  opacity: 0.85;
}
button:active:not(:disabled) {
  transform: scale(0.98);
}
button:disabled {
  opacity: 0.45;
  cursor: default;
}

/* Björn's primaryAccentButtonStyles: accent at 0.8, gradL text (light text
   in dark), a bevelled under-edge; hover goes to full accent at 0.85 opacity. */
button.primary,
a.button-link.primary {
  padding: 0.6em 1.3em;
  background: color-mix(in srgb, var(--accent) 80%, transparent);
  color: var(--accent-ink);
  box-shadow:
    inset 0 0 3px 0 color-mix(in srgb, var(--ai) 80%, transparent),
    0 2px 0 0 var(--ai);
  backdrop-filter: blur(1em);
  -webkit-backdrop-filter: blur(1em);
}
button.primary:hover:not(:disabled),
a.button-link.primary:hover {
  background: color-mix(in srgb, var(--accent) 98%, transparent);
  opacity: 0.85;
}
button.primary.open,
button.primary.is-active {
  background: var(--accent);
  box-shadow:
    inset 0 0 4px 0 color-mix(in srgb, var(--ai) 90%, transparent),
    0 1px 0 0 var(--ai);
  opacity: 1;
}
/* Quiet buttons (Björn has none of its own): no fill until hovered, then
   colorUI at 0.4 like its settings controls. */
button.ghost {
  background: transparent;
  color: var(--ink-2);
  box-shadow: none;
}
button.ghost:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ui) 40%, transparent);
  color: var(--ink);
  opacity: 1;
}
button.icon {
  display: inline-grid;
  place-items: center;
  width: 2.3em;
  height: 2.3em;
  padding: 0;
  background: transparent;
  color: var(--ink);
  box-shadow: none;
}
button.icon:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ui) 40%, transparent);
  opacity: 1;
}
button.tiny {
  padding: 0.2em 0.65em;
  font-size: 12px;
}

/* Björn's icons are single-colour SVGs; masks let them take any colour. */
.i {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  background: currentColor;
  mask: var(--src) center / contain no-repeat;
  -webkit-mask: var(--src) center / contain no-repeat;
  vertical-align: -0.15em;
}
.i-sun {
  --src: url("/shared/img/icons/theme-light.svg");
}
.i-moon {
  --src: url("/shared/img/icons/theme-dark.svg");
}
.i-dots {
  --src: url("/shared/img/icons/settings.svg");
  width: 1.25em;
}
.i-stars {
  --src: url("/shared/img/icons/icon-stars.svg");
}
.i-panel {
  --src: url("/shared/img/icons/panel.svg");
}
/* Björn's speaker, on every button that plays the target language. */
.i-speaker {
  --src: url("/shared/img/icons/icon-speaker.svg");
}
/* Björn's close X, on every close and remove button. Sized to the glyph it
   replaced, so the buttons' existing font sizes still set how big it is. */
.i-x {
  --src: url("/shared/img/icons/icon-x.svg");
  width: 0.55em;
  height: 0.55em;
  vertical-align: middle;
}
/* Björn's dropdown chevron, on everything that opens a menu. */
.i-dropdown {
  --src: url("/shared/img/icons/icon-dropdown.svg");
  width: 11px;
  height: 6px;
  vertical-align: 0.15em;
}

.muted {
  color: var(--ink-2);
}
.small {
  font-size: 12px;
}
.win {
  color: var(--fix);
}
.bad {
  color: var(--err);
}
s {
  color: var(--err);
  text-decoration-thickness: 1px;
}

/* Uppercase, letter-spaced labels, as in Björn's "THINGS TO TRY". */
#side h3,
#drawer h3 {
  margin: 0;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* --- Layout ---------------------------------------------------------------- */

@media (max-width: 760px) {
  :root {
    --page-top: 20px;
  }
}

.brand {
  font-family: "Bjorn", var(--font);
  font-weight: 700;
  font-size: 30px;
  line-height: 1;
  color: var(--accent);
  letter-spacing: -0.01em;
  margin: 0 6px 4px 4px;
}

/* The language pill, like Björn's "Swedish · Live practice". */
.lang-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.4em 0.95em 0.4em 0.7em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.lang-pill:empty {
  display: none;
}
.lang-pill img {
  width: 18px;
  height: 12px;
  object-fit: cover;
  border-radius: 2px;
}
.lang-pill .dot {
  color: var(--ink-3);
}

/* A segmented choice (theme, billing period, filters): a sunken track with
   the chosen option in the accent. Track and option are both round pills,
   the option 3px in, so it sits exactly inside. */
.mode {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  corner-shape: round;
  background: color-mix(in srgb, var(--shade) 22%, transparent);
  box-shadow: inset 0 0 0 1px var(--line);
}
.mode button {
  border-radius: 999px;
  corner-shape: round;
  padding: 0.35em 0.95em;
  background: transparent;
  color: var(--ink-2);
  box-shadow: none;
  font-size: 13px;
  transition:
    background 0.15s,
    color 0.15s;
}
.mode button:hover:not(:disabled) {
  color: var(--ink);
  opacity: 1;
}
.mode button.on,
.mode button.on:hover:not(:disabled) {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--shade) 30%, transparent);
}
:root[data-theme="light"] .mode {
  background: color-mix(in srgb, var(--ui) 70%, transparent);
}

#main {
  padding: var(--page-top) 28px 140px;
}
/* Only animate the margins once the page has its starting layout. */
body.ready #main {
  transition: margin 0.2s;
}
body:not(.side-closed) #main {
  margin-right: 340px;
}
.page {
  max-width: 44rem;
  margin: 0 auto;
}

.title {
  display: block;
  width: 100%;
  margin: 0 0 28px;
  padding: 0;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--ink);
  font-size: 44px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.1;
  resize: none;
  overflow: hidden;
}
.title::placeholder {
  color: var(--ink-3);
}

.statusline {
  display: flex;
  gap: 18px;
  margin-top: 30px;
  font-size: 12.5px;
  color: var(--ink-3);
}
#status.win {
  color: var(--fix);
}
#status.bad {
  color: var(--err);
}

/* --- Popover --------------------------------------------------------------- */

/* Björn's popovers (the vinyl player's): colorUI at 0.96, a faint border, the
   bevel and a soft drop shadow. */
#popover {
  position: absolute;
  z-index: 40;
  width: 350px;
  padding: 0.9em 1.1em;
  background: color-mix(in srgb, var(--ui) 96%, transparent);
  border: 1px solid color-mix(in srgb, var(--ink) 5%, transparent);
  border-radius: calc(0.7em * var(--brm));
  box-shadow:
    var(--bevel),
    0 0.5em 1.5em color-mix(in srgb, var(--shade) 18%, transparent);
  backdrop-filter: blur(1.1em);
  -webkit-backdrop-filter: blur(1.1em);
  font-size: 14px;
  animation: pop-in 0.16s ease-out;
}
/* Björn's popover entrance: down 0.4em into place, 0.25s. */
@keyframes pop-in {
  from {
    opacity: 0;
    transform: translateY(-0.4em);
  }
}
#popover p {
  margin: 8px 0;
}
.pop-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.tag {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 2px 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--err) 16%, transparent);
  color: var(--err);
}
.tag.t-translation,
.tag.t-reach {
  background: color-mix(in srgb, var(--reach) 16%, transparent);
  color: var(--reach);
}
.tag.t-style,
.tag.t-misread {
  background: color-mix(in srgb, var(--style) 16%, transparent);
  color: var(--style);
}
.tag.t-grow,
.tag.t-phrase {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}
.rule {
  color: var(--ink-2);
  font-size: 12.5px;
}
.swap {
  margin: 12px 0 4px;
  font-size: 19px;
}
.swap .arrow {
  color: var(--ink-3);
  margin: 0 0.5em;
}
.swap b {
  color: var(--fix);
}
.t-reach {
  color: var(--reach);
}
.pop-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 14px;
}
.versions,
.options {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 12px 0 4px;
}
.version,
.option {
  text-align: left;
  font-size: 15px;
  font-weight: 500;
}
.version.on {
  background: color-mix(in srgb, var(--fix) 16%, transparent);
  color: var(--fix);
}
.heard {
  font-size: 17px;
  color: var(--style);
}
.reveal {
  font-size: 18px;
  color: var(--fix);
}
.loading::after {
  content: "";
  display: inline-block;
  width: 1ch;
  animation: dots 1s steps(4) infinite;
}
@keyframes dots {
  0% {
    content: "";
  }
  25% {
    content: ".";
  }
  50% {
    content: "..";
  }
  75% {
    content: "...";
  }
}

/* Skeletons (ui.js, sk and skBox): faint shapes where the page's content will
   be, breathing slowly. A bar sits inside the element its text goes in, on
   the text's baseline, so the line keeps exactly its height; the bar itself
   is drawn a little thinner than the line. settle() cross-fades from them to
   the real thing. */
.sk {
  position: relative;
  display: inline-block;
  width: var(--w, 100%);
  max-width: 100%;
  color: transparent;
  user-select: none;
  pointer-events: none;
  animation: sk-breathe 1.8s ease-in-out infinite;
}
.sk::before {
  content: "";
  position: absolute;
  inset: max(0px, calc((1lh - 1.1em) / 2)) 0;
  border-radius: calc(0.35em * var(--brm));
  background: color-mix(in srgb, var(--ink) 7%, transparent);
}
.sk-box {
  display: block;
  flex: none;
  height: var(--h);
}
.sk-box::before {
  inset: 0;
}
.sk-round::before {
  border-radius: 50%;
}
@keyframes sk-breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.55;
  }
}
body[data-motion="off"] .sk {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  .sk {
    animation: none;
  }
}

/* Inputs follow Björn's chat composer: no border, white at 0.4, 0.6 on
   hover, 0.8 with focus. */
.field,
.settings select {
  width: 100%;
  padding: 0.75em 0.9em;
  border: 0;
  border-radius: calc(0.5em * var(--brm));
  background-color: color-mix(in srgb, var(--paper) 40%, transparent);
  color: var(--ink);
  outline: none;
  transition:
    opacity 200ms ease,
    background 200ms ease;
}
.field:hover,
.settings select:hover {
  background-color: color-mix(in srgb, var(--paper) 60%, transparent);
}
.field:focus,
.settings select:focus {
  background-color: color-mix(in srgb, var(--paper) 80%, transparent);
}
/* Every select drops the browser's arrow for Björn's dropdown chevron. */
select {
  appearance: none;
  -webkit-appearance: none;
  background-image: var(--dropdown);
  background-repeat: no-repeat;
  background-position: right 0.9em center;
  background-size: 11px 6px;
}
select,
select.field {
  padding-right: 2.4em;
}
.field::placeholder {
  color: color-mix(in srgb, var(--ink) 30%, transparent);
}
.field {
  margin-top: 10px;
}
.grow-ask label {
  display: block;
  margin-top: 10px;
}
.phrases {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: 10px;
  font-size: 13px;
}
.phrase {
  display: flex;
  gap: 6px;
  align-items: baseline;
}
.phrase button {
  margin-left: auto;
}

/* Trace: type over the ghost text to accept it. */
.trace {
  position: relative;
  margin: 12px 0 6px;
}
.trace-ghost,
.trace-input {
  font-family: var(--font);
  font-weight: 500;
  font-size: 17px;
  line-height: 1.55;
  letter-spacing: 0;
  font-kerning: none;
  font-variant-ligatures: none;
  padding: 8px 10px;
  white-space: pre-wrap;
  word-break: break-word;
}
.trace-ghost {
  color: var(--ink-3);
  border: 1px dashed var(--line);
  border-radius: calc(0.5em * var(--brm));
}
.trace-ghost .ok {
  color: var(--ink);
}
.trace-ghost .near {
  color: var(--warn);
}
.trace-ghost .no {
  color: var(--err);
  text-decoration: underline;
}
.trace-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  resize: none;
  overflow: hidden;
  background: transparent;
  border: 1px solid transparent;
  color: transparent;
  caret-color: var(--accent);
  outline: none;
}

/* --- Side panel ------------------------------------------------------------ */

#side {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 340px;
  overflow-y: auto;
  padding: 0 28px 40px 22px;
  font-size: 14px;
  transition: transform 0.25s ease;
}
body.side-closed #side {
  transform: translateX(105%);
}
/* The tabs stick while the panel scrolls, so they wear the page's own fixed
   background (it lines up with what's behind) and fade out underneath. They
   reach past the panel padding so cards don't peek out at the sides. The
   bottom margin matches the fade, so nothing sits under it until you scroll. */
.tabs {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  gap: 4px;
  margin: 0 -28px 18px -22px;
  padding: var(--page-top) 28px 12px 22px;
}
.tabs,
.tabs::after {
  background:
    radial-gradient(70% 55% at 12% -10%, var(--glow), transparent 70%) fixed no-repeat,
    linear-gradient(111deg, var(--grad-l) 0%, var(--grad-r) 100%) fixed no-repeat;
  background-color: var(--grad-r);
}
.tabs::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 18px;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent);
  mask-image: linear-gradient(to bottom, #000, transparent);
}
.tabs button {
  box-shadow: none;
  border-radius: 999px;
  padding: 0.35em 0.9em;
  background: transparent;
  color: var(--ink-2);
  font-size: 13px;
}
.tabs button.on {
  background: var(--surface);
  color: var(--ink);
}
.count {
  color: var(--accent);
}
#side h3 {
  color: var(--ink);
  margin: 22px 0 12px;
}
.rules,
.pocket,
#doc-list,
.suggest {
  list-style: none;
  margin: 0;
  padding: 0;
}
.pocket li {
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
.pocket-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 12px;
}
.ph {
  font-size: 16px;
  font-weight: 700;
}
.mean {
  color: var(--ink-2);
}
.ex {
  display: block;
  margin-top: 4px;
  color: var(--ink-3);
  font-size: 13px;
}
.meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
}
.ladder {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
}
.ladder-helped {
  color: var(--reach);
}
.ladder-recalled {
  color: var(--accent);
}
.ladder-used {
  color: var(--fix);
}

/* --- Modal & toasts -------------------------------------------------------- */

#modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  /* A light scrim and a little blur set the dialog apart from the page. In
     the hub the sidebar gets the same (hub.css, frame-modal). */
  background: color-mix(in srgb, var(--shade) 14%, transparent);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: scrim-in 0.2s ease-out;
}
@keyframes scrim-in {
  from {
    opacity: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  #modal {
    animation: none;
  }
}
body[data-motion="off"] #modal {
  animation: none;
}
#modal[hidden] {
  display: none;
}
/* A dialog on its way out (ui.js, leave): closed, but drawn until it has
   faded. Important, to win over the rule that keeps [hidden] hidden. */
#modal.leaving[hidden] {
  display: grid !important;
  pointer-events: none;
}
.modal-card {
  width: min(480px, calc(100vw - 32px));
  max-height: calc(100vh - 60px);
  overflow-y: auto;
  padding: 28px 26px 24px;
  background: var(--paper);
  border-radius: calc(0.8em * var(--brm));
  box-shadow:
    0 24px 64px -12px color-mix(in srgb, var(--shade) 32%, transparent),
    0 8px 24px -8px color-mix(in srgb, var(--shade) 18%, transparent),
    0 1px 3px color-mix(in srgb, var(--shade) 12%, transparent);
  animation: pop-in 0.25s ease-in-out;
}
.modal-card.wide {
  width: min(600px, calc(100vw - 32px));
}
/* Going from one dialog to the next (ui.js, morph): the panel is the card's
   box on its way from the old size to the new, both cards' content lies over
   it without a box of their own, and the old card sits where it was. */
.modal-panel {
  position: absolute;
  background: var(--paper);
  border-radius: calc(0.8em * var(--brm));
  corner-shape: superellipse(1.4);
  box-shadow:
    0 24px 64px -12px color-mix(in srgb, var(--shade) 32%, transparent),
    0 8px 24px -8px color-mix(in srgb, var(--shade) 18%, transparent),
    0 1px 3px color-mix(in srgb, var(--shade) 12%, transparent);
  pointer-events: none;
}
.modal-card.morphing,
.modal-card.modal-ghost {
  position: relative;
  z-index: 1;
  background: transparent;
  box-shadow: none;
}
.modal-card.modal-ghost {
  animation: none;
  position: absolute;
  margin: 0;
  box-sizing: border-box;
  pointer-events: none;
}
.modal-card h2 {
  margin: 0 0 10px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--accent);
  text-align: center;
}
.modal-card > p.muted {
  text-align: center;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 22px;
}
.settings label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin: 12px 0;
  font-weight: 600;
}
.settings select {
  width: 64%;
  font-size: 14px;
}
.settings .check {
  justify-content: flex-start;
  gap: 10px;
}

/* Settings: a header with a close button, then cards of rows, like a phone's
   settings. Each group has an uppercase label above its card. */
.modal-card.settings-card {
  width: min(520px, calc(100vw - 32px));
  padding: 22px 22px 24px;
}
.settings-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 16px;
}
.settings-top h2 {
  margin: 0;
  text-align: left;
}
.settings-top button.icon {
  color: var(--ink-2);
  font-size: 22px;
  line-height: 1;
}
.set-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin: 20px 4px 8px;
}
.set-label .eyebrow {
  margin: 0;
}
.set-label .muted {
  font-size: 12px;
}
.set-card {
  border: 1px solid var(--line);
  border-radius: calc(0.7em * var(--brm));
  corner-shape: superellipse(1.4);
  background: color-mix(in srgb, var(--shade) 14%, transparent);
  overflow: hidden;
}
:root[data-theme="light"] .set-card {
  background: color-mix(in srgb, white 55%, transparent);
}
.set-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-height: 52px;
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 600;
}
.set-row + .set-row {
  border-top: 1px solid var(--line);
}
/* A row that is a button: the whole width, a chevron at the end. */
button.set-row {
  width: 100%;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: inherit;
  text-align: left;
}
button.set-row:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  opacity: 1;
}
button.set-row:active:not(:disabled) {
  transform: none;
}
.set-row .chev {
  color: var(--ink-3);
  font-size: 20px;
  line-height: 1;
}
.set-row .end {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink-2);
  font-weight: 600;
}
.set-row .start {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.set-row img {
  flex: none;
  width: 22px;
  height: 22px;
  object-fit: contain;
}

/* The account: who you are, and the one thing to do about it. */
.set-account {
  padding: 14px 16px;
}
.set-account .avatar {
  flex: none;
  width: 40px;
  height: 40px;
  font-size: 16px;
}
.set-account .who {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.set-account .who b {
  font-size: 15px;
}
.set-account .who span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
}
.set-account button.link {
  padding: 0;
  background: none;
  box-shadow: none;
  color: var(--accent);
  font: inherit;
  font-weight: 700;
}
.set-account button.ghost,
.set-account button.primary,
.plan-row button {
  flex: none;
  padding: 0.5em 1em;
  border-radius: 999px;
  font-size: 13px;
}

/* An on/off switch in place of a checkbox. */
input.switch {
  appearance: none;
  flex: none;
  position: relative;
  width: 40px;
  height: 24px;
  margin: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 20%, transparent);
  cursor: pointer;
  transition: background 0.2s;
}
input.switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: white;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.3);
  transition: transform 0.2s;
}
input.switch:checked {
  background: var(--accent);
}
input.switch:checked::after {
  transform: translateX(16px);
}
input.switch:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.set-row .mode button {
  font-size: 13px;
}

/* Today's usage: a meter per allowance, warn from 80%, bad once it's used
   up, and the plan underneath. */
.meter {
  padding: 14px 16px;
  --meter: var(--accent);
}
.meter + .meter {
  border-top: 1px solid var(--line);
}
.meter.low {
  --meter: var(--warn);
}
.meter.out {
  --meter: var(--bad);
}
.meter-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.meter-head b {
  font-size: 14px;
}
.meter-head span {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.meter-head span strong {
  color: var(--ink);
}
.meter.low .meter-head span,
.meter.out .meter-head span,
.meter.low .meter-head span strong,
.meter.out .meter-head span strong {
  color: var(--meter);
}
.meter-bar {
  height: 6px;
  margin: 9px 0 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 12%, transparent);
  overflow: hidden;
}
.meter-bar i {
  display: block;
  height: 100%;
  min-width: 6px;
  border-radius: inherit;
  background: var(--meter);
  transition: width 0.4s ease;
}
.meter p {
  margin: 0;
  font-size: 12px;
  color: var(--ink-3);
}
.plan-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 16px;
  border-top: 1px solid var(--line);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
.plan-row.out {
  background: color-mix(in srgb, var(--bad) 10%, transparent);
}
.plan-row.fluent {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.plan-row b {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
}
.plan-row b .i {
  color: var(--accent);
}
.plan-row p {
  margin: 2px 0 0;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-2);
  line-height: 1.4;
}
.plan-actions {
  display: flex;
  flex: none;
  gap: 6px;
}
@media (max-width: 480px) {
  .plan-row {
    flex-direction: column;
    align-items: stretch;
  }
  .plan-actions {
    justify-content: flex-end;
  }
}
.suggest li {
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.suggest label {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.suggest label > span {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.review-meaning {
  font-size: 16px;
  color: var(--ink-2);
  text-align: center;
}
.cloze-line {
  font-size: 22px;
  line-height: 2;
  margin: 16px 0;
  text-align: center;
}
.cloze {
  background: transparent;
  border: 0;
  border-bottom: 2px solid var(--accent);
  outline: none;
  font-size: 22px;
  font-weight: 700;
  padding: 0 2px;
  text-align: center;
}
.cloze.ok {
  border-color: var(--fix);
  color: var(--fix);
}
.cloze.no {
  border-color: var(--err);
  color: var(--err);
}
.review-result {
  text-align: center;
}

/* Toasts copy Björn's notifications: an accent card with light text. */
#toasts {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 70;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
}
.toast {
  max-width: 480px;
  padding: 0.75em 1.2em 0.8em;
  border-radius: calc(0.6em * var(--brm));
  background: color-mix(in srgb, var(--accent) 96%, transparent);
  color: var(--on-accent);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--shade) 22%, transparent);
  font-size: 14px;
  animation: toast-in 0.35s cubic-bezier(0.2, 1.4, 0.4, 1);
  transition:
    opacity 0.3s,
    transform 0.3s;
}
@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}
/* How long it stays: a line along the bottom that runs out as it does (toast in ui.js). */
.toast {
  position: relative;
  overflow: hidden;
}
.toast-time {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 5px;
  background: color-mix(in srgb, var(--on-accent) 35%, transparent);
  transform-origin: left;
  animation: toast-time linear forwards;
}
@keyframes toast-time {
  to {
    transform: scaleX(0);
  }
}
.toast .muted,
.toast .t-reach {
  color: inherit;
  opacity: 0.8;
}
.toast b {
  font-weight: 700;
}
.toast.bad {
  background: var(--err);
}
.toast.leaving {
  opacity: 0;
  transform: translateY(8px);
}
.toast-actions {
  margin-top: 8px;
}
.toast button {
  background: color-mix(in srgb, var(--on-accent) 22%, transparent);
  color: var(--on-accent);
}

/* No room beside the page: the side panel slides over it as a solid sheet,
   like Write's drawer from the other side, and a tap outside closes it (write/main.js). */
@media (max-width: 900px) {
  body:not(.side-closed) #main {
    margin: 0;
  }
  #side {
    z-index: 40;
    width: min(340px, 100%);
    background: linear-gradient(var(--raised), var(--raised)), var(--grad-r);
    box-shadow: -12px 0 40px color-mix(in srgb, var(--shade) 22%, transparent);
  }
  body.side-closed #side {
    visibility: hidden;
    transition:
      transform 0.25s ease,
      visibility 0s 0.25s;
  }
  #side .tabs,
  #side .tabs::after {
    background: linear-gradient(var(--raised), var(--raised)), var(--grad-r);
  }
  .title {
    font-size: 32px;
  }
}
/* A phone: the page already gives a column to the drawer button. */
@media (max-width: 600px) {
  #main {
    padding-inline: 16px;
  }
}

/* --- Welcome --------------------------------------------------------------- */

.welcome {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 6px 6px 0;
}
.welcome-brand {
  font-size: 46px;
  margin: 0 0 14px;
}
.modal-card .welcome h2 {
  max-width: 22ch;
  margin: 0 0 18px;
  font-size: 28px;
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 1.15;
  color: var(--ink);
}

/* A looping miniature of a repair: the mistake is marked, then the fix drops in. */
.demo {
  margin: 0 0 22px;
  padding: 10px 18px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  font-size: 19px;
  white-space: nowrap;
}
.demo-mark {
  text-decoration: underline wavy var(--err);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 5px;
  text-decoration-skip-ink: none;
  animation: demo-mark 4.2s ease-in-out infinite;
}
.demo-add {
  display: inline-block;
  max-width: 0;
  overflow: hidden;
  vertical-align: bottom;
  color: var(--fix);
  opacity: 0;
  animation: demo-add 4.2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}
@keyframes demo-mark {
  0%,
  45% {
    text-decoration-color: var(--err);
  }
  55%,
  100% {
    text-decoration-color: transparent;
  }
}
@keyframes demo-add {
  0%,
  45% {
    max-width: 0;
    opacity: 0;
    transform: translateY(-0.5em);
  }
  60%,
  92% {
    max-width: 3.5em;
    opacity: 1;
    transform: none;
  }
  100% {
    max-width: 3.5em;
    opacity: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .demo-mark,
  .demo-add {
    animation: none;
  }
  .demo-add {
    max-width: 3.5em;
    opacity: 1;
  }
}

/* Numbered points in circles, like Björn's "THINGS TO TRY". */
.pitch {
  counter-reset: pitch;
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  text-align: left;
  font-size: 14.5px;
  line-height: 1.5;
}
.pitch li {
  counter-increment: pitch;
  position: relative;
  padding: 0 0 14px 42px;
  color: var(--ink-2);
}
.pitch li b {
  color: var(--ink);
}
.pitch li::before {
  content: counter(pitch);
  position: absolute;
  left: 0;
  top: -2px;
  width: 26px;
  height: 26px;
  border: 1px solid var(--line);
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
}
.feature-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin: 0 0 22px;
}
.feature-chips span {
  padding: 0.3em 0.85em;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-2);
}
.welcome-go {
  font-size: 16px;
  padding: 0.75em 2.2em;
}
.welcome .small {
  margin: 10px 0 0;
}

/* --- Shell ------------------------------------------------------------------ */

.avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 700;
}

/* The app switcher: a small menu of the four ways to practise. */
/* Menus are Björn's activities menu: a frosted panel of separate tiles,
   white at 0.84, 0.94 on hover, a slight press. */
.menu {
  position: absolute;
  z-index: 45;
  display: flex;
  flex-direction: column;
  gap: 0.35em;
  min-width: 250px;
  padding: 0.45em;
  background: color-mix(in srgb, var(--paper) 38%, transparent);
  border-radius: calc(0.7em * var(--brm));
  corner-shape: superellipse(1.4);
  box-shadow: 0 0.1em 0.5em 0 color-mix(in srgb, var(--shade) 8%, transparent);
  backdrop-filter: blur(1em);
  -webkit-backdrop-filter: blur(1em);
  animation: pop-in 0.25s ease-in-out;
}
.menu a,
.menu button {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 0.72em 0.86em;
  border-radius: calc(0.4em * var(--brm));
  corner-shape: superellipse(1.4);
  background: color-mix(in srgb, var(--paper) 84%, transparent);
  color: var(--ink);
  box-shadow: none;
  text-decoration: none;
  font-weight: 600;
  text-align: left;
  transition: 150ms;
}
.menu a:hover,
.menu button:hover:not(:disabled) {
  background: color-mix(in srgb, var(--paper) 94%, transparent);
  opacity: 1;
}
.menu a:active,
.menu button:active:not(:disabled) {
  transform: scale(0.99);
}
.menu a.on {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.menu .mark {
  font-family: "Bjorn", var(--font);
  font-size: 18px;
  color: var(--accent);
  min-width: 58px;
}
.menu small {
  display: block;
  font-weight: 500;
  color: var(--ink-2);
  font-size: 12px;
}
.menu hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 0.2em 0.4em;
}

.code-input {
  letter-spacing: 0.4em;
  font-size: 22px;
  text-align: center;
  font-weight: 700;
}
.limit-note {
  margin: -6px 0 0;
  font-size: 14px;
}

/* Saving progress: Björn, a heading, what an account gets you, then fields
   with labels that stand out from the card. */
.save-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.save-card .char {
  margin-bottom: 14px;
}
.save-card h2 {
  margin: 0 0 6px;
  text-align: left;
}
.save-card > p.muted {
  margin: 0;
  line-height: 1.5;
}
.save-gains {
  display: grid;
  gap: 8px;
  margin: 16px 0 4px;
  padding: 0;
  list-style: none;
  font-size: 14px;
  font-weight: 600;
}
.save-gains li {
  display: flex;
  align-items: center;
  gap: 10px;
}
.save-gains li::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--good) 18%, transparent)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='m5 9.2 2.6 2.6L13 6.4' fill='none' stroke='%2333c08a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / contain no-repeat;
}
/* Continue with Google: the same size as the form's button, in the plain
   button colour, then a line with "or with your email" across it. */
.google-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  align-self: stretch;
  margin-top: 20px;
  padding: 0.75em 1em;
  border-radius: 999px;
  font-size: 15px;
}
.google-button svg {
  flex: none;
  width: 18px;
  height: 18px;
}
.save-or {
  display: flex;
  align-items: center;
  gap: 12px;
  align-self: stretch;
  margin: 18px 0 0;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
}
.save-or::before,
.save-or::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}
.save-or + .save-form {
  margin-top: 14px;
}
.save-form {
  align-self: stretch;
  margin-top: 18px;
}
.save-form label {
  display: block;
  margin-bottom: 14px;
  font-size: 13px;
  font-weight: 700;
}
.save-form label .muted {
  font-weight: 600;
}
.save-form .field {
  margin-top: 6px;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--shade) 16%, transparent);
  font-size: 15px;
}
:root[data-theme="light"] .save-form .field {
  background: color-mix(in srgb, white 70%, transparent);
}
.save-form .field:hover {
  border-color: color-mix(in srgb, var(--ink) 18%, transparent);
}
.save-form .field:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--glow);
}
.save-form .code-input {
  padding: 0.5em;
  font-size: 26px;
  letter-spacing: 0.5em;
  text-indent: 0.5em;
}
.save-form .code-input::selection {
  background: color-mix(in srgb, var(--accent) 35%, transparent);
}
.save-form .code-input::placeholder {
  letter-spacing: 0.5em;
}
.save-form button.primary {
  width: 100%;
  padding: 0.75em 1em;
  border-radius: 999px;
  font-size: 15px;
}
.form-error {
  min-height: 1.2em;
  margin: -4px 0 10px;
  color: var(--bad);
  font-size: 13px;
  font-weight: 600;
}
.form-error:empty {
  min-height: 0;
  margin: 0;
}
.save-foot {
  align-self: stretch;
  margin: 20px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  line-height: 1.5;
}
.save-links {
  display: flex;
  justify-content: space-between;
  align-self: stretch;
  margin: 14px 0 0;
}
.save-card button.link {
  padding: 0;
  background: none;
  box-shadow: none;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.save-card button.link:hover:not(:disabled) {
  color: var(--ink);
  opacity: 1;
}
.page-wide {
  max-width: 72rem;
  margin: 0 auto;
}
.empty {
  padding: 40px 0;
  text-align: center;
  color: var(--ink-2);
}

/* An anchor that looks like a button. */
a.button-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  border-radius: calc(0.5em * var(--brm));
  corner-shape: superellipse(1.4);
  padding: 0.55em 1em;
  background: var(--ui);
  color: var(--ink);
  box-shadow: var(--bevel);
  font-weight: 700;
  text-decoration: none;
  transition: 0.15s;
}
a.button-link:hover {
  opacity: 0.85;
}
a.button-link:active {
  transform: scale(0.98);
}
.spacer {
  flex: 1;
}

/* Anything marked hidden stays hidden, whatever its display rule. */
[hidden] {
  display: none !important;
}

/* Uppercase, letter-spaced section label, as in Björn's "THINGS TO TRY". */
.eyebrow {
  margin: 0 0 12px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* Apps with controls at the bottom show notifications at the top instead. */
body[data-toasts="top"] #toasts {
  top: 84px;
  bottom: auto;
}

/* --- Topics ------------------------------------------------------------------- */

.topic-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.topic-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0.35em 0.85em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 13px;
  font-weight: 600;
}
.topic-chip.on {
  border-color: transparent;
  background: var(--accent);
  color: var(--on-accent);
}
.topic-chip.add {
  box-shadow: none;
  border-style: dashed;
  background: transparent;
  color: var(--ink-2);
}
.topic-progress {
  font-size: 11px;
  font-weight: 700;
  opacity: 0.7;
}
.topic-form textarea {
  resize: vertical;
  font: inherit;
}
.topic-examples {
  margin: 8px 2px 0;
}
.topic-kinds {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 12px 2px 0;
  font-size: 13.5px;
}
.topic-kinds label {
  display: flex;
  gap: 6px;
  margin: 0;
  font-weight: 500;
}
.topic-suggestion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  margin: 0 0 14px;
  border-radius: calc(0.6em * var(--brm));
  corner-shape: superellipse(1.4);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  font-size: 14px;
}
.topic-suggestion span {
  flex: 1;
}

/* --- The cast (characters.js) ---------------------------------------------- */

.char {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
}
.char svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}
.char .eyes {
  fill: rgb(22 18 30 / 0.86);
  transform-box: fill-box;
  transform-origin: center;
  animation: blink 6.5s infinite;
}
@keyframes blink {
  0%,
  95%,
  100% {
    transform: scaleY(1);
  }
  97% {
    transform: scaleY(0.12);
  }
}
body[data-motion="off"] .char .eyes {
  animation: none;
}
.char-alive .char-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform-origin: 50% 80%;
  animation: char-breathe 4.6s ease-in-out infinite;
}
.char-alive img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: fill;
  animation: char-eyes-open 6.5s steps(1, end) 1s infinite;
}
.char-alive .char-blink {
  opacity: 0;
  animation-name: char-eyes-closed;
}
@keyframes char-breathe {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-1px); }
}
@keyframes char-eyes-open {
  0%, 94%, 98%, 100% { opacity: 1; }
  95%, 97% { opacity: 0; }
}
@keyframes char-eyes-closed {
  0%, 94%, 98%, 100% { opacity: 0; }
  95%, 97% { opacity: 1; }
}
body[data-motion="off"] .char-alive,
body[data-motion="off"] .char-alive * {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  .char .eyes,
  .char-alive,
  .char-alive * {
    animation: none;
  }
}
.char-penpal img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.char-person {
  border-radius: 50%;
  background: var(--c);
  color: rgb(255 255 255 / 0.94);
  font-weight: 700;
  line-height: 1;
}

/* A link to a pattern's two-minute lesson (lessons.js). */
.lesson-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px 2px 4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  text-decoration: none;
  white-space: nowrap;
  vertical-align: middle;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.lesson-chip:hover,
.lesson-chip:focus-visible {
  color: var(--ink);
  border-color: color-mix(in srgb, #e25c8a 55%, transparent);
  background: color-mix(in srgb, #e25c8a 10%, transparent);
}

/* --- Upgrading: Björn's plan card, and the welcome after paying ------------ */

.upgrade {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.upgrade h2 .i,
.upgrade-badge .i {
  color: var(--accent);
}
.upgrade .billing {
  margin: 6px 0 18px;
}
.upgrade-card {
  position: relative;
  align-self: stretch;
  padding: 26px 24px 22px;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: calc(0.8em * var(--brm));
  corner-shape: superellipse(1.4);
  background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%);
}
.upgrade-badge {
  position: absolute;
  top: -13px;
  left: 22px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  font-size: 12px;
  font-weight: 700;
}
.upgrade-card h3 {
  margin: 0 0 4px;
  font-size: 24px;
}
.upgrade-card > p {
  margin: 0;
}
.upgrade-price {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0 16px;
}
.upgrade-price b {
  font-size: 40px;
  letter-spacing: -0.02em;
  line-height: 1;
}
.upgrade-price span {
  display: flex;
  flex-direction: column;
  font-weight: 600;
  color: var(--ink-2);
}
.upgrade-price small {
  font-size: 12px;
  color: var(--ink-3);
}
.upgrade-card button.primary {
  width: 100%;
  padding: 0.75em 1em;
  border-radius: 999px;
  font-size: 15px;
}
.upgrade-card .save-gains {
  margin-top: 18px;
}
.upgrade-foot {
  margin: 14px 0 0;
  text-align: center;
}

.welcome-fluent {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.welcome-fluent h2 {
  margin: 4px 0 6px;
}
.welcome-fluent > p {
  margin: 0 0 6px;
  max-width: 34ch;
  line-height: 1.5;
}
.welcome-fluent .eyebrow {
  margin: 14px 0 0;
  color: var(--good);
}
.welcome-fluent button.primary {
  margin-top: 18px;
  padding: 0.75em 2.2em;
  border-radius: 999px;
  font-size: 15px;
}
.welcome-fluent .modal-actions {
  align-self: stretch;
}
.welcome-host {
  animation: welcome-hop 0.9s cubic-bezier(.3,1.6,.5,1) both;
}
@keyframes welcome-hop {
  0% {
    transform: translateY(30px) scale(0.6);
    opacity: 0;
  }
  60% {
    transform: translateY(-10px) scale(1.08);
    opacity: 1;
  }
  100% {
    transform: none;
  }
}
body[data-motion="off"] .welcome-host {
  animation: none;
}
.welcome-fluent .spinner {
  width: 22px;
  height: 22px;
  margin: 14px 0 6px;
  border: 3px solid color-mix(in srgb, var(--ink) 15%, transparent);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* Björn's flag burst over a welcome (flagBurst in shell.js). */
.flag-burst {
  position: fixed;
  inset: 0;
  z-index: 90;
  overflow: visible;
  pointer-events: none;
}
.flag-burst img {
  position: absolute;
  height: auto;
  opacity: 0;
  will-change: transform, opacity;
}

/* --- Language and level ------------------------------------------------------ */

.lang-picker {
  display: flex;
  flex-direction: column;
}
.lang-picker h2 {
  margin: 0 0 4px;
  text-align: left;
}
.lang-picker > p.muted {
  margin: 0 0 6px;
}
.lang-picker .eyebrow {
  display: block;
  margin: 18px 0 8px;
}
.picker-langs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.picker-langs button,
.picker-levels label {
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--shade) 12%, transparent);
  box-shadow: none;
  transition:
    background 0.15s,
    border-color 0.15s;
}
:root[data-theme="light"] .picker-langs button,
:root[data-theme="light"] .picker-levels label {
  background: color-mix(in srgb, white 55%, transparent);
}
.picker-langs button {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 8px 12px;
  text-align: left;
  font-size: 14px;
  font-weight: 600;
}
.picker-langs img {
  flex: none;
  width: 24px;
  height: 24px;
  object-fit: contain;
}
.picker-langs span {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.2;
}
.picker-langs small {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-3);
}
.picker-langs button:hover:not(:disabled),
.picker-levels label:hover {
  border-color: color-mix(in srgb, var(--ink) 20%, transparent);
  opacity: 1;
}
.picker-langs button.on,
.picker-levels label:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
/* A tick in the corner of the chosen language. */
.picker-langs button.on::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 10px;
  width: 18px;
  height: 18px;
  margin-top: -9px;
  border-radius: 50%;
  background: var(--accent)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='m5 9.2 2.6 2.6L13 6.4' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / contain no-repeat;
}
.picker-levels {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}
.picker-levels label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 10px 11px;
  border-radius: calc(0.5em * var(--brm));
  corner-shape: superellipse(1.4);
  cursor: pointer;
}
.picker-levels input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.picker-levels label:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.picker-levels b {
  font-size: 18px;
}
.picker-levels label:has(input:checked) b {
  color: var(--accent);
}
.picker-levels span {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink-2);
}
.picker-home {
  display: block;
}
.picker-home select {
  margin-top: 0;
  border: 1px solid var(--line);
  background-color: color-mix(in srgb, var(--shade) 16%, transparent);
  font-size: 15px;
  font-weight: 600;
}
:root[data-theme="light"] .picker-home select {
  background-color: color-mix(in srgb, white 70%, transparent);
}
.lang-picker > button.primary {
  margin-top: 22px;
  padding: 0.75em 1em;
  border-radius: 999px;
  font-size: 15px;
}
@media (max-width: 560px) {
  .picker-langs {
    grid-template-columns: repeat(2, 1fr);
  }
  .picker-levels {
    grid-template-columns: repeat(3, 1fr);
  }
}
.avatar.guest {
  background: color-mix(in srgb, var(--ink) 18%, transparent);
  color: var(--ink);
}
.modal-card button.picker-back {
  align-self: flex-start;
  margin: -6px 0 10px -4px;
  padding: 4px 8px;
  border-radius: 999px;
  background: none;
  box-shadow: none;
  color: var(--ink-2);
  font-size: 13px;
}
.modal-card button.picker-back:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink);
  opacity: 1;
}

/* --- Feedback (/shared/feedback.js) ------------------------------------------ */

.fb-lead {
  margin: -6px 2px 16px;
  font-size: 14px;
}
.fb-mood {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.3;
}
.fb-mood b {
  font-size: 15px;
}
.fb-mood span {
  color: var(--ink-3);
  font-size: 13px;
  font-weight: 500;
}

/* The questions: the answer picked as a chip (back to the list), a heading,
   then the questions as one card of rows you write straight into. */
.fb-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: -4px -6px 14px 0;
}
.fb-top button.icon {
  color: var(--ink-2);
  font-size: 22px;
  line-height: 1;
}
button.fb-chip {
  --tone: var(--accent);
  padding: 5px 12px 5px 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--tone) 16%, transparent);
  box-shadow: none;
  color: var(--tone);
  font-size: 13px;
}
button.fb-chip:hover:not(:disabled) {
  background: color-mix(in srgb, var(--tone) 26%, transparent);
  opacity: 1;
}
button.fb-chip.fb-love {
  --tone: var(--good);
}
button.fb-chip.fb-meh {
  --tone: var(--warn);
}
button.fb-chip.fb-stuck,
button.fb-chip.fb-broken {
  --tone: var(--bad);
}
.modal-card h2.fb-title {
  margin: 0;
  color: var(--ink);
  text-align: left;
}
.fb-sub {
  margin: 4px 0 18px;
  color: var(--ink-3);
  font-size: 14px;
}
.fb-fields {
  border: 1px solid var(--line);
  border-radius: calc(0.7em * var(--brm));
  corner-shape: superellipse(1.4);
  background: color-mix(in srgb, var(--shade) 14%, transparent);
  overflow: hidden;
}
:root[data-theme="light"] .fb-fields {
  background: color-mix(in srgb, white 55%, transparent);
}
.fb-field {
  display: block;
  padding: 13px 16px 10px;
  cursor: text;
  transition: background 0.15s;
}
.fb-field + .fb-field {
  border-top: 1px solid var(--line);
}
.fb-field:hover {
  background: color-mix(in srgb, var(--ink) 3%, transparent);
}
.fb-field:focus-within {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.fb-field:focus-within > span {
  color: var(--accent);
}
.fb-field > span {
  display: block;
  font-size: 14px;
  font-weight: 700;
}
/* Grows with what's written (field-sizing, or feedback.js where that's missing). */
.fb-field textarea {
  display: block;
  width: 100%;
  min-height: 2.9em;
  max-height: 14em;
  margin: 4px 0 0;
  padding: 0;
  border: 0;
  outline: 0;
  background: none;
  color: var(--ink);
  font-size: 15px;
  line-height: 1.45;
  resize: none;
  field-sizing: content;
}
.fb-field textarea::placeholder {
  color: color-mix(in srgb, var(--ink) 32%, transparent);
}
.eyebrow.fb-more {
  margin: 20px 4px 8px;
}
.fb-choice {
  margin: 20px 0 0;
  padding: 0;
  border: 0;
}
.fb-choice legend {
  padding: 0 4px;
  font-size: 14px;
  font-weight: 700;
}
.fb-options {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-top: 8px;
}
.fb-options label {
  display: grid;
  place-items: center;
  min-height: 48px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: calc(0.5em * var(--brm));
  corner-shape: superellipse(1.4);
  background: color-mix(in srgb, var(--shade) 12%, transparent);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  text-align: center;
  cursor: pointer;
  transition:
    background 0.15s,
    border-color 0.15s;
}
:root[data-theme="light"] .fb-options label {
  background: color-mix(in srgb, white 55%, transparent);
}
.fb-options label:hover {
  border-color: color-mix(in srgb, var(--ink) 20%, transparent);
}
.fb-options label:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.fb-options label:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.fb-options input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
/* An email to answer to (guests) or a switch (accounts): one quiet line. */
.fb-reply {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 20px 0 0;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: calc(0.6em * var(--brm));
  corner-shape: superellipse(1.4);
  font-size: 14px;
  font-weight: 600;
  overflow-wrap: anywhere;
  transition: border-color 0.15s;
}
.fb-reply:focus-within {
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
}
.fb-reply > span:first-child:not(.fb-reply-icon) {
  flex: 1;
  color: var(--ink-2);
}
.fb-reply b {
  color: var(--ink);
}
.fb-reply-icon {
  flex: none;
  color: var(--ink-3);
  font-weight: 700;
}
.fb-reply input[type="email"] {
  flex: 1;
  min-width: 0;
  padding: 2px 0;
  border: 0;
  outline: 0;
  background: none;
  color: var(--ink);
  font-size: 15px;
  font-weight: 500;
}
.fb-reply input[type="email"]::placeholder {
  color: color-mix(in srgb, var(--ink) 32%, transparent);
}
.fb-error {
  margin: 12px 0 0;
  color: var(--bad);
  font-size: 14px;
}
.fb-form .modal-actions {
  align-items: center;
}
.fb-note {
  margin-right: auto;
  color: var(--ink-3);
  font-size: 12.5px;
}
.fb-thanks {
  text-align: center;
}
.fb-thanks p {
  margin: 6px 0 0;
}
.fb-thanks .modal-actions {
  justify-content: center;
}
@media (max-width: 560px) {
  .fb-options {
    grid-template-columns: 1fr;
  }
}
