/* progress: ordered source sections, combined by the asset build. */
/* Progress: cumulative achievements with no calendar resets.
   Shared settings and mock-readiness styles are retained below.

   The page reads the same at every width: a page title over a summary panel
   and a list of rows, built from the theme tokens, so it follows day and night
   without a palette of its own. desktop-study.css only widens the scale. */
#home {
  border-top-color: var(--paper);
  padding: 0 0 calc(100px + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
  background: var(--paper);
  color: var(--ink);
}
#home .hinner {
  max-width: 540px;
}
#home.show .hinner > * {
  animation: none;
}
/* Row one: the shared header controls, above the title and level with the rest
   of the page's content, as on every other study tab. The row's shape is the
   shared rule below; only the page's own gutter lives here. */
.progress-actions {
  margin: 0 16px;
}
.progress-hero {
  padding: 0 16px;
}
/* The page-title tier every study page's heading wears: Topics, Preferences
   and the topic notes are the same size, weight and tracking. */
#home .progress-hero h1 {
  margin: 0;
  color: var(--ink);
  font:
    900 30px/1.2 Nunito,
    sans-serif;
  letter-spacing: -0.4px;
  text-wrap: initial;
}
/* The summary wears Practice tests' own blue (data-section="mocks"), as its
   header does. White on it clears only 3:1, so the heading stays large text,
   19px bold. The deeper bottom padding gives the diamond room beneath. */
.progress-summary-card {
  margin: 20px 0 0;
  padding: 18px 16px 31px;
  border-radius: 16px;
  background: var(--topic-banner);
  color: #fff;
}
#home .progress-summary-card h2 {
  margin: 0 0 13px;
  color: #fff;
  font:
    900 19px/1.3 Nunito,
    sans-serif;
}
.progress-summary-meter {
  display: flex;
  align-items: center;
  min-height: 34px;
  gap: 12px;
}
/* The meters keep a pale track and a dark label in both themes. Every fill is
   a bright colour that needs dark text on it, and no one label colour reads on
   both a bright fill and a dark track, so the track stays pale at night. */
.quest-track {
  position: relative;
  flex: 1;
  height: 20px;
  border-radius: 10px;
  background: #e8e8e8;
  overflow: hidden;
  isolation: isolate;
}
.quest-track-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--progress, 0%);
  border-radius: inherit;
  background: #ffc83a;
}
.quest-track-fill::after {
  content: "";
  position: absolute;
  inset: 3px 5px auto;
  height: 5px;
  border-radius: 6px;
  background: rgb(255 255 255 / 25%);
}
.quest-track-label {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #686868;
  font-size: 12px;
  line-height: 1;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}
/* On the empty track the count is a soft mid grey, the lightest that keeps
   4.5:1 on the track; once the fill passes the
   middle the count sits on colour, so it turns white with a soft drop. */
.quest-track.is-filled .quest-track-label {
  color: #fff;
  text-shadow: 0 1.5px 0 rgb(0 0 0 / 28%);
}
.quest-track.is-summary {
  height: 24px;
  border-radius: 12px;
}
.quest-track.is-summary .quest-track-fill {
  background: var(--brand);
}
.quest-track.is-lessons .quest-track-fill {
  background: #d83a48;
}
.quest-track.is-correct .quest-track-fill,
.quest-track.is-complete .quest-track-fill {
  background: #8bd437;
}
.milestones {
  padding: 0 16px;
}
/* A section heading over its list: spacing, not a fixed row height. */
.milestones-header {
  display: flex;
  align-items: center;
  padding: 20px 0 12px;
  border-bottom: 2px solid var(--line-2);
}
#home .milestones-header h2 {
  margin: 0;
  font:
    900 19px/1.3 Nunito,
    sans-serif;
  letter-spacing: -0.2px;
}
.milestones-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.milestone {
  display: flex;
  align-items: center;
  gap: 19px;
  width: 100%;
  min-height: 106px;
  padding: 19px 4px 19px 9px;
  border: 0;
  border-bottom: 2px solid var(--line-2);
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.milestone:disabled {
  cursor: default;
  opacity: 1;
}
.milestone:not(:disabled):hover {
  background: var(--panel);
}
.milestone:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: -3px;
  border-radius: 8px;
}
.milestones-list li:last-child .milestone {
  border-bottom: 0;
}
.milestone-content {
  flex: 1;
  min-width: 0;
}
/* The diamond for finishing every lesson ends the milestones bar, as a medal
   ends its milestone's: faded until won, full colour after. Faint white and
   blue sparkles twinkle round it either way. A thin white outline keeps the
   pale blue diamond from vanishing into the card's blue, so "faded" is only a
   touch here: half opacity would lose it again. */
.progress-summary-prize {
  position: relative;
  flex: none;
  width: 64px;
  height: 64px;
  margin: -16px 0;
}
.progress-summary-diamond {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: saturate(0.55) drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 1.5px #fff);
  opacity: 0.9;
}
.progress-summary-diamond.is-earned {
  filter: drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 1.5px #fff);
  opacity: 1;
}
.prize-sparkles i {
  position: absolute;
  width: 9px;
  height: 9px;
  background: #fff;
  clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
  opacity: 0;
  animation: prize-twinkle 2.4s ease-in-out infinite;
}
.prize-sparkles i:nth-child(1) {
  top: 16px;
  right: -3px;
}
.prize-sparkles i:nth-child(2) {
  top: 30px;
  left: -5px;
  width: 7px;
  height: 7px;
  background: #7dd3fc;
  animation-delay: 0.6s;
}
.prize-sparkles i:nth-child(3) {
  bottom: 4px;
  right: 6px;
  width: 7px;
  height: 7px;
  animation-delay: 1.2s;
}
.prize-sparkles i:nth-child(4) {
  top: 40px;
  left: 20px;
  width: 6px;
  height: 6px;
  background: #bae6fd;
  animation-delay: 1.8s;
}
@keyframes prize-twinkle {
  0%,
  100% {
    opacity: 0;
    transform: scale(0.4) rotate(0deg);
  }
  50% {
    opacity: 0.9;
    transform: scale(1) rotate(45deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .prize-sparkles i {
    animation: none;
    opacity: 0.6;
  }
}
/* The outline of this app's gem, measured from its diamond picture, so the
   glint in the diamond's moment stays on the gem (progress-diamond-reveal.css). */
.diamond-reveal {
  --diamond-outline: polygon(29.7% 35.3%, 70.2% 35.3%, 86.8% 53.8%, 49.4% 94%, 13% 53.7%);
}
.milestone-title {
  display: block;
  margin: 0 0 13px;
  font:
    850 17px/1.35 Nunito,
    sans-serif;
  color: var(--ink);
}
.milestone-meter {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* The medal a track has reached, always in full colour (the owner, 1 Oct
   2026: faded medals looked faint). */
.milestone-medal {
  display: block;
  flex: none;
  width: 64px;
  height: 64px;
  margin: -20px 0;
  object-fit: contain;
}
/* The medal hangs below its bar. A row with nothing under the bar ("Am I
   ready?") keeps the room a "milestones reached" line would take, so the medal
   sits as it does in every other row instead of on the row's rule. */
.milestone-meter:last-child {
  margin-bottom: 24px;
}
.milestone-reached {
  display: block;
  margin-top: 8px;
  color: var(--green-ink);
  font-size: 12px;
  font-weight: 900;
}
/* The settings button is one component, used on Progress and Learn. */
.settings-button {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 13px;
  background: var(--paper);
  color: var(--icon-quiet);
  box-shadow: none;
}
.settings-button svg {
  width: 24px;
  height: 24px;
  fill: currentColor;
}
.settings-button:hover {
  background: var(--panel);
}
/* The test-day countdown, study streak and review count sit beside Preferences
   in the same 44px row, borderless like it. */
.streak-button,
.test-day-button,
.review-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex: none;
  height: 44px;
  min-width: 44px;
  margin: 0;
  padding: 0 8px;
  border: 0;
  border-radius: 13px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 17px;
  font-weight: 850;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  box-shadow: none;
}
.streak-button svg,
.test-day-button svg,
.review-button svg {
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
}
.streak-button:hover,
.test-day-button:hover,
.review-button:hover {
  background: var(--panel);
}
/* No streak or due facts: the value steps back, but the button still opens
   its sheet. The icon uses .is-unlit (sheets.css). */
.streak-button:not(.is-lit) b,
.review-button:not(.is-due) b {
  color: var(--ink-3);
}
/* The test date is in words ("+ Test Date", "12 days"), so it takes a size
   under the counts beside it. Its calendar stays in colour, and with no date
   yet the words are an invitation in the brand's ink rather than a grey +. */
.test-day-button b {
  font-size: 15px;
}
.test-day-button:not(.is-set) b {
  color: var(--brand-ink);
}
/* Under 360px "+ Test Date" and the three buttons beside it only just share
   the row, so the test date's button gives up a little of its padding. */
@media (max-width: 359px) {
  .test-day-button {
    gap: 4px;
    padding: 0 4px;
  }
}
/* Row one, on every study tab: the same four controls, the same 44px height,
   the same space above and below, right-aligned on a wide screen and spread
   across their own row on a phone. Declared once, here with the controls it
   lays out and after each tab's own stylesheet, so no page can drift from it.
   Learn adds sticky on top of this (today.css); nothing else differs. */
.today-top,
.mock-library-heading,
.topics-heading,
.progress-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 15px 0 12px;
}
.header-actions {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
/* On phones the buttons spread across the row, as on every tab; wider screens
   pull them to the right. */
@media (max-width: 520px) {
  .header-actions {
    order: -1;
    width: 100%;
    justify-content: space-between;
  }
}
/* A reached goal waiting to be collected (owner, 5 Oct 2026, from a
   reference): its row is raised on a card with the app's border and lip, its
   bar full, its medal swinging gently from the ribbon and two sparkles
   twinkling beside it. Tapping it opens the medal (progress-medal-reveal.css). */
.milestone.is-ready {
  margin: 12px 0;
  padding: 17px 4px 17px 13px;
  border: 2px solid var(--line-2);
  border-radius: 16px;
  background: var(--paper);
  box-shadow: var(--drop) var(--lip);
}
.milestones-list li:last-child .milestone.is-ready {
  border-bottom: 2px solid var(--line-2);
}
.milestone.is-ready:active {
  transform: translateY(4px);
  box-shadow: 0 0 0 var(--lip);
}
.milestone.is-ready .milestone-meter {
  position: relative;
}
.milestone.is-ready .milestone-medal {
  transform-origin: 50% 8%;
  animation: medal-ready-swing 2.8s ease-in-out infinite;
}
.milestone.is-ready .milestone-reached {
  color: var(--brand-ink);
}
.milestone-sparkles i {
  position: absolute;
  width: 11px;
  height: 11px;
  background: var(--brand);
  clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
  opacity: 0;
  animation: prize-twinkle 2.4s ease-in-out infinite;
}
.milestone-sparkles i:nth-child(1) {
  top: -27px;
  right: 2px;
}
.milestone-sparkles i:nth-child(2) {
  bottom: -22px;
  right: 58px;
  width: 8px;
  height: 8px;
  background: #ffc83a;
  animation-delay: 1.2s;
}
@keyframes medal-ready-swing {
  0%,
  55%,
  100% {
    transform: rotate(0);
  }
  66% {
    transform: rotate(-10deg);
  }
  78% {
    transform: rotate(8deg);
  }
  89% {
    transform: rotate(-3deg);
  }
}
/* The medal flying home lands in this row (medal-reveal.js): the row's own
   medal is the far end of the flight, then it settles and the bar fills again
   from empty towards the next goal. */
.milestone.is-arriving .milestone-medal {
  view-transition-name: medal-flight;
}
.milestone.is-arriving .quest-track-fill {
  width: 0;
}
.milestone.is-landed .milestone-medal {
  animation: medal-land 0.4s var(--ease);
}
.milestone.is-landed .quest-track-fill {
  animation: track-refill 0.7s 0.15s var(--ease) both;
}
@keyframes medal-land {
  45% {
    transform: scale(1.18);
  }
}
@keyframes track-refill {
  from {
    width: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .milestone.is-ready .milestone-medal,
  .milestone-sparkles i,
  .milestone.is-landed .milestone-medal,
  .milestone.is-landed .quest-track-fill {
    animation: none;
  }
  .milestone-sparkles i {
    opacity: 1;
  }
}
/* The medal reveal (medal-reveal.html), laid out as the owner's reference: on
   the page's own paper, the metal's name in its colour, the medal large in the
   middle with a soft glow of its metal, one line, and the app's own Continue
   at the foot. Each metal's
   colours hang on data-tier; its name mixes the metal with the theme's ink, so
   it reads darker on white and lighter at night. The motion lives in
   progress-medal-reveal-motion.css. */
.medal-reveal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: calc(24px + var(--safe-area-inset-top, env(safe-area-inset-top, 0px))) 24px
    calc(120px + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
  background: var(--paper);
  color: var(--ink);
  text-align: center;
}
.medal-reveal:not(.show) {
  display: none;
}
.medal-reveal [data-tier="bronze"] {
  --tier-fill: #c47434;
  --tier-glow: rgb(228 164 100 / 55%);
}
.medal-reveal [data-tier="silver"] {
  --tier-fill: #a4acbc;
  --tier-glow: rgb(196 204 220 / 70%);
}
.medal-reveal [data-tier="gold"],
.medal-reveal [data-tier="royal"] {
  --tier-fill: #f4b424;
  --tier-glow: rgb(255 200 58 / 50%);
}
.medal-reveal-tier {
  display: grid;
  margin: 0;
  font:
    900 30px/1.2 Nunito,
    sans-serif;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.medal-reveal-tier span {
  grid-area: 1 / 1;
  color: color-mix(in srgb, var(--tier-fill) 60%, var(--ink));
}
.medal-reveal-art {
  position: relative;
  width: min(230px, 58vw);
  aspect-ratio: 1;
  margin: 30px 0 34px;
}
.medal-reveal-glow {
  position: absolute;
  inset: -24%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--tier-glow), transparent);
}
.medal-reveal-swing {
  position: absolute;
  inset: 0;
  transform-origin: 50% 6%;
  perspective: 700px;
}
.medal-reveal-sparkles i {
  position: absolute;
  width: 16px;
  height: 16px;
  background: var(--tier-fill);
  clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
  opacity: 0;
}
.medal-reveal-sparkles i:nth-child(1) {
  top: 18%;
  left: -14%;
}
.medal-reveal-sparkles i:nth-child(2) {
  top: 4%;
  right: -10%;
  width: 11px;
  height: 11px;
}
.medal-reveal-sparkles i:nth-child(3) {
  bottom: 14%;
  right: -16%;
}
.medal-reveal-sparkles i:nth-child(4) {
  bottom: 2%;
  left: -6%;
  width: 10px;
  height: 10px;
}
.medal-reveal-text {
  max-width: 340px;
  margin: 30px 0 0;
  font:
    900 21px/1.35 Nunito,
    sans-serif;
  color: var(--ink);
}
.medal-reveal-text:focus {
  outline: none;
}
/* Above the tour's own gold button rules, which place it in the page. */
.medal-reveal .medal-reveal-continue {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: calc(28px + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
  width: auto;
  max-width: 492px;
  margin: 0 auto;
}
/* The medal reveal's motion, timed from the moment it opens: the medal pops in
   with its name (0–0.5s), shakes on its ribbon (0.75s), spins in 3D
   (1.3–2.9s, progress-medal-coin.css) and comes round as the next metal at
   full speed (1.95s), when its name and glow change with it, then the
   line and Continue rise in (3s). With reduced motion it opens on the new
   metal, still. */
.medal-reveal.is-medal.show .medal-reveal-art {
  animation: medal-arrive 0.5s var(--ease) both;
}
.medal-reveal.is-medal.show .medal-reveal-tier {
  animation: medal-fade-in 0.4s 0.15s ease-out both;
}
.medal-reveal.is-medal.show .medal-reveal-swing {
  animation: medal-swing 0.55s 0.75s ease-in-out;
}
.medal-reveal.is-medal.show .medal-reveal-tier .is-from,
.medal-reveal.is-medal.show .medal-reveal-glow.is-from {
  animation: medal-turn-away 0.2s 1.7s ease-in forwards;
}
.medal-reveal.is-medal.show .medal-reveal-tier .is-to {
  animation: medal-name-in 0.4s 1.95s cubic-bezier(0.2, 0.8, 0.3, 1.3) both;
}
.medal-reveal.is-medal.show .medal-reveal-glow.is-to {
  animation: medal-glow 0.9s 1.95s ease-out both;
}
.medal-reveal.is-medal.show .medal-reveal-sparkles i {
  animation: prize-twinkle 2.4s 2.9s ease-in-out infinite;
}
.medal-reveal.is-medal.show .medal-reveal-sparkles i:nth-child(2) {
  animation-delay: 3.5s;
}
.medal-reveal.is-medal.show .medal-reveal-sparkles i:nth-child(3) {
  animation-delay: 4.1s;
}
.medal-reveal.is-medal.show .medal-reveal-sparkles i:nth-child(4) {
  animation-delay: 4.7s;
}
.medal-reveal.is-medal.show .medal-reveal-text {
  animation: medal-fade-in 0.4s 3s var(--ease) both;
}
.medal-reveal.is-medal.show .medal-reveal-continue {
  animation: medal-rise 0.4s 3.1s var(--ease) both;
}
/* Continue: the big prize is the near end of the flight to its place on the
   page. The rest of the reveal goes at once and the page comes back under the
   prize in flight. */
.medal-reveal.is-flying .medal-reveal-swing {
  view-transition-name: medal-flight;
}
::view-transition-group(medal-flight) {
  animation-duration: 0.75s;
  animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1);
}
::view-transition-old(root) {
  animation-duration: 0.18s;
}
::view-transition-new(root) {
  animation-duration: 0.4s;
}
@keyframes medal-arrive {
  from {
    opacity: 0;
    transform: scale(0.55);
  }
  70% {
    opacity: 1;
    transform: scale(1.06);
  }
}
@keyframes medal-fade-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}
@keyframes medal-swing {
  20% {
    transform: rotate(-10deg);
  }
  45% {
    transform: rotate(8deg);
  }
  70% {
    transform: rotate(-5deg);
  }
  88% {
    transform: rotate(2deg);
  }
}
@keyframes medal-turn-away {
  to {
    opacity: 0;
    transform: scale(0.7);
  }
}
@keyframes medal-name-in {
  from {
    opacity: 0;
    transform: scale(0.6);
  }
}
@keyframes medal-glow {
  from {
    opacity: 0;
    transform: scale(0.7);
  }
  45% {
    opacity: 1;
    transform: scale(1.12);
  }
}
/* Continue cannot be pressed until it is in place, but it can hold focus all
   along, so a learner who wants less motion lands on it at once. */
@keyframes medal-rise {
  from {
    opacity: 0;
    pointer-events: none;
    transform: translateY(16px);
  }
}
@media (prefers-reduced-motion: reduce) {
  .medal-reveal.show * {
    animation: none;
  }
  .medal-reveal .is-from {
    visibility: hidden;
  }
  .medal-reveal-sparkles i {
    opacity: 0.8;
  }
}
/* A prize in the reveal is a solid coin (owner, 5 Oct 2026: "make the
   trophy's 3D when spinning"): its face at the front and back, nine layers of
   its edge between them in the metal's darker shades (a band 10px deep when it
   turns side-on), and its ribbon hanging still behind (medal-reveal-coin). The
   parts are framed as the row's icon is, so laid together they are the icon. */
.medal-reveal-ribbon,
.medal-reveal-coin,
.medal-reveal-coin img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.medal-reveal-coin {
  transform-style: preserve-3d;
}
.medal-reveal-face {
  transform: translateZ(5px);
  backface-visibility: hidden;
}
.medal-reveal-face.is-back {
  transform: rotateY(180deg) translateZ(5px);
}
.medal-reveal-edge:nth-child(3) {
  transform: translateZ(4px);
}
.medal-reveal-edge:nth-child(4) {
  transform: translateZ(3px);
}
.medal-reveal-edge:nth-child(5) {
  transform: translateZ(2px);
}
.medal-reveal-edge:nth-child(6) {
  transform: translateZ(1px);
}
.medal-reveal-edge:nth-child(8) {
  transform: translateZ(-1px);
}
.medal-reveal-edge:nth-child(9) {
  transform: translateZ(-2px);
}
.medal-reveal-edge:nth-child(10) {
  transform: translateZ(-3px);
}
.medal-reveal-edge:nth-child(11) {
  transform: translateZ(-4px);
}
/* The medal spins four times, fastest in the middle, and becomes the next
   metal at full speed: both coins spin together and the first gives way to the
   second side on at 1.955s, while the ribbons cross over. It stops face on at
   2.9s (LANDS_MS in medal-reveal.js). */
.medal-reveal.is-medal.show .medal-reveal-coin.is-from {
  animation:
    medal-spin 1.6s 1.3s cubic-bezier(0.5, 0, 0.2, 1) both,
    medal-leave 0.01s 1.955s forwards;
}
.medal-reveal.is-medal.show .medal-reveal-coin.is-to {
  animation:
    medal-spin 1.6s 1.3s cubic-bezier(0.5, 0, 0.2, 1) both,
    medal-enter 0.01s 1.955s backwards;
}
.medal-reveal.is-medal.show .medal-reveal-ribbon.is-from {
  animation: medal-fade-away 0.3s 1.8s forwards;
}
.medal-reveal.is-medal.show .medal-reveal-ribbon.is-to {
  animation: medal-fade-up 0.3s 1.8s both;
}
@keyframes medal-spin {
  to {
    transform: rotateY(1440deg);
  }
}
@keyframes medal-leave {
  to {
    visibility: hidden;
  }
}
@keyframes medal-enter {
  from {
    visibility: hidden;
  }
}
@keyframes medal-fade-away {
  to {
    opacity: 0;
  }
}
@keyframes medal-fade-up {
  from {
    opacity: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .medal-reveal .medal-reveal-coin,
  .medal-reveal .medal-reveal-ribbon {
    animation: none;
  }
}
/* The diamond's own moment (medal-reveal.html, diamond-reveal): on the course
   card's colour, light rays turning slowly behind a flash, the gem arriving out
   of it and turning once as a solid crystal (progress-medal-coin.css), then a
   glint across its face and white sparkles, with the purchase tour's gold
   Continue. Timed from the moment it opens; reduced motion shows it still. */
.diamond-reveal {
  overflow: hidden;
  background: var(--topic-banner);
  color: #fff;
}
.diamond-reveal .medal-reveal-art::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: -1;
  width: 230vmax;
  height: 230vmax;
  background: repeating-conic-gradient(rgb(255 255 255 / 16%) 0deg 9deg, transparent 9deg 24deg);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.diamond-reveal .medal-reveal-tier span,
.diamond-reveal .medal-reveal-text {
  color: #fff;
}
.diamond-reveal-flash {
  position: absolute;
  top: 58%;
  left: 50%;
  width: 80%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side, #fff, rgb(255 255 255 / 0%));
  opacity: 0;
  transform: translate(-50%, -50%);
}
/* The glint is clipped to the gem's outline, which each app measures from its
   own diamond (--diamond-outline in its progress-prize.css). */
.diamond-reveal-glint {
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: var(--diamond-outline);
  pointer-events: none;
}
.diamond-reveal-glint::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 30%;
  background: linear-gradient(100deg, transparent, rgb(255 255 255 / 75%), transparent);
  transform: translateX(-160%) skewX(-18deg);
}
.diamond-reveal .medal-reveal-sparkles i {
  background: #fff;
}
.diamond-reveal .medal-reveal-sparkles i:nth-child(even) {
  background: #bae6fd;
}
.diamond-reveal .medal-reveal-sparkles i:nth-child(5) {
  top: 46%;
  left: -20%;
  width: 12px;
  height: 12px;
}
.diamond-reveal .medal-reveal-sparkles i:nth-child(6) {
  top: 40%;
  right: -18%;
  width: 9px;
  height: 9px;
}
.diamond-reveal .medal-reveal-continue {
  letter-spacing: 0.8px;
  text-transform: uppercase;
}
.diamond-reveal.show {
  animation: diamond-in 0.3s ease-out both;
}
.diamond-reveal.show .medal-reveal-art::before {
  animation:
    diamond-rays 48s linear infinite,
    diamond-in 0.9s 0.2s ease-out both;
}
.diamond-reveal.show .diamond-reveal-flash {
  animation: diamond-flash 0.75s 0.3s ease-out both;
}
.diamond-reveal.show .medal-reveal-swing {
  animation: diamond-arrive 0.7s 0.45s cubic-bezier(0.2, 0.8, 0.3, 1.25) both;
}
.diamond-reveal.show .medal-reveal-coin {
  animation: diamond-turn 1.3s 0.45s cubic-bezier(0.25, 0.6, 0.25, 1) both;
}
.diamond-reveal.show .diamond-reveal-glint::after {
  animation: diamond-glint 0.8s 1.85s ease-in-out 2 both;
}
.diamond-reveal.show .medal-reveal-tier {
  animation: medal-name-in 0.5s 0.55s cubic-bezier(0.2, 0.8, 0.3, 1.3) both;
}
.diamond-reveal.show .medal-reveal-sparkles i {
  animation: prize-twinkle 2.2s 1s ease-in-out infinite;
}
.diamond-reveal.show .medal-reveal-sparkles i:nth-child(2) {
  animation-delay: 1.4s;
}
.diamond-reveal.show .medal-reveal-sparkles i:nth-child(3) {
  animation-delay: 1.8s;
}
.diamond-reveal.show .medal-reveal-sparkles i:nth-child(4) {
  animation-delay: 2.2s;
}
.diamond-reveal.show .medal-reveal-sparkles i:nth-child(5) {
  animation-delay: 2.6s;
}
.diamond-reveal.show .medal-reveal-sparkles i:nth-child(6) {
  animation-delay: 3s;
}
.diamond-reveal.show .medal-reveal-text {
  animation: medal-fade-in 0.4s 2s var(--ease) both;
}
.diamond-reveal.show .medal-reveal-continue {
  animation: medal-rise 0.4s 2.1s var(--ease) both;
}
@keyframes diamond-in {
  from {
    opacity: 0;
  }
}
@keyframes diamond-rays {
  to {
    transform: translate(-50%, -50%) rotate(360deg);
  }
}
@keyframes diamond-flash {
  from {
    opacity: 1;
    transform: translate(-50%, -50%) scale(0);
  }
  35% {
    opacity: 1;
  }
  to {
    opacity: 0;
    transform: translate(-50%, -50%) scale(2.4);
  }
}
@keyframes diamond-arrive {
  from {
    opacity: 0;
    transform: scale(0.2);
  }
  30% {
    opacity: 1;
  }
}
@keyframes diamond-turn {
  from {
    transform: rotateY(-360deg);
  }
}
@keyframes diamond-glint {
  0% {
    transform: translateX(-160%) skewX(-18deg);
  }
  70%,
  100% {
    transform: translateX(420%) skewX(-18deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .diamond-reveal.show,
  .diamond-reveal.show *,
  .diamond-reveal.show .medal-reveal-art::before,
  .diamond-reveal.show .diamond-reveal-glint::after {
    animation: none;
  }
}
/* Finishing every lesson leaves the diamond waiting to be collected (owner,
   5 Oct 2026): it bobs on the course bar, its sparkles quicken and a line under
   the bar says to tap it; its moment is diamond-reveal (medal-reveal.js). It
   lands back here, settling as a medal does in its row. */
button.progress-summary-prize {
  display: block;
  padding: 0;
  border: 0;
  border-radius: 14px;
  background: none;
  box-shadow: none;
  cursor: pointer;
}
button.progress-summary-prize:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}
.progress-summary-prize.is-ready .progress-summary-diamond {
  animation: diamond-ready 2.2s ease-in-out infinite;
}
.progress-summary-prize.is-ready .prize-sparkles i {
  animation-duration: 1.4s;
}
.progress-summary-collect {
  margin: 14px 0 0;
  color: #fff;
  font-size: 15px;
  font-weight: 900;
}
.progress-summary-prize.is-arriving .progress-summary-diamond {
  view-transition-name: medal-flight;
}
.progress-summary-prize.is-landed .progress-summary-diamond {
  animation: medal-land 0.4s var(--ease);
}
@keyframes diamond-ready {
  0%,
  100% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-4px) scale(1.08);
  }
}
@media (prefers-reduced-motion: reduce) {
  .progress-summary-prize.is-ready .progress-summary-diamond,
  .progress-summary-prize.is-landed .progress-summary-diamond {
    animation: none;
  }
}
/* A header number that changed since it was last seen rolls to its new value
   (header-counts.js): each changed digit slides out of its slot as the new one
   slides in, upward as a number grows and downward as it falls, and the
   crumpet pops as a streak grows. The roll starts once the tab has eased in,
   and waits while the app is inert, under the opening screen or a sheet. */
.count-digit {
  position: relative;
  display: inline-block;
  /* The slot clips above and below, never beside: words are wider than digits. */
  clip-path: inset(0 -3em);
}
/* The old digit and the new move as one strip, a slot apart, with one timing:
   they never overlap, and the new one settles with a little spring. */
.count-old,
.count-new {
  animation-duration: 460ms;
  animation-delay: 320ms;
  animation-timing-function: cubic-bezier(0.35, 1.25, 0.45, 1);
  animation-fill-mode: both;
}
.count-old {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  animation-name: count-out-down;
}
.count-new {
  display: inline-block;
  animation-name: count-in-down;
}
.count-roll.is-up .count-old {
  animation-name: count-out-up;
}
.count-roll.is-up .count-new {
  animation-name: count-in-up;
}
/* The feed's answers in a row change as the answer lands, in view: the count
   rolls at once, while its chip pops (.pop, session-chrome.css). */
.chip .count-old,
.chip .count-new {
  animation-delay: 60ms;
}
.streak-button.is-rising svg {
  transform-origin: 50% 65%;
  animation: crumpet-rise 640ms cubic-bezier(0.3, 1.5, 0.5, 1) 360ms both;
}
[inert] .count-old,
[inert] .count-new,
[inert] .streak-button.is-rising svg {
  animation-play-state: paused;
}
@keyframes count-in-up {
  from {
    transform: translateY(100%);
  }
}
@keyframes count-out-up {
  to {
    transform: translateY(-100%);
  }
}
@keyframes count-in-down {
  from {
    transform: translateY(-100%);
  }
}
@keyframes count-out-down {
  to {
    transform: translateY(100%);
  }
}
@keyframes crumpet-rise {
  40% {
    transform: scale(1.3) rotate(-10deg);
  }
  70% {
    transform: scale(0.95) rotate(4deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .count-old {
    display: none;
  }
  .count-new,
  .streak-button.is-rising svg {
    animation: none;
  }
}
@media (max-width: 359px) {
  .progress-hero {
    padding-left: 12px;
    padding-right: 12px;
  }
  .progress-actions {
    margin-inline: 12px;
  }
  .milestones {
    padding: 0 12px;
  }
  .milestone {
    gap: 12px;
    padding-left: 0;
  }
  .milestone-title {
    font-size: 16px;
  }
}
/* Desktop: the page owns the gutter, so the controls row keeps the same edges
   as the hero and the list. */
@media (min-width: 960px) {
  #home .progress-actions {
    margin-inline: 0;
  }
  #home .milestones-header {
    min-height: 0;
    padding: 26px 0 14px;
  }
}
