:root {
  --owl-green: #58cc02;
  --owl-green-shadow: #58a700;
  --macaw-blue: #1cb0f6;
  --macaw-blue-shadow: #1899d6;
  --deep-blue: #2b70c9;
  --sunny-yellow: #ffc800;
  --sunny-yellow-shadow: #d49a00;
  --alert-red: #ff4b4b;
  --alert-red-shadow: #d83434;
  --purple-accent: #ce82ff;
  --purple-shadow: #9f55d8;
  --canvas: #ffffff;
  --hairline: #e5e5e5;
  --hairline-strong: #dadada;
  --ink: #3c3c3c;
  --muted-ink: #777777;
  --radius-control: 16px;
  --radius-card: 18px;
  --site-max-width: 1600px;
  --content-width: min(80%, var(--site-max-width));
  --hero-height: 434px;
  --font-display: "Fredoka", "Nunito", "Segoe UI", sans-serif;
  --font-ui: "Nunito", "Segoe UI", "Noto Sans", Arial, sans-serif;
  --font-nav: "Inter", "Segoe UI", "Noto Sans", Arial, sans-serif;
  --font-google-sans: "Google Sans", "Google Sans Text", var(--font-nav);
  /* Admin tool font: Latin/numbers in Google Sans, Korean in Noto Sans KR
     (high readability) — the admin UI is Korean-labelled. */
  --font-admin:
    "Google Sans", "Google Sans Text", "Noto Sans KR", "Malgun Gothic",
    var(--font-nav);
  --font-google-sans-flex:
    "Google Sans Flex", "Google Sans", "Google Sans Text", var(--font-nav);
  --font-sniglet: "Sniglet", var(--font-nav);
}

*,
*::before,
*::after {
  box-sizing: border-box;
  font-style: normal !important;
  font-synthesis-style: none;
}

html {
  font-style: normal !important;
  font-synthesis: none;
  /* Always reserve scrollbar space so header logo/nav/icons stay in the
     exact same position across pages, whether or not a page scrolls. */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-ui);
  font-style: normal !important;
  font-synthesis: none;
}

button {
  font: inherit;
  font-style: normal !important;
}

.app-shell {
  display: flex;
  width: 100%;
  flex-direction: column;
  min-height: 100vh;
  background: var(--canvas);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  min-height: 80px;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 5px max(10%, calc((100% - var(--site-max-width)) / 2));
  background: var(--canvas);
  border: 0;
  border-bottom: 1px solid rgba(229, 229, 229, 0.82);
  box-shadow: 0 2px 8px rgba(60, 60, 60, 0.08);
}

.top-nav {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  min-width: 0;
  align-items: center;
  justify-content: center;
  gap: 18px;
}

body:not(.subpage-active) .top-nav {
  display: none;
}

.top-nav-link {
  display: grid;
  width: 70px;
  min-width: 70px;
  min-height: 62px;
  align-content: center;
  justify-items: center;
  gap: 3px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  color: var(--muted-ink);
  cursor: pointer;
  font-family: var(--font-google-sans);
  font-size: 10px;
  font-weight: 800;
  line-height: 1.2;
  white-space: nowrap;
  transition:
    background 160ms ease,
    color 160ms ease,
    transform 160ms ease;
}

.nav-book {
  position: relative;
  display: grid;
  width: 70px;
  height: 50px;
  align-content: center;
  justify-items: center;
  gap: 0;
  place-items: center;
  overflow: hidden;
  border-radius: 24px;
  box-shadow: 0 5px 0 rgba(60, 60, 60, 0.16);
  color: var(--canvas);
  transform: none;
  transition:
    box-shadow 160ms ease,
    transform 160ms ease;
}

.nav-book-number {
  position: relative;
  z-index: 1;
  color: var(--canvas);
  font-family: var(--font-sniglet);
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
}

.nav-book-label {
  position: relative;
  z-index: 1;
  color: var(--canvas);
  font-family: var(--font-nav);
  font-size: 8px;
  font-weight: 800;
  line-height: 1;
}

.nav-level-one .nav-book {
  background: var(--sunny-yellow);
  box-shadow: 0 5px 0 var(--sunny-yellow-shadow);
}

.nav-level-two .nav-book {
  background: var(--alert-red);
  box-shadow: 0 5px 0 var(--alert-red-shadow);
}

.nav-level-three .nav-book {
  background: var(--macaw-blue);
  box-shadow: 0 5px 0 var(--macaw-blue-shadow);
}

.nav-level-four .nav-book {
  background: var(--purple-accent);
  box-shadow: 0 5px 0 var(--purple-shadow);
}

.brand {
  display: inline-flex;
  min-width: 0;
  align-items: center;
  padding: 0;
  background: none;
  border: 0;
  color: var(--deep-blue);
  cursor: pointer;
  filter: none;
  text-shadow: none;
  transition: transform 160ms ease;
}

.brand-name {
  display: inline-flex;
  min-width: 0;
  align-items: baseline;
  gap: 6px;
  color: var(--deep-blue);
  font-family: var(--font-display);
  font-size: 29px;
  font-style: normal !important;
  font-weight: 700;
  line-height: 1;
  filter: none;
  text-shadow: none;
  white-space: normal;
  transition:
    font-size 160ms ease,
    font-weight 160ms ease;
}

.brand-accent,
.brand-adventures {
  display: inline-flex;
  align-items: baseline;
}

.brand-accent {
  color: #16b8ad;
  font-family: "Cherry Bomb One", var(--font-display);
  font-size: 33px;
  font-weight: 400;
  text-shadow: none;
}

.brand-adventures {
  color: #f0643f;
  font-family: "Cherry Bomb One", var(--font-display);
  font-size: 33px;
  font-weight: 400;
  text-shadow: none;
}

.brand-accent,
.brand-adventures {
  transition: color 160ms ease;
}

body.subpage-active .brand-accent {
  color: #b0b0b0;
}

body.subpage-active .brand-adventures {
  color: #b0b0b0;
}

/* On subpages the logo is grayed out; on hover, restore its full main-page
   colors. Gated to hover-capable pointers so it doesn't stick on touch. */
@media (hover: hover) {
  body.subpage-active .brand:hover .brand-accent {
    color: #16b8ad;
  }

  body.subpage-active .brand:hover .brand-adventures {
    color: #f0643f;
  }
}

body.subpage-active .brand-name {
  font-size: 20px;
  font-weight: 600;
}

.login-button {
  display: inline-grid;
  width: 48px;
  height: 48px;
  flex: 0 0 auto;
  place-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  color: var(--muted-ink);
  cursor: pointer;
  transition:
    color 160ms ease,
    transform 160ms ease;
}

/* Once signed in (admin OR member), the header shows Log out (and Admin for
   admins) — hide the login icon so both aren't shown at once (desktop/tablet/mobile). */
body.signed-in .login-button {
  display: none;
}

.login-icon {
  width: 30px;
  height: 30px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.6;
}

main {
  flex: 1 0 auto;
  min-height: 0;
}

.screen {
  display: none;
}

.screen-active {
  display: block;
}

#contentScreen.screen-active {
  min-height: calc(100vh - 185px);
  background: var(--level-accent-soft, var(--canvas));
}

/* Month-selection pages — shared treatment for ALL levels (1-4). The layout,
   tactile button styling, centered Manrope numbers, and theme-tinted body are
   identical across levels (prototyped on Level 4, then rolled out to 1-3).
   Per-level colors come from the .level-theme-N CSS variables below.
   DESIGN.md grounding: saturated accent fill + white text for strong
   child-facing contrast (Learning Content Button); a thick bottom lip and no
   soft drop shadow (Tactile Depth); centered content; rounded rectangle (39px,
   from the base .month-button) per "rounded rectangles over pills". */
#monthScreen[class*="level-theme-"].screen-active {
  min-height: calc(100vh - 185px);
  background: var(--level-accent-soft, var(--canvas));
}

#monthScreen[class*="level-theme-"] .section-white {
  background: var(--level-accent-soft, var(--canvas));
}

#monthScreen[class*="level-theme-"] .month-button {
  align-items: center;
  justify-content: center;
  min-height: 137px;
  background: var(--level-accent, var(--canvas));
  border-color: var(--level-accent-shadow, var(--hairline));
  box-shadow: 0 7px 0 var(--level-accent-shadow, var(--hairline-strong));
}

#monthScreen[class*="level-theme-"] .month-button span,
#monthScreen[class*="level-theme-"] .month-button strong {
  color: var(--canvas);
}

/* Pin the month label top-left so the number can sit dead-center. */
#monthScreen[class*="level-theme-"] .month-button span {
  position: absolute;
  top: 28px;
  left: 18px;
}

#monthScreen[class*="level-theme-"] .month-button strong {
  align-self: center;
  margin-top: 0;
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  /* Keep the number white but add a thin outline in each level's own theme
     color — the accent-shadow token, a slightly deeper shade of the button
     background. paint-order draws the stroke behind the fill so the white
     weight is preserved. */
  -webkit-text-stroke: 1.25px var(--level-accent-shadow, rgba(0, 0, 0, 0.4));
  paint-order: stroke fill;
}

/* --content-* variables drive the V1 content-page design (weekday buttons +
   flat week-label cards). Level 1 holds the client-approved April values
   exactly; Levels 2-4 use the analogous shades from their own theme palette:
   --content-day-bg/-shadow = the theme-colored weekday button (3D),
   --content-day-text       = dark theme shade for the Mon–Fri label,
   --content-week-tint      = light theme tint for the flat week-label card. */
.level-theme-1 {
  --level-accent: var(--sunny-yellow);
  --level-accent-shadow: var(--sunny-yellow-shadow);
  --level-accent-soft: #fff3cc;
  --content-day-bg: #ffd43b;
  --content-day-shadow: #c78f00;
  --content-day-text: #8a6400;
  --content-week-tint: #ffe9a8;
}

.level-theme-2 {
  --level-accent: var(--alert-red);
  --level-accent-shadow: var(--alert-red-shadow);
  --level-accent-soft: #ffe8e8;
  --content-day-bg: #ff7676;
  --content-day-shadow: #e85555;
  --content-day-text: #a83838;
  --content-week-tint: #ffcfcf;
}

.level-theme-3 {
  --level-accent: var(--macaw-blue);
  --level-accent-shadow: var(--macaw-blue-shadow);
  --level-accent-soft: #e8f6ff;
  --content-day-bg: #45c0f7;
  --content-day-shadow: #2aa6e3;
  --content-day-text: #135f95;
  --content-week-tint: #c6e7ff;
}

.level-theme-4 {
  --level-accent: var(--purple-accent);
  --level-accent-shadow: var(--purple-shadow);
  --level-accent-soft: #f4e3ff;
  --content-day-bg: #da99ff;
  --content-day-shadow: #ad6ce0;
  --content-day-text: #71399f;
  --content-week-tint: #e6c9ff;
}

.section-box {
  width: 100%;
}

.site-footer {
  flex: 0 0 auto;
  padding: 44px clamp(24px, 5vw, 72px);
  background: var(--owl-green);
  border-top: 0;
  color: var(--canvas);
  text-align: center;
}

/* On a level page (페이지1/페이지2), blend the footer into the body: use the
   level's soft body tint as the background and the deeper theme shade for the
   copyright text (instead of the saturated accent fill + white text, which
   walled off the body and made it feel cramped). --level-accent-soft /
   --level-accent-shadow are set on the body's .level-theme-N class. */
body[class*="level-theme-"] .site-footer {
  background: var(--level-accent-soft);
  color: var(--level-accent-shadow);
}

.site-footer p {
  margin: 0;
  font-family: var(--font-nav);
  font-size: 13px;
  font-weight: 800;
  line-height: 1.35;
}

/* Main (home) page only: white footer band with dark-gray text (overrides the
   default green/white). Home is the only screen without `subpage-active`. */
body:not(.subpage-active) .site-footer {
  background: var(--canvas);
  color: var(--ink);
}

/* Main (home) page only: drop the footer copyright to a plain regular weight.
   Home is the only screen without `subpage-active` on <body> (app.js adds it to
   every other screen), so this scopes to the main page; all other pages keep
   the fully bold line (HOLD). */
body:not(.subpage-active) .site-footer p {
  font-size: 12px;
  font-weight: 400;
}

/* Keep the "TPS EDUCATION" name bold even where the line is regular weight. */
.site-footer p strong {
  font-weight: 700;
}

/* Login page recolors the shared footer to a clean white band with a hairline
   top border and muted dark text (the white/green default would be unreadable).
   `login-active` is toggled on <body> in app.js showScreen(). */
body.login-active .site-footer {
  background: var(--canvas);
  border-top: 1px solid var(--hairline);
  color: var(--muted-ink);
}

/* Login page only: drop the footer's all-bold weight to a plain regular.
   Other pages keep the fully bold line (HOLD). */
body.login-active .site-footer p {
  font-weight: 400;
}

/* ── Login page ──────────────────────────────────────────────────────────
   Frontend-only sign-in screen. Reuses the design system: Fredoka display
   title, soft-gray rounded inputs, the macaw-blue tactile primary button, and
   stroke buttons for social sign-in. No sign-up entry by request. */
/* Center the login card both ways in the space between header and footer.
   main grows to fill that space (app-shell flex column), the login screen
   fills main, and the section centers the card within it. */
body.login-active main {
  display: flex;
  flex-direction: column;
}

#loginScreen.screen-active {
  display: flex;
  flex: 1 1 auto;
}

.login-section {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
}

.login-card {
  width: min(100%, 416px);
}

.login-title {
  margin: 0 0 28px;
  color: var(--ink);
  font-family: "Cal Sans", var(--font-display);
  font-size: 32px;
  font-weight: 400;
  letter-spacing: 0.03em;
  text-align: center;
}

.login-form {
  display: grid;
  gap: 14px;
}

.login-field {
  position: relative;
}

.login-input {
  width: 100%;
  height: 58px;
  padding: 0 20px;
  background: #f7f7f7;
  border: 2px solid var(--hairline);
  border-radius: var(--radius-control);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 17px;
  font-weight: 600;
  transition:
    border-color 160ms ease,
    background 160ms ease;
}

.login-input::placeholder {
  color: var(--muted-ink);
  font-weight: 500;
}

.login-input:focus {
  background: var(--canvas);
  border-color: var(--macaw-blue);
  outline: none;
}

.login-submit {
  width: 100%;
  height: 75px;
  margin-top: 6px;
  background: var(--macaw-blue);
  border: 0;
  border-radius: var(--radius-control);
  box-shadow: 0 4px 0 var(--macaw-blue-shadow);
  color: var(--canvas);
  cursor: pointer;
  font-family: var(--font-nav);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition:
    transform 120ms ease,
    box-shadow 120ms ease;
}

.login-submit:active {
  transform: translateY(4px);
  box-shadow: none;
}

.login-legal {
  margin: 28px 0 0;
  color: var(--muted-ink);
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  text-align: center;
}

.login-legal strong {
  font-weight: 800;
}

.section-blue {
  background: var(--owl-green);
  color: var(--canvas);
}

.section-white {
  background: var(--canvas);
  color: var(--ink);
}

.section-inner {
  width: var(--content-width);
  margin: 0 auto;
  padding: 64px 24px;
}

.hero-section .section-inner {
  width: var(--content-width);
  height: var(--hero-height);
  min-height: 0;
  padding-right: clamp(42px, 5vw, 72px);
  padding-left: clamp(42px, 5vw, 72px);
  padding-top: 0;
  padding-bottom: 0;
}

.hero-section.section-blue {
  position: relative;
  height: var(--hero-height);
  background: var(--deep-blue);
  color: var(--canvas);
  overflow: hidden;
}

.hero-wave {
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  z-index: 2;
  display: block;
  width: 100%;
  height: 170px;
  pointer-events: none;
}

.hero-wave path {
  fill: var(--canvas);
}

.hero-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 44px;
}

.hero-grid {
  position: relative;
  /* No z-index here on purpose: the grid must NOT create a stacking context,
     so .hero-copy (z-index:3) can sit ABOVE the white wave (z-index:2) while
     .hero-stage / .hero-image (z-index:1) sit BELOW it — i.e. the characters
     emerge from behind the white curve, but the app-download buttons stay on
     top of it. */
  height: 100%;
  min-height: 0;
  align-items: stretch;
}

.hero-copy {
  min-width: 0;
  max-width: 650px;
}

.hero-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Above the white wave (z-index:2) so the text + app buttons are never
     covered; the image (z-index:1) stays behind the wave. */
  position: relative;
  z-index: 3;
  padding-top: 24px;
  padding-bottom: 130px;
}

.hero-copy h1,
.hero-copy p,
.app-downloads {
  animation: heroTextRise 720ms ease both;
}

/* Hero title: animate word-by-word instead of as one block. */
#homeTitle {
  animation: none;
}

.hero-word {
  display: inline-block;
  opacity: 0;
  animation: heroWordIn 600ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
}

/* Sequential reveal: each word starts ~0.17s after the previous. */
.hero-word:nth-child(1) {
  animation-delay: 0.05s;
}
.hero-word:nth-child(2) {
  animation-delay: 0.22s;
}
.hero-word:nth-child(3) {
  animation-delay: 0.39s;
}
.hero-word:nth-child(4) {
  animation-delay: 0.56s;
}

@keyframes heroWordIn {
  0% {
    opacity: 0;
    transform: translate3d(0, 26px, 0);
  }
  60% {
    opacity: 1;
    transform: translate3d(0, -6px, 0);
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

.hero-copy h1 {
  animation-delay: 100ms;
}

.hero-copy p {
  animation-delay: 190ms;
}

.app-downloads {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 30px;
  animation-delay: 280ms;
}

.app-download-button {
  display: inline-flex;
  width: 160px;
  min-height: 58px;
  align-items: center;
  gap: 10px;
  justify-content: flex-start;
  padding: 0 16px;
  background: #4db0ef;
  border-radius: 12px;
  box-shadow: 0 4px 0 #2d93d5;
  color: var(--canvas);
  font-family: var(--font-google-sans);
  text-decoration: none;
  transition:
    filter 160ms ease,
    transform 160ms ease,
    box-shadow 160ms ease;
}

.app-download-button span {
  display: grid;
  gap: 3px;
  line-height: 1;
}

.app-download-button small {
  color: var(--canvas);
  font-size: 10px;
  font-weight: 900;
  line-height: 1;
}

.app-download-button strong {
  color: var(--canvas);
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  white-space: nowrap;
}

.app-download-icon {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  fill: currentColor;
}

.eyebrow {
  display: inline-flex;
  width: fit-content;
  min-height: 34px;
  align-items: center;
  padding: 6px 12px;
  background: rgba(255, 255, 255, 0.22);
  border-radius: var(--radius-control);
  color: var(--canvas);
  font-size: 14px;
  font-style: normal !important;
  font-weight: 900;
  letter-spacing: 0;
}

.eyebrow.blue {
  background: #e8f6ff;
  color: var(--macaw-blue);
}

.hero-copy .eyebrow {
  background: rgba(255, 255, 255, 0.18);
  color: var(--canvas);
}

.eyebrow.green {
  background: #d7ffb8;
  color: var(--owl-green-shadow);
}

h1,
h2,
h3,
p,
figure {
  margin: 0;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-style: normal !important;
  font-weight: 700;
  letter-spacing: 0;
}

h1 {
  margin-top: 14px;
  color: var(--canvas);
  font-size: 48px;
  line-height: 1.08;
}

.hero-copy h1 {
  max-width: 500px;
  font-size: 49px;
  font-weight: 600;
  line-height: 1.08;
}

h2 {
  margin-top: 10px;
  color: inherit;
  font-size: 38px;
  line-height: 1.14;
}

h3 {
  color: var(--ink);
  font-size: 22px;
  line-height: 1.18;
}

p {
  margin-top: 16px;
  color: inherit;
  font-size: 18px;
  font-style: normal !important;
  font-weight: 700;
  line-height: 1.45;
}

.hero-copy p {
  width: min(100%, 460px);
  max-width: 460px;
  font-size: 16px;
  line-height: 1.42;
}

.section-white p {
  color: var(--muted-ink);
}

.hero-stage {
  position: relative;
  display: grid;
  height: 100%;
  min-width: 0;
  min-height: 0;
  place-items: center;
  overflow: visible;
}

/* Hero character rig: the base layer + cut-out parts (waving arm, two heads)
   are stacked; .hero-rig is the sized/positioned element that carries the gentle
   whole-character float, while each part oscillates around its joint on top
   (e-book / InDesign style subtle motion). */
.hero-rig {
  position: relative;
  z-index: 1;
  /* Anchor to the top of the hero with a fixed 30px gap, and let the image grow
     down toward the hero bottom (max-height = full height minus that 30px gap)
     so it scales up to nearly the top boundary. */
  align-self: start;
  width: min(390px, 82%);
  max-height: calc(100% - 30px);
  margin-top: 30px;
  margin-bottom: 0;
  filter: drop-shadow(0 22px 18px rgba(3, 29, 64, 0.2));
  transform: rotate(-2deg);
  animation: heroImageFloat 4.33s ease-in-out infinite;
  will-change: transform;
}

.hero-rig .hero-image {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
}

/* Each cut-out part overlays the base exactly (same full-canvas PNG) and rotates
   around its joint. transform-origin = joint position as % of the artwork. */
.hero-rig-part {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  pointer-events: none;
}

/* Dad's raised arm — wave, pivot at the shoulder. */
.hero-rig-f-arm {
  transform-origin: 25.4% 39.8%;
  animation: heroWave 1.73s ease-in-out infinite;
}

/* Girl's extended arm — gentler wave, pivot at her shoulder. */
.hero-rig-d-arm {
  transform-origin: 79% 62.2%;
  animation: heroWaveSmall 2.07s ease-in-out infinite;
}

/* Dad's head — sway, pivot at the neck. */
.hero-rig-f-head {
  transform-origin: 33.7% 28%;
  animation: heroSway 2.27s ease-in-out infinite;
}

/* Girl's head — sway (opposite phase), pivot at the neck. */
.hero-rig-d-head {
  transform-origin: 74.1% 61.8%;
  animation: heroSwayAlt 2s ease-in-out infinite;
}

@keyframes heroWave {
  0%,
  100% {
    transform: rotate(-9deg);
  }
  50% {
    transform: rotate(9deg);
  }
}

@keyframes heroWaveSmall {
  0%,
  100% {
    transform: rotate(6deg);
  }
  50% {
    transform: rotate(-6deg);
  }
}

@keyframes heroSway {
  0%,
  100% {
    transform: rotate(-3deg);
  }
  50% {
    transform: rotate(3deg);
  }
}

@keyframes heroSwayAlt {
  0%,
  100% {
    transform: rotate(3deg);
  }
  50% {
    transform: rotate(-3deg);
  }
}

@keyframes heroImageFloat {
  0%,
  100% {
    transform: translate3d(0, 0, 0) rotate(-2deg);
  }

  48% {
    transform: translate3d(10px, -13px, 0) rotate(1deg);
  }
}

@keyframes heroTextRise {
  from {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
  }

  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

.level-section {
  position: relative;
  z-index: 3;
  margin-top: -58px;
}

.level-section .section-inner {
  width: var(--content-width);
  padding: 9px clamp(42px, 5vw, 72px) 24px;
}

.level-section .eyebrow.blue {
  font-family: var(--font-nav);
}

.level-section h2 {
  font-family: "Nunito", var(--font-ui);
  font-weight: 900;
  font-size: 33px;
}

.level-grid {
  display: grid;
  /* Two-up from the smallest screens (2x2 for the four levels); widens to 4
     columns at >=768px. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
  justify-content: center;
}

.level-button,
.month-button,
.content-type,
.lesson-button,
.back-button {
  position: relative;
  min-width: 0;
  border: 0;
  border-radius: var(--radius-control);
  cursor: pointer;
  touch-action: manipulation;
  transition:
    box-shadow 160ms ease,
    filter 160ms ease,
    transform 160ms ease;
}

.level-button:active,
.month-button:active,
.content-type:active,
.lesson-button:active,
.back-button:active {
  transform: translateY(4px);
  box-shadow: none;
}

.level-button {
  display: grid;
  /* Single overlapping cell: the kicker pins to the top-left while the "Level N"
     label sits dead-center (both axes). Height reduced 10% (220 -> 198). */
  grid-template: 1fr / 1fr;
  min-height: 198px;
  padding: 28px;
  border-radius: 39px;
  color: var(--canvas);
  font-family: var(--font-nav);
  text-align: left;
}

.level-button > * {
  grid-area: 1 / 1;
}

.level-button strong {
  align-self: center;
  justify-self: center;
  margin-top: 0;
  font-family: var(--font-sniglet);
  font-size: 40px;
  font-style: normal !important;
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: 0;
  text-align: center;
}

.level-button small {
  align-self: end;
  justify-self: center;
  margin-top: 0;
  font-size: 16px;
  font-style: normal !important;
  font-weight: 800;
  line-height: 1.25;
  text-align: center;
}

.level-one {
  background: var(--sunny-yellow);
  box-shadow: 0 6px 0 var(--sunny-yellow-shadow);
}

.level-two {
  background: var(--alert-red);
  box-shadow: 0 6px 0 var(--alert-red-shadow);
}

.level-three {
  background: var(--macaw-blue);
  box-shadow: 0 6px 0 var(--macaw-blue-shadow);
}

.level-four {
  background: var(--purple-accent);
  box-shadow: 0 6px 0 var(--purple-shadow);
}

/* ──────────────────────────────────────────────────────────────────────────
   Home page layout. The level ("body") section flexes to fill the space between
   the header/hero (top) and footer (bottom); the level-button group is centered
   both axes. Same proven pattern as the login page (body.login-active main):
   make the home <main> a flex column, let the home screen fill it, and let the
   level section center its content. This vertically centers the buttons on EVERY
   device — including mobile (fixes the "buttons stuck near the top" issue).
   --home-fixed = button height cap so >=768px never scrolls; --home-lvl-gap is
   the gap between buttons. Bump --home-fixed up if a device shows a sliver.
   ────────────────────────────────────────────────────────────────────────── */
:root {
  --home-fixed: 590px;
  --home-lvl-gap: 22px;
}

body:not(.subpage-active) main {
  display: flex;
  flex-direction: column;
}

#homeScreen.screen-active {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

#homeScreen .hero-section.section-blue {
  flex: 0 0 auto;
}

#homeScreen .level-section {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  align-items: center;
  justify-content: center;
}

/* Tablet (landscape) + desktop: lay the four buttons in one centered row, sized
   to fill the available space at a 6:4 (w:h) ratio. Mobile keeps the base 2x2
   grid (just centered by the flex level-section above). */
@media (min-width: 768px) {
  #homeScreen .level-section .section-inner {
    display: flex;
    width: 100%;
    max-width: var(--site-max-width);
    height: auto;
    align-items: center;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
    padding-right: clamp(20px, 3vw, 64px);
    padding-left: clamp(20px, 3vw, 64px);
  }

  #homeScreen .level-grid {
    display: flex;
    width: 100%;
    gap: var(--home-lvl-gap);
    align-items: center;
    justify-content: center;
  }

  #homeScreen .level-button {
    flex: 0 0 auto;
    /* size = min(width-fit, height-fit, hard cap). 6:4 means width = height*1.5,
       so the height cap (100vh - --home-fixed) is multiplied by 1.5 here; the
       360px cap keeps buttons near PC size on very large monitors. */
    width: min(
      calc((100% - 3 * var(--home-lvl-gap)) / 4),
      calc((100vh - var(--home-fixed)) * 1.5),
      360px
    );
    height: auto;
    min-height: 0;
    padding: 12px;
    aspect-ratio: 6 / 4;
  }

  /* Keep "Level N" on a single line, scaled to the button width. */
  #homeScreen .level-button strong {
    white-space: nowrap;
    font-size: clamp(24px, 3.2vw, 40px);
  }
}

/* PC only (>1180px): restore the original left/right margin around the level
   button group. Tablets (768-1180px) keep the full-width layout above so their
   buttons stay large; PCs narrow the grid back to --content-width (80%) so the
   group sits centered with breathing room on both sides. */
@media (min-width: 1181px) {
  #homeScreen .level-section .section-inner {
    width: var(--content-width);
    max-width: var(--site-max-width);
    padding-right: clamp(42px, 5vw, 72px);
    padding-left: clamp(42px, 5vw, 72px);
  }
}

/* Mobile: drop the hero-wave overlap (-58px) so the level section starts at the
   hero bottom; with symmetric padding the 2x2 button group then centers cleanly
   between the hero and the footer instead of tucking up under the hero. */
@media (max-width: 767px) {
  #homeScreen .level-section {
    margin-top: 0;
  }

  #homeScreen .level-section .section-inner {
    padding-top: 0;
    padding-bottom: 0;
  }
}

.overview-section .section-inner {
  padding-top: 54px;
  padding-bottom: 78px;
}

.overview-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.overview-card {
  min-height: 220px;
  padding: 26px;
  background: var(--canvas);
  border: 2px solid var(--hairline);
  border-radius: var(--radius-card);
  box-shadow: 0 6px 0 var(--hairline-strong);
}

.overview-number {
  display: inline-flex;
  margin-bottom: 18px;
  color: var(--macaw-blue);
  font-family: var(--font-nav);
  font-size: 14px;
  font-weight: 800;
  line-height: 1;
}

.overview-card p {
  color: var(--muted-ink);
  font-size: 17px;
}

.screen-heading {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  margin-bottom: 30px;
}

.month-header {
  margin-bottom: 80px;
}

.month-heading {
  margin-bottom: 0;
}

#contentScreen .section-inner {
  position: relative;
  width: 100%;
  padding-right: 78px;
  padding-left: 78px;
}

#contentScreen .content-main-header {
  margin-bottom: 34px;
}

.back-button {
  min-height: 50px;
  padding: 0 18px;
  flex: 0 0 auto;
  background: var(--macaw-blue);
  box-shadow: 0 4px 0 var(--macaw-blue-shadow);
  color: var(--canvas);
  font-size: 15px;
  font-weight: 900;
}

.month-grid {
  display: grid;
  /* Two columns from the smallest screens up (2x5 for Mar–Dec) so the month
     list isn't a single very tall column on phones; widens to 5 at >=768px. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 12px;
  row-gap: 20px;
}

#monthScreen .month-heading {
  width: 100%;
  justify-content: center;
  text-align: center;
}

#monthScreen .screen-heading h2 {
  color: var(--level-accent-shadow, var(--ink));
}

.month-button {
  display: flex;
  width: 90%;
  min-height: 112px;
  justify-self: center;
  flex-direction: column;
  justify-content: center;
  padding: 28px 18px;
  background: var(--canvas);
  border: 2px solid var(--hairline);
  border-radius: 39px;
  box-shadow:
    0 7px 0 var(--hairline-strong),
    0 12px 18px rgba(60, 60, 60, 0.08);
  color: var(--ink);
  font-family: var(--font-google-sans);
  text-align: left;
}

.month-button span {
  color: var(--level-accent, var(--macaw-blue));
  font-size: 13px;
  font-weight: 900;
}

.month-button strong {
  align-self: center;
  /* inline-flex + flex-end bottom-aligns the number and the "월" suffix despite
     their different typefaces/sizes; nowrap keeps them on one line (e.g. "12월"). */
  display: inline-flex;
  align-items: flex-end;
  margin-top: 8px;
  color: var(--level-accent-shadow, var(--ink));
  font-family: "Concert One", var(--font-display);
  font-size: 52px;
  font-style: normal !important;
  font-weight: 400;
  line-height: 1;
  white-space: nowrap;
}

/* The "월" suffix uses its own typeface, sized relative to the number (em) so it
   tracks the digit size across breakpoints and stays visually similar. It sits
   inline right after the number, bottom-aligned via the flex parent. */
.month-button strong .month-num {
  /* <i> wrapper so the number keeps the strong's typeface/weight (font-style
     reset from the italic default). Nudged down so its baseline meets the "월"
     glyph's bottom, compensating for the two fonts' differing descenders. */
  font-style: normal;
  transform: translateY(0.12em);
}

.month-button strong .month-suffix {
  margin-left: 0.06em;
  font-family: "Nanum Gothic Coding", monospace;
  font-style: normal;
  font-weight: 700;
  font-size: 0.62em;
  line-height: 1;
}

.content-toolbar {
  display: grid;
  grid-template-columns: minmax(112px, 150px) 82px repeat(5, minmax(86px, 1fr));
  gap: 30px;
  margin-bottom: 24px;
  padding: 6px 50px 14px;
  overflow-x: auto;
}

.content-type {
  display: inline-flex;
  min-height: 56px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 12px;
  background: var(--canvas);
  border-radius: 26px;
  box-shadow:
    0 6px 0 #d8d8d8,
    0 10px 16px rgba(30, 90, 0, 0.14);
  color: #0878c8;
  font-size: 15px;
  font-weight: 900;
}

.content-type-icon {
  display: grid;
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  place-items: center;
  background: #e8f6ff;
  border-radius: 50%;
  color: #0878c8;
  font-family: var(--font-google-sans);
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
}

.content-type.active {
  background: #ffd43b;
  box-shadow:
    0 6px 0 #c78f00,
    0 10px 16px rgba(30, 90, 0, 0.16);
  color: #2f2f2f;
}

.content-type.active .content-type-icon {
  background: rgba(255, 255, 255, 0.55);
  color: #2f2f2f;
}

#contentScreen .content-v2-back {
  background: #f1f1f1;
  box-shadow: 0 4px 0 #d8d8d8;
  color: var(--muted-ink);
}

/* Month detail page: light per-level tinted background (replaces green).
   Text colors flip to dark/themed so they stay readable on the light tint.
   Scoped to #contentScreen so the V2 candidate page keeps its green styling. */
#contentScreen .section-blue {
  background: var(--level-accent-soft, var(--canvas));
  color: var(--ink);
}

#contentScreen .content-v2-title-block h2 {
  font-family: "Baloo 2", var(--font-ui);
  font-weight: 800;
  color: var(--level-accent-shadow, var(--ink));
}

/* Level label under the title is hidden for now (to be redone separately later). */
#contentScreen .content-v2-level {
  display: none;
}

#contentScreen .content-v2-month-pill {
  background: rgba(255, 255, 255, 0.6);
  color: var(--level-accent-shadow, var(--ink));
}

#contentScreen .content-v2-month-pill strong {
  background: var(--level-accent, var(--macaw-blue));
  color: var(--canvas);
}

/* Centered level + book-band banner at the top of the content page.
   Text style matches the main "Start Reading" level box; color per level theme.
   Trial: shown on the March page of each level only (pending review). */
#contentScreen .content-level-banner {
  display: grid;
  justify-items: center;
  gap: 4px;
  margin-bottom: 26px;
  text-align: center;
}

#contentLevelName,
#monthLevelTag {
  font-family: var(--font-sniglet);
  font-size: 40px;
  font-weight: 700;
  line-height: 1.02;
  color: var(--level-accent-shadow, var(--ink));
}

#contentLevelBand {
  font-family: var(--font-nav);
  font-size: 16px;
  font-weight: 800;
  line-height: 1.25;
  color: var(--level-accent-shadow, var(--muted-ink));
}

/* Banner month pill: hidden by default; shown centered under the band on April. */
#contentScreen .content-banner-month {
  display: inline-flex;
  margin-top: 8px;
}

/* All content pages: show the banner month as a bare number in a circle.
   Drop the "Month" label (font-size:0 hides the text node) and the pill
   background; the circle keeps its per-level theme color (var(--level-accent),
   set on .content-v2-month-pill strong). 60px circle, Manrope 800 / 36px. */
#contentScreen .content-banner-month {
  gap: 0;
  padding: 0;
  background: transparent;
  font-size: 0;
}

#contentScreen .content-banner-month strong {
  width: 60px;
  height: 60px;
  font-family: "Manrope", sans-serif;
  font-size: 36px;
  font-weight: 800;
}

/* Content page: title-block hidden — level + month show in the centered banner. */
#contentScreen .content-v2-title-block {
  display: none;
}

/* Content page: the nav row (Back/Next) sits just below the top header,
   above the centered banner, with a small margin. */
#contentScreen[data-month] .section-inner {
  display: flex;
  flex-direction: column;
  padding-top: 20px;
}

#contentScreen[data-month] .content-main-header {
  order: -1;
  margin-bottom: 8px;
}

/* Month navigation buttons: Next styled like Back. Back is hidden on the first
   month (March) and Next on the last (December); they keep their slot so the
   remaining button stays in place. */
#contentScreen .content-v2-next {
  background: #f1f1f1;
  box-shadow: 0 4px 0 #d8d8d8;
  color: var(--muted-ink);
}

#contentScreen[data-month="March"] .content-v2-back {
  visibility: hidden;
}

#contentScreen[data-month="December"] .content-v2-next {
  visibility: hidden;
}

.content-type:nth-child(1) {
  grid-column: 3;
}

.content-type:nth-child(2) {
  grid-column: 4;
}

.content-type:nth-child(3) {
  grid-column: 5;
}

.content-type:nth-child(4) {
  grid-column: 6;
}

.content-type:nth-child(5) {
  grid-column: 7;
}

/* ----------------------------------------------------------------------
   V1 content-page design — applied to ALL levels (1-4) and ALL months.
   Rolled out from the client-approved Level 1 / April page. Per-level colors
   come from the .level-theme-N --content-* variables. Toolbar is reduced to
   Opening + Ending Song (centered); the weekday board uses theme-colored 3D
   buttons with flat, tinted week-label cards.
   ---------------------------------------------------------------------- */

/* Hide Story / Word Chant / Sentence Chant, leaving Opening + Ending Song. */
#contentScreen .content-type:nth-child(2),
#contentScreen .content-type:nth-child(3),
#contentScreen .content-type:nth-child(4) {
  display: none;
}

/* Center the remaining Opening / Ending Song buttons in the screen
   instead of leaving them left-aligned in the toolbar grid. */
/* All content pages: center Opening/Ending Song and tighten the gap to the
   weekday board (~50% of the original). The board's top padding is halved in
   the >=768px block (desktop) so mobile keeps its smaller padding. */
#contentScreen .content-toolbar {
  display: flex;
  justify-content: center;
  margin-bottom: 12px;
  padding-bottom: 7px;
}

/* Opening + Ending Song buttons: keep the 3D depth (the 0 6px bevel) but drop
   the soft drop shadow, and bump the label 15->17px (the button is
   content-sized, so its width grows proportionally with the text). */
#contentScreen .content-type {
  box-shadow: 0 6px 0 #d8d8d8;
  font-size: 17px;
}

/* Drop Opening Song's yellow "active" accent so it matches Ending Song's
   default white/blue style (same bevel-only shadow). */
#contentScreen .content-type.active {
  background: var(--canvas);
  box-shadow: 0 6px 0 #d8d8d8;
  color: #0878c8;
}

#contentScreen .content-type.active .content-type-icon {
  background: #e8f6ff;
  color: #0878c8;
}

/* Unify every weekday button (Mon–Fri, all weeks) to the level theme color,
   overriding the per-day day-3 / day-5 / base colors. */
#contentScreen .lesson-button {
  background: var(--content-day-bg);
  box-shadow:
    0 7px 0 var(--content-day-shadow),
    0 12px 18px rgba(30, 90, 0, 0.16);
  color: #2f2f2f;
}

/* Weekday label (Mon–Fri): larger text in the dark theme shade. */
#contentScreen .lesson-button strong {
  font-size: 24px;
  color: var(--content-day-text);
}

/* Week-label cards (1 week–4 week): flat (2D) on a light theme tint that sits
   between the page background and the weekday buttons so they stay visible. */
#contentScreen .week-label {
  background: var(--content-week-tint);
  box-shadow: none;
}

.lesson-board {
  padding: 50px;
  overflow-x: auto;
  background: transparent;
  border-radius: 0;
}

.lesson-grid {
  display: grid;
  min-width: 900px;
  grid-template-columns: minmax(112px, 150px) 82px repeat(5, minmax(86px, 1fr));
  gap: 30px;
}

.book-title-card {
  display: grid;
  min-height: 202px;
  grid-row: span 2;
  overflow: hidden;
  background: #f5f5f5;
  border-radius: 26px;
  box-shadow:
    inset 0 0 0 2px #e0e0e0,
    0 7px 0 #cfcfcf,
    0 12px 18px rgba(30, 90, 0, 0.12);
}

/* Book cover art on the two title-card placeholders. The cards are shared
   markup (all levels/months render the white placeholder); app.js adds
   .has-cover and an inline background-image from the content data only when a
   cover is set for the current level/month, so every other page keeps the
   empty placeholder. Cover fills the card (aspect kept, slight crop is fine);
   no 3D lip — instead a 3px white outline OUTSIDE the cover (outset box-shadow,
   not inset, so it never covers the image) following the rounded corners. */
.book-title-card.has-cover {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  box-shadow: 0 0 0 3px #ffffff;
}

/* Level 1 only: a single cover instead of two. The second card is dropped at
   every breakpoint; the first reserves the whole left column (4 rows) so the
   weekday grid auto-flows unchanged, while the cover itself keeps its current
   size/proportion (aspect-ratio, not stretched) and sits vertically centered
   in that 1–4 week span. Column width is untouched, so the tablet/mobile
   no-scroll layouts are unaffected. Levels 2–4 keep both covers. */
#contentScreen.level-theme-1 .book-title-card.book-2 {
  display: none;
}

@media (min-width: 768px) {
  #contentScreen.level-theme-1 .book-title-card.book-1 {
    grid-column: 1;
    grid-row: 1 / span 4;
    align-self: center;
    aspect-ratio: 150 / 202;
    min-height: 0;
  }
}

.week-label {
  display: grid;
  min-height: 86px;
  place-items: center;
  background: #f8f8f8;
  border-radius: 24px;
  box-shadow:
    0 7px 0 #d0d0d0,
    0 12px 18px rgba(30, 90, 0, 0.12);
  color: #383838;
  font-family: var(--font-google-sans);
  font-size: 14px;
  font-weight: 900;
}

.lesson-button {
  display: flex;
  min-height: 86px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 6px 4px;
  background: #159ee8;
  border-radius: 26px;
  box-shadow:
    0 7px 0 #0878b8,
    0 12px 18px rgba(30, 90, 0, 0.16);
  color: var(--canvas);
}

.lesson-button.day-1 {
  background: #ffd43b;
  box-shadow:
    0 7px 0 #c78f00,
    0 12px 18px rgba(30, 90, 0, 0.16);
  color: #2f2f2f;
}

.lesson-button.day-3 {
  background: #2fa900;
  box-shadow:
    0 7px 0 #1f7900,
    0 12px 18px rgba(30, 90, 0, 0.18);
}

.lesson-button.day-5 {
  background: #b75ef4;
  box-shadow:
    0 7px 0 #8440bf,
    0 12px 18px rgba(30, 90, 0, 0.16);
}

.lesson-button strong {
  font-size: 20px;
  font-weight: 900;
  line-height: 1;
}

#contentScreenV2.screen-active {
  min-height: calc(100vh - 185px);
  background: #4cc703;
}

.content-v2-section {
  background: #4cc703;
}

.content-v2-inner {
  width: 100%;
  padding: 76px clamp(92px, 7vw, 136px) 84px;
}

.content-v2-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 34px;
}

.content-v2-title-block {
  display: grid;
  gap: 10px;
}

.content-v2-month-pill,
.content-v2-level {
  display: inline-flex;
  width: fit-content;
  align-items: center;
  gap: 8px;
  color: var(--canvas);
  font-family: var(--font-google-sans);
  font-size: 14px;
  font-weight: 900;
  line-height: 1;
}

.content-v2-month-pill {
  padding: 9px 14px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 999px;
}

.content-v2-month-pill strong {
  display: grid;
  width: 26px;
  height: 26px;
  place-items: center;
  background: var(--canvas);
  border-radius: 50%;
  color: var(--level-accent, var(--macaw-blue));
  font-size: 16px;
}

.content-v2-title-block h2 {
  color: var(--canvas);
  font-family: "Nunito", var(--font-ui);
  font-size: 33px;
  font-weight: 900;
}

.content-v2-level {
  opacity: 0.9;
}

.content-v2-back {
  background: #f1f1f1;
  box-shadow: 0 4px 0 #d8d8d8;
  color: var(--muted-ink);
}

.content-v2-tabs,
.content-v2-grid {
  display: grid;
  grid-template-columns: minmax(116px, 148px) 76px repeat(5, minmax(92px, 1fr));
  gap: 22px;
}

.content-v2-tabs {
  margin-bottom: 24px;
  padding: 0 28px;
  overflow-x: auto;
}

.content-v2-tab {
  display: inline-flex;
  min-height: 50px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 14px;
  background: rgba(255, 255, 255, 0.95);
  border: 0;
  border-radius: 999px;
  box-shadow: 0 5px 0 rgba(60, 60, 60, 0.14);
  color: #0878c8;
  cursor: pointer;
  font-size: 15px;
  font-weight: 900;
}

.content-v2-tab.active {
  background: #ffd43b;
  box-shadow: 0 5px 0 #c78f00;
  color: #2f2f2f;
}

.content-v2-tab:nth-child(1) {
  grid-column: 3;
}

.content-v2-tab:nth-child(2) {
  grid-column: 4;
}

.content-v2-tab:nth-child(3) {
  grid-column: 5;
}

.content-v2-tab:nth-child(4) {
  grid-column: 6;
}

.content-v2-tab:nth-child(5) {
  grid-column: 7;
}

.content-v2-tab-icon {
  display: grid;
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  place-items: center;
  background: #e8f6ff;
  border-radius: 50%;
  color: #0878c8;
  font-family: var(--font-google-sans);
  font-size: 14px;
  font-weight: 900;
}

.content-v2-tab.active .content-v2-tab-icon {
  background: rgba(255, 255, 255, 0.55);
  color: #2f2f2f;
}

.content-v2-board {
  padding: 28px;
  overflow-x: auto;
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 28px;
}

.content-v2-grid {
  min-width: 920px;
}

.content-v2-book-card {
  display: grid;
  min-height: 178px;
  grid-row: span 2;
  place-items: center;
  align-content: center;
  gap: 12px;
  background: #f4f4f4;
  border-radius: 22px;
  box-shadow: inset 0 0 0 2px #dddddd;
  color: #686868;
  font-family: var(--font-google-sans);
  font-size: 14px;
  font-weight: 900;
}

.content-v2-book-icon {
  position: relative;
  display: block;
  width: 42px;
  height: 52px;
  background: #ffffff;
  border-radius: 6px 12px 10px 6px;
  box-shadow: inset 7px 0 0 #e6e6e6;
}

.content-v2-week-label {
  display: grid;
  min-height: 78px;
  place-items: center;
  align-content: center;
  gap: 2px;
  background: rgba(255, 255, 255, 0.72);
  border-radius: 999px;
  color: #424242;
  font-family: var(--font-google-sans);
  font-weight: 900;
}

.content-v2-week-label span {
  font-size: 21px;
  line-height: 1;
}

.content-v2-week-label strong {
  font-size: 11px;
  line-height: 1;
  text-transform: uppercase;
}

.content-v2-day-button {
  min-height: 78px;
  padding: 0 10px;
  border: 0;
  border-radius: 22px;
  background: #159ee8;
  box-shadow: 0 6px 0 #0878b8;
  color: var(--canvas);
  cursor: pointer;
}

.content-v2-day-button.day-1 {
  background: #ffd43b;
  box-shadow: 0 6px 0 #c78f00;
  color: #2f2f2f;
}

.content-v2-day-button.day-3 {
  background: #208d00;
  box-shadow: 0 6px 0 #176700;
}

.content-v2-day-button.day-5 {
  background: #b75ef4;
  box-shadow: 0 6px 0 #8440bf;
}

.content-v2-day-button strong {
  font-size: 21px;
  font-weight: 900;
}

#contentScreenV3.screen-active {
  min-height: calc(100vh - 185px);
  background: #f4fbff;
}

.content-v3-section {
  min-height: calc(100vh - 185px);
  background: linear-gradient(180deg, #2b70c9 0 335px, #f4fbff 335px 100%);
  color: var(--ink);
}

.content-v3-inner {
  width: min(1320px, 100%);
  padding: 70px clamp(32px, 5vw, 72px) 86px;
}

.content-v3-hero {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 26px;
  color: var(--canvas);
}

.content-v3-title-block {
  display: grid;
  max-width: 760px;
  gap: 10px;
}

.content-v3-kicker,
.content-v3-title-row,
.content-v3-month-badge,
.content-v3-level {
  display: inline-flex;
  width: fit-content;
  align-items: center;
}

.content-v3-kicker {
  min-height: 34px;
  padding: 7px 13px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-control);
  color: var(--canvas);
  font-family: var(--font-google-sans);
  font-size: 13px;
  font-weight: 900;
}

.content-v3-title-row {
  gap: 10px;
}

.content-v3-month-badge,
.content-v3-level {
  gap: 8px;
  min-height: 38px;
  padding: 8px 14px;
  background: var(--canvas);
  border-radius: 999px;
  color: var(--deep-blue);
  font-family: var(--font-google-sans);
  font-size: 14px;
  font-weight: 900;
}

.content-v3-month-badge strong {
  display: grid;
  width: 24px;
  height: 24px;
  place-items: center;
  background: var(--owl-green);
  border-radius: 50%;
  color: var(--canvas);
  line-height: 1;
}

.content-v3-title-block h2 {
  margin-top: 0;
  color: var(--canvas);
  font-size: clamp(38px, 4vw, 58px);
  line-height: 0.98;
}

.content-v3-title-block p {
  width: min(100%, 560px);
  margin-top: 0;
  color: rgba(255, 255, 255, 0.88);
  font-size: 17px;
  line-height: 1.4;
}

.content-v3-back {
  margin-top: 20px;
  background: var(--canvas);
  box-shadow: 0 4px 0 rgba(255, 255, 255, 0.55);
  color: var(--deep-blue);
}

.content-v3-typebar {
  display: grid;
  grid-template-columns: repeat(5, minmax(130px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
  padding: 18px;
  background: var(--canvas);
  border: 2px solid #d9eefc;
  border-radius: 26px;
  box-shadow:
    0 8px 0 #c5e6fa,
    0 18px 32px rgba(20, 83, 163, 0.12);
}

.content-v3-type {
  display: inline-flex;
  min-height: 58px;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 0 12px;
  border: 0;
  border-radius: 18px;
  background: #f5fbff;
  box-shadow: 0 4px 0 #d8edf8;
  color: var(--deep-blue);
  cursor: pointer;
  font-family: var(--font-google-sans);
  font-size: 15px;
  font-weight: 900;
  line-height: 1.1;
  transition:
    box-shadow 160ms ease,
    filter 160ms ease,
    transform 160ms ease;
}

.content-v3-type-icon {
  display: grid;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  place-items: center;
  background: var(--canvas);
  border-radius: 50%;
  color: currentColor;
  font-family: var(--font-google-sans);
  font-size: 15px;
  font-weight: 900;
}

.content-v3-type.active,
.content-v3-type[data-content-type="openingSong"] {
  background: #ff5c7a;
  box-shadow: 0 4px 0 #d83e5a;
  color: var(--canvas);
}

.content-v3-type[data-content-type="story"] {
  background: #1cb0f6;
  box-shadow: 0 4px 0 #1899d6;
  color: var(--canvas);
}

.content-v3-type[data-content-type="wordChant"] {
  background: #06d6a0;
  box-shadow: 0 4px 0 #05a77d;
  color: #113f37;
}

.content-v3-type[data-content-type="sentenceChant"] {
  background: #b75ef4;
  box-shadow: 0 4px 0 #8440bf;
  color: var(--canvas);
}

.content-v3-type[data-content-type="endingSong"] {
  background: #ff8a3d;
  box-shadow: 0 4px 0 #ce6422;
  color: var(--canvas);
}

.content-v3-calendar-shell {
  padding: 22px;
  overflow-x: auto;
  background: var(--canvas);
  border: 2px solid #d9eefc;
  border-radius: 30px;
  box-shadow:
    0 10px 0 #c5e6fa,
    0 28px 44px rgba(20, 83, 163, 0.12);
}

.content-v3-weekdays,
.content-v3-calendar {
  display: grid;
  min-width: 960px;
  grid-template-columns: repeat(5, minmax(150px, 1fr));
  gap: 14px;
}

.content-v3-weekdays {
  margin-bottom: 14px;
}

.content-v3-weekdays span {
  display: grid;
  min-height: 46px;
  place-items: center;
  background: #e9f7ff;
  border-radius: 18px;
  box-shadow: inset 0 -3px 0 rgba(25, 153, 214, 0.15);
  color: var(--deep-blue);
  font-family: var(--font-google-sans);
  font-size: 16px;
  font-weight: 900;
  letter-spacing: 0;
  text-transform: uppercase;
}

.content-v3-day-cell {
  position: relative;
  display: grid;
  min-height: 142px;
  align-content: space-between;
  gap: 12px;
  padding: 17px;
  border: 0;
  border-radius: 24px;
  background: #f7fbff;
  box-shadow:
    inset 0 -2px 0 rgba(255, 255, 255, 0.42),
    0 8px 0 #d2e8f5,
    0 16px 24px rgba(20, 83, 163, 0.12);
  color: var(--ink);
  cursor: pointer;
  font-family: var(--font-google-sans);
  text-align: left;
  transition:
    box-shadow 160ms ease,
    filter 160ms ease,
    transform 160ms ease;
}

.content-v3-day-cell::before {
  position: absolute;
  inset: 3px 3px auto;
  height: 38%;
  border-radius: 21px 21px 16px 16px;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.34),
    rgba(255, 255, 255, 0)
  );
  content: "";
  pointer-events: none;
}

.content-v3-day-name {
  position: relative;
  z-index: 1;
  display: grid;
  width: 62px;
  height: 42px;
  place-items: center;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 15px;
  box-shadow: inset 0 -3px 0 rgba(12, 31, 56, 0.12);
  color: var(--deep-blue);
  font-size: 20px;
  font-weight: 900;
  line-height: 1;
  text-transform: uppercase;
}

.content-v3-chip {
  position: relative;
  z-index: 1;
  display: inline-flex;
  width: fit-content;
  max-width: 100%;
  align-items: center;
  gap: 7px;
  padding: 9px 11px;
  background: rgba(255, 255, 255, 0.86);
  border-radius: 999px;
  box-shadow: inset 0 -2px 0 rgba(12, 31, 56, 0.1);
  color: var(--deep-blue);
  font-size: 13px;
  font-weight: 900;
  line-height: 1;
}

.content-v3-chip span {
  display: grid;
  width: 22px;
  height: 22px;
  place-items: center;
  background: var(--canvas);
  border-radius: 50%;
  line-height: 1;
}

.content-v3-play {
  position: absolute;
  top: 14px;
  right: 14px;
  display: grid;
  width: 38px;
  height: 38px;
  place-items: center;
  background: rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  box-shadow: 0 4px 0 rgba(12, 31, 56, 0.14);
  color: var(--deep-blue);
  font-size: 13px;
  line-height: 1;
}

.content-v3-day-cell small {
  position: relative;
  z-index: 1;
  color: rgba(60, 60, 60, 0.64);
  font-size: 12px;
  font-weight: 900;
  line-height: 1;
}

.content-v3-day-cell.type-openingSong {
  background: linear-gradient(180deg, #ff7d97, #ff5f80);
  box-shadow:
    inset 0 -2px 0 rgba(255, 255, 255, 0.32),
    0 8px 0 #d83e5a,
    0 16px 24px rgba(216, 62, 90, 0.2);
  color: var(--canvas);
}

.content-v3-day-cell.type-story {
  background: linear-gradient(180deg, #35bcff, #159ee9);
  box-shadow:
    inset 0 -2px 0 rgba(255, 255, 255, 0.32),
    0 8px 0 #168cc5,
    0 16px 24px rgba(22, 140, 197, 0.2);
  color: var(--canvas);
}

.content-v3-day-cell.type-wordChant {
  background: linear-gradient(180deg, #37e2b2, #10c997);
  box-shadow:
    inset 0 -2px 0 rgba(255, 255, 255, 0.32),
    0 8px 0 #05a77d,
    0 16px 24px rgba(5, 167, 125, 0.18);
  color: #123f36;
}

.content-v3-day-cell.type-sentenceChant {
  background: linear-gradient(180deg, #c978ff, #ad55ee);
  box-shadow:
    inset 0 -2px 0 rgba(255, 255, 255, 0.32),
    0 8px 0 #8440bf,
    0 16px 24px rgba(132, 64, 191, 0.2);
  color: var(--canvas);
}

.content-v3-day-cell.type-endingSong {
  background: linear-gradient(180deg, #ffa861, #ff8738);
  box-shadow:
    inset 0 -2px 0 rgba(255, 255, 255, 0.32),
    0 8px 0 #ce6422,
    0 16px 24px rgba(206, 100, 34, 0.2);
  color: var(--canvas);
}

.content-v3-day-cell.type-openingSong small,
.content-v3-day-cell.type-story small,
.content-v3-day-cell.type-sentenceChant small,
.content-v3-day-cell.type-endingSong small {
  color: rgba(255, 255, 255, 0.78);
}

@media (hover: hover) {
  .brand:hover:not(:active) {
    transform: translateY(-1px);
  }

  .top-nav-link:hover:not(:active) {
    transform: translateY(-1px);
  }

  .top-nav-link:hover:not(:active) .nav-book {
    filter: brightness(1.05);
    transform: translateY(-2px);
  }

  .login-button:hover:not(:active) {
    color: var(--deep-blue);
    transform: translateY(-1px);
  }

  .level-button:hover:not(:active),
  .month-button:hover:not(:active),
  .content-type:hover:not(:active),
  .lesson-button:hover:not(:active),
  .back-button:hover:not(:active),
  .app-download-button:hover:not(:active) {
    filter: brightness(1.08);
    transform: translateY(-2px);
  }

  .content-type.active:hover:not(:active) {
    filter: brightness(1.06);
  }

  .content-v2-tab:hover:not(:active),
  .content-v2-day-button:hover:not(:active) {
    filter: brightness(1.05);
    transform: translateY(-2px);
  }

  .content-v3-type:hover:not(:active),
  .content-v3-day-cell:hover:not(:active) {
    filter: brightness(1.05);
    transform: translateY(-3px);
  }
}

@media (min-width: 530px) {
  .section-inner {
    padding-right: 30px;
    padding-left: 30px;
  }

  .level-grid,
  .month-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .content-toolbar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  #contentScreen .content-toolbar {
    grid-template-columns: minmax(112px, 150px) 82px repeat(
        5,
        minmax(86px, 1fr)
      );
  }
}

@media (min-width: 768px) {
  .topbar {
    padding-right: max(10%, calc((100% - var(--site-max-width)) / 2));
    padding-left: max(10%, calc((100% - var(--site-max-width)) / 2));
  }

  main {
    min-height: 0;
  }

  .section-inner {
    padding: 84px 60px;
  }

  .hero-section .section-inner {
    height: var(--hero-height);
    min-height: 0;
    padding-top: 0;
    padding-bottom: 0;
  }

  .hero-grid {
    grid-template-columns: minmax(0, 0.92fr) minmax(360px, 0.8fr);
    gap: clamp(72px, 9vw, 150px);
  }

  .hero-stage {
    grid-column: 2;
    grid-row: 1;
  }

  .hero-copy {
    grid-column: 1;
    grid-row: 1;
  }

  .level-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 28px;
  }

  .overview-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .month-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  #monthScreen .month-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
  }

  #contentScreen .content-main-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
  }

  #contentScreen .section-inner {
    width: 100%;
    padding: 84px clamp(106px, calc(6vw + 50px), 146px) 96px;
  }

  .content-toolbar {
    grid-template-columns: minmax(112px, 150px) 82px repeat(
        5,
        minmax(86px, 1fr)
      );
  }

  .lesson-board {
    padding: 50px;
  }

  /* All content pages: halve the board's top padding (50->25) so the weekday
     group sits closer to the toolbar (paired with the toolbar rule above). */
  #contentScreen .lesson-board {
    padding-top: 25px;
  }

  .lesson-button {
    min-height: 86px;
  }
}

@media (min-width: 768px) and (max-width: 1180px) {
  .topbar {
    min-height: 86px;
    flex-wrap: nowrap;
    padding-right: 38px;
    padding-left: 38px;
  }

  .brand {
    max-width: 340px;
  }

  .brand-name {
    font-size: 24px;
    overflow-wrap: break-word;
    line-height: 1.05;
  }

  .top-nav {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    gap: 18px;
  }

  .top-nav-link {
    width: 50px;
    min-width: 50px;
    min-height: 54px;
  }

  .nav-book {
    width: 50px;
    height: 36px;
    border-radius: 17px;
  }

  .nav-book-number {
    font-size: 20px;
  }

  .login-button {
    margin-left: auto;
  }

  /* Hero: the desktop 360px image column + huge gap squeezes the copy on
     tablet landscape (text wraps tall and the buttons sink into the wave).
     Give the copy more room, shrink the gap, and push the image to the right
     edge of its cell. */
  .hero-grid {
    grid-template-columns: minmax(0, 1.1fr) minmax(280px, 0.72fr);
    gap: clamp(28px, 4vw, 60px);
  }

  .hero-copy {
    padding-bottom: 92px;
  }

  .hero-stage {
    place-items: center end;
  }

  .hero-rig {
    width: min(330px, 100%);
  }
}

@media (min-width: 768px) and (max-width: 960px) {
  .topbar {
    padding-right: 34px;
    padding-left: 34px;
  }

  .brand {
    max-width: 285px;
  }

  .brand-name {
    font-size: 21px;
  }

  .top-nav {
    left: 52%;
    gap: 14px;
  }

  .login-button {
    width: 44px;
    height: 44px;
  }
}

/* Tablet month page (iPad / Galaxy Tab, both orientations): full-width, square
   (1:1) buttons whose number + month label scale with the button size, so they
   read consistently across sizes. Was a fixed 137px height with widely varying
   widths (e.g. 78px on iPad portrait, where the month name overflowed). */
@media (min-width: 768px) and (max-width: 1180px) {
  #monthScreen .section-inner {
    width: 100%;
    padding-right: 16px;
    padding-left: 16px;
  }

  .month-grid {
    align-items: start;
  }

  /* Match the PC month-button proportion: same fixed height (137px) with a
     full-width row, so the width (and thus the ratio) tracks PC instead of the
     square (1:1) that looked too tall on tablets. */
  #monthScreen[class*="level-theme-"] .month-button {
    min-height: 137px;
    aspect-ratio: auto;
  }

  .month-button strong {
    font-size: clamp(40px, 7vw, 92px);
  }

  #monthScreen[class*="level-theme-"] .month-button span {
    top: clamp(12px, 1.8vw, 26px);
    left: clamp(12px, 1.6vw, 20px);
    font-size: clamp(13px, 1.6vw, 21px);
  }
}

/* Short landscape tablets (iPad / Galaxy Tab landscape, ~712–820px tall): the
   desktop's 84–96px section padding + banner/toolbar margins push the month grid
   and the weekday board past the fold. Trim the vertical whitespace so the whole
   page (header→footer) and all four week rows fit without a vertical scrollbar.
   iPad Pro 12.9 (1366 wide) uses the desktop layout (>1180) and already fits. */
@media (min-width: 768px) and (max-width: 1180px) and (orientation: landscape) {
  /* Shorter footer (was 44px top/bottom padding = ~106px tall) reclaims room on
     both the month and content pages. */
  .site-footer {
    padding-top: 16px;
    padding-bottom: 16px;
  }

  #monthScreen .section-inner {
    padding-top: 24px;
    padding-bottom: 24px;
  }

  #contentScreen .section-inner {
    padding-top: 16px;
    padding-bottom: 18px;
  }

  /* Fill the tinted section down to the footer (no white band). Same fix as the
     month page: the base min-height uses calc(100vh - 185px), but THIS block trims
     the footer to ~50px and the header is ~86px → 185 over-subtracts ~49px. */
  #contentScreen.screen-active {
    min-height: calc(100vh - 136px);
  }

  /* Banner on TWO rows (was a single row to save height): row 1 = level name (left)
     + month circle (right), row 2 = the book band centered below. Keeps "Level 1"
     on its own top line with the month badge beside it. The circle is shrunk so the
     extra row doesn't push the 4-week board past the fold on the short Galaxy Tab. */
  #contentScreen .content-level-banner {
    grid-auto-flow: row;
    grid-template-columns: auto auto;
    align-items: center;
    justify-content: center;
    column-gap: 12px;
    row-gap: 2px;
    margin-bottom: 8px;
  }

  #contentLevelName {
    grid-column: 1;
    grid-row: 1;
  }

  #contentScreen .content-banner-month {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
  }

  #contentLevelBand {
    grid-column: 1 / -1;
    grid-row: 2;
  }

  #contentScreen .content-banner-month strong {
    width: 46px;
    height: 46px;
    font-size: 28px;
  }

  #contentScreen .content-main-header {
    margin-bottom: 6px;
  }

  #contentScreen .content-toolbar {
    margin-bottom: 6px;
    padding-bottom: 4px;
  }

  #contentScreen .lesson-board {
    padding-top: 6px;
    padding-bottom: 10px;
  }

  /* Slightly shorter weekday buttons + week labels so all four week rows clear
     the fold. (The week-label's 86px min-height was the actual row-height driver,
     spanning into the book cover's 2-row height.) */
  .lesson-button {
    min-height: 64px;
  }

  #contentScreen .week-label {
    min-height: 64px;
  }

  /* Month page — (A) fill the tinted section down to the footer (no white gap).
     The base min-height uses calc(100vh - 185px), but THIS block trims the footer
     to 16px padding (~50px tall) and the header is ~86px, so 185 over-subtracts by
     ~49px → a white band shows between the section and the footer. Correct it to
     the real header(86)+footer(50)=136, and flex the inner box so the month grid
     sits vertically centered in the filled section. */
  #monthScreen[class*="level-theme-"].screen-active {
    min-height: calc(100vh - 136px);
    display: flex;
  }

  #monthScreen[class*="level-theme-"] .section-box.section-white {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  /* (B) Uniform button size across devices. Buttons are 1fr of --content-width
     (min(80%,…)), so a wider tablet (Galaxy Tab 1138) gets bigger buttons than a
     narrower one (iPad 1024). Cap + center the grid so 5 columns yield ~150px
     squares on both. */
  #monthScreen .month-grid {
    max-width: none;
    margin-inline: auto;
  }

  /* The grid cap above fixes the button at ~135px, but the number/label fonts
     still use vw (7vw / 1.6vw = viewport-relative). At 1138px the number swells
     to ~80px and overlaps the absolutely-positioned top-left month label. The
     button no longer scales with the viewport, so size the fonts to the capped
     button with constants instead. */
  #monthScreen[class*="level-theme-"] .month-button strong {
    font-size: 52px;
  }

  #monthScreen[class*="level-theme-"] .month-button span {
    top: 16px;
    left: 16px;
    font-size: 14px;
  }

  /* Toolbar pills (Opening/Ending Song, Word/Sentence Game): on PC they sit at
     ~55% of the content width, but on the narrower tablet the fixed PC size made
     them fill ~78% and look oversized next to the (scaled-down) weekday board.
     Scale font/icon/height down roughly in proportion to the viewport (~ width
     /1440) so their size relative to the page matches PC. */
  #contentScreen .content-type {
    min-height: 42px;
    padding: 0 10px;
    gap: 6px;
    font-size: clamp(12px, 1.2vw, 14px);
    /* Scale the radius + 3D bevel down with the shorter button so it stays a
       clean rounded rectangle (the full-pill radius made the bevel shadow wrap
       the curved bottom and look distorted). */
    border-radius: 16px;
    box-shadow: 0 4px 0 #d8d8d8;
  }

  #contentScreen .content-type.active {
    box-shadow: 0 4px 0 #d8d8d8;
  }

  #contentScreen .content-type-icon {
    width: 20px;
    height: 20px;
    font-size: 12px;
  }

  #contentScreen .content-toolbar {
    /* (2) Align the 4 pills to the weekday grid: Opening Song's left edge = the
       Monday column's left, Sentence Game's right edge = the Friday column's
       right, with equal gaps between (space-between). The left offset matches the
       board's left pad + cover col + week-label col + their gaps (30+150+16+60+16
       = 272); the right inset matches the board's right pad (30). */
    justify-content: space-between;
    padding-left: 272px;
    padding-right: 30px;
    margin-top: 36px;
    /* (1) breathing room above the weekday board, within the spare space (kept
       small enough that the shortest tablet — Galaxy Tab — still doesn't scroll). */
    margin-bottom: 16px;
  }
}

/* PC (>=1250px, where the base weekday grid applies): align the 4 toolbar pills
   to the weekday grid like the tablet rule above. Left offset = board pad(50) +
   cover + week-label + gaps (= 342); right inset = board pad(50). No vertical
   gap is added here because PC page2 is already at/near full height. */
@media (min-width: 1250px) {
  #contentScreen .content-toolbar {
    justify-content: space-between;
    padding-left: 342px;
    padding-right: 50px;
  }
}

/* Tablet landscape (and iPad portrait): the weekday board's 900px min-width +
   the desktop's large content padding overflow the viewport, leaving a
   horizontal scrollbar inside .lesson-board so Thu/Fri get cut off. Drop the
   min-width floor, tighten the grid (smaller gap + column mins), and trim the
   content padding so all five weekday columns fit with no horizontal scroll.
   Handed off to the base desktop layout at >=1250px, where it fits natively. */
@media (min-width: 768px) and (max-width: 1249px) {
  #contentScreen .section-inner {
    padding-right: clamp(28px, 4vw, 64px);
    padding-left: clamp(28px, 4vw, 64px);
  }

  .lesson-board {
    padding: 30px;
    overflow-x: visible;
  }

  .lesson-grid {
    min-width: 0;
    grid-template-columns: minmax(72px, 150px) 60px repeat(5, minmax(54px, 1fr));
    gap: 16px;
  }

  .book-title-card {
    min-height: 0;
  }
}

/* Tablet (e.g. iPad 1024 landscape): the 4-up level cards were taller than
   wide. Make them square (aspect-ratio 1:1) — min-height:auto lets a card still
   grow if its band text needs more than the square height, so nothing clips.
   Lower bound is 900px (not 768): below that the 4 columns get too narrow and
   the "Level N" wordmark would crowd, so narrow tablets keep the taller card. */
@media (min-width: 900px) and (max-width: 1180px) {
  /* Full width gives the 4 cards more room so a square is roomy (not cramped). */
  .level-section .section-inner {
    width: 100%;
  }

  /* Stop the cards stretching to the tallest one's height — otherwise the row
     stretch overrides aspect-ratio. */
  .level-grid {
    align-items: start;
  }

  .level-button {
    min-height: 0;
    aspect-ratio: 1 / 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Text entrance animations still respect reduced-motion. The hero character
     rig (float + arm/head sway) is intentionally exempt — per request it should
     animate regardless of the OS "reduce motion" setting. */
  .hero-copy .eyebrow,
  .hero-copy p,
  .app-downloads {
    animation: none;
  }

  /* The hero title's word-by-word reveal is intentionally exempt (like the
     character rig) — per request it should play regardless of "reduce motion".
     Leaving its animation on also keeps the words visible (opacity 0 -> 1). */
}

@media (max-width: 1023px) {
  /* Tablet/mobile: move the level nav to its own centered row so the wider
     icons never collide with the brand logo. */
  .topbar {
    flex-wrap: wrap;
  }

  .top-nav {
    position: static;
    left: auto;
    order: 3;
    width: 100%;
    flex-basis: 100%;
    margin: 8px 0 0;
    transform: none;
    gap: 16px;
    justify-content: center;
  }
}

@media (max-width: 767px) {
  :root {
    --hero-height: 380px;
  }

  /* Compact mobile header: smaller logo, tighter logo->nav gap, less vertical
     padding so the header doesn't dominate the (especially landscape) screen. */
  .topbar {
    min-height: 0;
    flex-wrap: wrap;
    /* Tight row-gap: the base 16px gap created ~32px of dead space between the
       brand row, the (empty, on public pages) actions row, and the nav row. */
    gap: 2px;
    padding-right: 24px;
    padding-left: 24px;
    padding-top: 8px;
    padding-bottom: 8px;
  }

  /* Logo aligned left (both orientations); the actions cluster (login icon, or
     Admin/Log out when signed in) sits on the same row to its right. */
  .brand {
    width: auto;
    justify-content: flex-start;
  }

  .brand-name {
    width: auto;
    font-size: clamp(9px, 2.5vw, 12px);
    justify-content: flex-start;
    justify-items: start;
    line-height: 1.1;
    text-align: left;
  }

  /* The actual wordmark letters live in these two spans (fixed 33px by default);
     shrink them on mobile so the header can be shorter. The brand row height
     follows the letter size, so this also trims the header. */
  .brand-accent,
  .brand-adventures {
    font-size: clamp(17px, 5vw, 20px);
  }

  .top-nav {
    position: static;
    left: auto;
    order: 3;
    transform: none;
    width: 100vw;
    flex-basis: 100vw;
    margin-top: 0;
    margin-right: -24px;
    margin-left: -24px;
    gap: 12px;
    justify-content: center;
  }

  .top-nav-link {
    width: 46px;
    min-width: 46px;
    min-height: 48px;
  }

  .nav-book {
    width: 46px;
    height: 33px;
    border-radius: 16px;
  }

  .nav-book-number {
    font-size: 18px;
  }

  /* Header actions on mobile: a compact cluster on the right of the logo row.
     The login icon (signed out) and the Admin / Log out buttons (signed in) are
     all small CIRCULAR icon buttons sized to roughly the logo height. */
  .topbar-actions {
    gap: 8px;
  }

  .login-button {
    display: inline-grid;
    width: 34px;
    height: 34px;
    color: var(--ink);
  }

  .login-icon {
    width: 21px;
    height: 21px;
  }

  /* Plain line icons (no circular background) — simple and uncropped. The
     .topbar-actions prefix raises specificity above the base pill styles (which
     are declared later in the file). */
  .topbar-actions .admin-nav-button,
  .topbar-actions .admin-logout-button {
    width: auto;
    height: auto;
    padding: 5px;
    border-radius: 0;
    background: none;
    color: var(--ink);
    display: inline-grid;
    place-items: center;
  }

  .topbar-actions .admin-nav-button:hover,
  .topbar-actions .admin-logout-button:hover {
    background: none;
  }

  /* Match the login icon's footprint (21px) and shrink from the old 24px. */
  .admin-nav-button .action-icon,
  .admin-logout-button .action-icon {
    display: block;
    width: 21px;
    height: 21px;
  }

  /* The log-out glyph (door + arrow) fills its 24x24 viewBox almost edge to
     edge, while the key glyph is tall and narrow — so at an equal box the
     log-out reads noticeably bigger. Trim its box a touch so the two icons
     look the same size, keyed to the Admin (key) icon. */
  .admin-logout-button .action-icon {
    width: 18px;
    height: 18px;
  }

  .action-label {
    display: none;
  }

  /* Mobile hero: stack the copy, the two app buttons (side by side), then the
     character image below — all visible. The section grows to fit its content
     instead of being clamped to --hero-height (which clipped the hero). */
  .hero-section.section-blue,
  .hero-section .section-inner {
    height: auto;
    min-height: 0;
  }

  .hero-section .section-inner {
    width: 100%;
    padding: 12px 24px 12px;
  }

  .hero-grid {
    height: auto;
    gap: 14px;
  }

  .hero-copy {
    width: 100%;
    max-width: 100%;
    position: relative;
    z-index: 3;
    padding-top: 0;
    padding-bottom: 0;
  }

  .hero-copy h1,
  .hero-copy p {
    max-width: 100%;
    overflow-wrap: break-word;
  }

  /* Mobile portrait title 30% smaller (frees vertical space for a larger hero
     image). <=420px gets an even smaller size in its own block below. */
  .hero-copy h1 {
    font-size: 34px;
  }

  .hero-copy p {
    width: 100%;
  }

  /* Shorter wave on mobile so the in-flow image below the copy only tucks its
     base behind the white curve instead of being half-covered. */
  .hero-wave {
    height: 96px;
  }

  /* Keep the two store buttons on one row, sharing the width evenly. Shrink the
     icon + label so "Google Play" stays inside the button at 320px wide. */
  .app-downloads {
    flex-wrap: nowrap;
    gap: 10px;
    margin-top: 22px;
  }

  .app-download-button {
    width: auto;
    min-width: 0;
    flex: 1 1 0;
    gap: 6px;
    padding: 0 8px;
  }

  .app-download-icon {
    width: 20px;
    height: 20px;
  }

  .app-download-button small {
    font-size: 9px;
  }

  .app-download-button strong {
    font-size: 12px;
  }

  /* Full viewport width (default was 80%, which left big margins and made the
     2-up level cards narrow + tall). Full width + a tighter gap widens them. */
  .level-section .section-inner {
    width: 100%;
    padding-right: 18px;
    padding-left: 18px;
  }

  .level-grid {
    gap: 14px;
  }

  /* Two-up level cards: wider (full-width section) + a shorter height so they
     read as cards, not tall pills. */
  .level-button {
    min-height: 0;
    padding: 12px;
    border-radius: 28px;
    /* Match the tablet/PC 6:4 ratio: 2-up width drives the height, which keeps
       the 2x2 group shorter so it can center between hero and footer. */
    aspect-ratio: 6 / 4;
  }

  .level-button strong {
    white-space: nowrap;
    font-size: clamp(20px, 5.5vw, 30px);
  }

  .level-button small {
    font-size: 12px;
    line-height: 1.2;
  }

  /* Month screen: use the full viewport width (the default 80% content width
     left big side margins, squeezing the buttons tall and wrapping the title).
     Full width gives the 2-up buttons a wider, less stretched aspect. */
  #monthScreen .section-inner {
    width: 100%;
    padding-right: 18px;
    padding-left: 18px;
  }

  /* Two-up month buttons: full cell width + a shorter, wider aspect. */
  .month-button {
    width: 100%;
    min-height: 84px;
    padding: 14px 16px;
  }

  .month-button strong {
    font-size: 40px;
  }

  .hero-stage {
    position: static;
    right: auto;
    bottom: auto;
    z-index: 1;
    width: 100%;
    height: auto;
    min-height: 0;
    place-items: center;
    pointer-events: auto;
  }

  .hero-rig {
    width: min(185px, 50%);
    max-height: none;
    margin: 0;
    opacity: 1;
  }

  .hero-rig .hero-image {
    max-height: none;
  }

  #contentScreen .section-inner {
    padding-right: 16px;
    padding-left: 16px;
  }

  /* Opening / Ending Song buttons. Base mobile = horizontal; portrait stacks
     them vertically (see the orientation:portrait block). NOTE: a leftover
     duplicate rule used to re-shrink these to 10px/18px here — removed, so the
     label + icon read at a proper size. */
  #contentScreen .content-toolbar {
    min-width: 0;
    gap: 10px;
    margin-bottom: 14px;
    padding: 4px 6px 8px;
    overflow-x: visible;
  }

  #contentScreen .content-type {
    flex: 1 1 0;
    max-width: 240px;
    min-height: 56px;
    gap: 8px;
    padding: 0 14px;
    font-size: 15px;
  }

  #contentScreen .content-type-icon {
    width: 24px;
    height: 24px;
    font-size: 14px;
  }

  /* Mobile weekday board: a 6-column grid (week label + Mon–Fri) with each
     book cover promoted to its own full-width row above its two weeks. This
     drops the wide book-card column that forced a horizontal scrollbar, so all
     five weekdays fit on screen with no horizontal scroll and the day text
     scales to the button. */
  #contentScreen .lesson-board {
    padding: 10px;
    overflow-x: visible;
  }

  #contentScreen .lesson-grid {
    min-width: 0;
    /* Cap + center the board so the weekday buttons stay phone-sized on wide
       (landscape) screens instead of ballooning to fill 5 stretched columns.
       Below ~430px the board just shrinks to fit, so portrait is unchanged.
       The week column widens a touch (clamp) for the "N week" label. */
    max-width: 430px;
    margin-inline: auto;
    /* Week column is just the number on mobile (the "week" word is hidden
       below), so it can be narrow — that frees width for bigger day buttons. */
    grid-template-columns: clamp(24px, 6.5vw, 34px) repeat(5, minmax(0, 1fr));
    /* Keep columns tight (5 days must fit) but space the week rows apart so
       week 1 and week 2 don't butt together. */
    column-gap: 6px;
    row-gap: 14px;
  }

  /* Book cover sits on its own full-width row, but the CARD itself is sized to
     the cover (centered, PC card aspect) — not stretched full width — so the
     rounded cover and its white outline match the PC look instead of floating
     in an oversized white box. margin-top adds breathing room so book 2 doesn't
     butt up against the week-2 button row above it. */
  #contentScreen .book-title-card {
    grid-column: 1 / -1;
    grid-row: auto;
    justify-self: center;
    width: min(150px, 46%);
    min-height: 0;
    aspect-ratio: 150 / 202;
    /* Extra space above each cover (on top of the grid row-gap) so book 2 has
       clear breathing room from the week-2 row above it. */
    margin-top: 16px;
    margin-bottom: 6px;
    border-radius: 22px;
  }

  /* has-cover keeps the base rule (background-size:cover + rounded + 3px white
     outline), so no override needed here — it now renders like the PC card. */

  #contentScreen .week-label {
    min-height: 0;
    padding: 2px;
    border-radius: 14px;
    font-size: clamp(14px, 3.6vw, 18px);
    line-height: 1.1;
    text-align: center;
  }

  /* Show only the week number on mobile (e.g. "1" instead of "1 week"). */
  #contentScreen .week-label .wk-word {
    display: none;
  }

  /* Square (1:1) weekday buttons instead of tall pills. */
  #contentScreen .lesson-button {
    min-height: 0;
    aspect-ratio: 1 / 1;
    border-radius: 16px;
    padding: 4px 2px;
  }

  #contentScreen .lesson-button strong {
    font-size: clamp(13px, 3.8vw, 19px);
  }

  .content-v2-inner {
    padding: 54px 24px 64px;
  }

  .content-v2-header {
    align-items: flex-start;
    margin-bottom: 24px;
  }

  .content-v2-tabs,
  .content-v2-grid {
    grid-template-columns: minmax(62px, 0.9fr) 56px repeat(5, minmax(42px, 1fr));
    gap: 8px;
  }

  .content-v2-tabs {
    padding: 0 12px;
  }

  .content-v2-tab {
    min-height: 44px;
    gap: 4px;
    padding-right: 4px;
    padding-left: 4px;
    font-size: 10px;
  }

  .content-v2-tab-icon {
    width: 18px;
    height: 18px;
    font-size: 11px;
  }

  .content-v2-board {
    padding: 12px;
  }

  .content-v2-grid {
    min-width: 0;
  }

  .content-v2-book-card {
    min-height: 148px;
    font-size: 10px;
  }

  .content-v2-book-icon {
    width: 28px;
    height: 36px;
  }

  .content-v2-week-label {
    min-height: 68px;
  }

  .content-v2-week-label span {
    font-size: 15px;
  }

  .content-v2-week-label strong {
    font-size: 8px;
  }

  .content-v2-day-button {
    min-height: 68px;
    border-radius: 16px;
  }

  .content-v2-day-button strong {
    font-size: 13px;
  }

  .content-v3-section {
    background: linear-gradient(180deg, #2b70c9 0 330px, #f4fbff 330px 100%);
  }

  .content-v3-inner {
    padding: 42px 18px 58px;
  }

  .content-v3-hero {
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 20px;
  }

  .content-v3-kicker {
    min-height: 30px;
    font-size: 12px;
  }

  .content-v3-title-row {
    flex-wrap: wrap;
  }

  .content-v3-month-badge,
  .content-v3-level {
    min-height: 34px;
    padding: 7px 11px;
    font-size: 12px;
  }

  .content-v3-title-block h2 {
    font-size: 32px;
    line-height: 1.03;
  }

  .content-v3-title-block p {
    display: none;
  }

  .content-v3-back {
    min-height: 46px;
    margin-top: 0;
    padding-right: 14px;
    padding-left: 14px;
  }

  .content-v3-typebar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    padding: 12px;
    border-radius: 22px;
  }

  .content-v3-type {
    min-height: 50px;
    gap: 6px;
    padding-right: 8px;
    padding-left: 8px;
    font-size: 12px;
  }

  .content-v3-type:last-child {
    grid-column: 1 / -1;
  }

  .content-v3-type-icon {
    width: 24px;
    height: 24px;
    font-size: 12px;
  }

  .content-v3-calendar-shell {
    padding: 12px;
    border-radius: 24px;
  }

  .content-v3-weekdays,
  .content-v3-calendar {
    min-width: 720px;
    grid-template-columns: repeat(5, minmax(132px, 1fr));
    gap: 10px;
  }

  .content-v3-weekdays span {
    min-height: 38px;
    border-radius: 13px;
    font-size: 13px;
  }

  .content-v3-day-cell {
    min-height: 118px;
    padding: 13px;
    border-radius: 18px;
  }

  .content-v3-day-name {
    width: 50px;
    height: 34px;
    border-radius: 12px;
    font-size: 16px;
  }

  .content-v3-chip {
    padding: 7px 9px;
    font-size: 12px;
  }

  .content-v3-play {
    width: 31px;
    height: 31px;
    top: 12px;
    right: 12px;
  }
}

@media (max-width: 420px) {
  :root {
    --hero-height: 340px;
  }

  .topbar {
    padding-right: 18px;
    padding-left: 18px;
  }

  .level-section .section-inner {
    padding-right: 18px;
    padding-left: 18px;
  }

  .top-nav {
    margin-right: -18px;
    margin-left: -18px;
  }

  .brand-name {
    width: 100%;
    /* ~50% of the previous size per request. */
    font-size: clamp(10px, 3vw, 13px);
    line-height: 1.12;
  }

  h1 {
    font-size: 36px;
  }

  .hero-copy h1 {
    font-size: 29px;
    line-height: 1.04;
  }

  h2 {
    font-size: 30px;
  }

  p {
    font-size: 16px;
  }

  .screen-heading {
    flex-direction: column;
  }

  .lesson-board {
    padding: 8px;
  }

  .lesson-grid {
    gap: 5px;
  }

  .lesson-button {
    min-height: 68px;
  }
}

/* Landscape phones (short + wide): put the logo and the level nav on ONE row
   (logo left, nav right) instead of stacking them, to reclaim vertical space.
   Large-phone landscapes (>=768px) already get the horizontal tablet header. */
@media (max-width: 767px) and (orientation: portrait) {
  /* Header row 1 = logo (left) + actions (right); the level nav drops to its
     own centered row below (from the base rules). This keeps the header short. */
  .topbar-actions {
    order: 1;
    margin-left: auto;
  }

  /* Slightly larger logo. The header row 1 height is set by the 34px action
     icons (login / admin / log out), and the logo stays well under that, so the
     header height and the right-side icons are unaffected. */
  .brand-accent,
  .brand-adventures {
    font-size: clamp(22px, 6.5vw, 26px);
  }

  /* Month buttons square (1:1): keep the current width, drop the 137px height
     floor and let aspect-ratio set the height from the column width. (Matches
     the level-theme rule's specificity so it actually wins.) */
  #monthScreen[class*="level-theme-"] .month-button {
    min-height: 0;
    aspect-ratio: 1 / 1;
  }

  /* Stack Opening Song (top) / Ending Song (bottom) vertically; with the row no
     longer shared, the buttons can be larger. */
  #contentScreen .content-toolbar {
    flex-direction: column;
    align-items: center;
    gap: 12px;
  }

  #contentScreen .content-type {
    flex: 0 0 auto;
    width: 100%;
    /* ~60% of the previous width (was 272). Label + icon trimmed a touch so the
       text stays inside the narrower button. */
    max-width: 164px;
    min-height: 64px;
    gap: 6px;
    padding: 0 10px;
    font-size: 15px;
  }

  #contentScreen .content-type-icon {
    width: 22px;
    height: 22px;
    font-size: 13px;
  }

  /* Month nav (Back / Next) ~80% of the base size — the default 50px/15px
     buttons felt too big at the top of the portrait content page. */
  #contentScreen .content-nav-prev,
  #contentScreen .content-nav-next {
    min-height: 40px;
    padding: 0 14px;
    box-shadow: 0 3px 0 #d8d8d8;
    font-size: 12px;
  }
}

/* Small portrait tablets (Galaxy Tab S4 712, Tab S7 753, … widths 600–767px).
   Below 768px they miss the tablet block and fall into the phone 2-column path,
   so the month buttons balloon to ~330px squares. Pull the iPad (>=768) tablet
   month layout (5-column compact squares) down to this range. Phones (<600px
   portrait) keep 2 columns; landscape is unaffected. Placed after the
   max-width:767px portrait block so it wins by source order at equal specificity. */
@media (min-width: 600px) and (max-width: 767px) and (orientation: portrait) {
  #monthScreen .month-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    align-items: start; /* else the default row stretch overrides aspect-ratio */
  }

  /* aspect-ratio:1/1 already applied by the portrait block above (keeps squares).
     Scale the number + label to the smaller cells — same vw clamps as the tablet
     block so it visually matches the iPad. */
  .month-button strong {
    font-size: clamp(40px, 7vw, 92px);
  }

  #monthScreen[class*="level-theme-"] .month-button span {
    top: clamp(12px, 1.8vw, 26px);
    left: clamp(12px, 1.6vw, 20px);
    font-size: clamp(13px, 1.6vw, 21px);
  }
}

@media (max-width: 767px) and (orientation: landscape) {
  .topbar {
    flex-wrap: nowrap;
    gap: 12px;
    min-height: 0;
    align-items: center;
    padding-top: 5px;
    padding-bottom: 5px;
  }

  .brand {
    width: auto;
  }

  .brand-name {
    width: auto;
    font-size: clamp(11px, 1.9vw, 14px);
    text-align: left;
  }

  /* Single-row header: logo (left) · level nav (center) · actions (right). */
  .top-nav {
    position: static;
    left: auto;
    order: 1;
    flex: 1 1 auto;
    transform: none;
    width: auto;
    flex-basis: auto;
    margin: 0;
    gap: 10px;
    justify-content: center;
  }

  .topbar-actions {
    order: 2;
  }

  .top-nav-link {
    width: 44px;
    min-width: 44px;
    min-height: 44px;
  }

  .nav-book {
    width: 44px;
    height: 31px;
  }

  .nav-book-number {
    font-size: 18px;
  }

  /* Bigger song/day-button text + icon so they read in proportion to the
     buttons at landscape size. */
  #contentScreen .content-type {
    min-height: 52px;
    font-size: 16px;
  }

  #contentScreen .content-type-icon {
    width: 26px;
    height: 26px;
    font-size: 15px;
  }

  #contentScreen .lesson-button strong {
    font-size: 21px;
  }

  #contentScreen .week-label {
    font-size: 19px;
  }

  /* Landscape has horizontal room: lay the board out exactly like PC — book
     cover (left) · week label · Mon–Fri — the cover spanning its two week rows.
     Uncaps the board (portrait keeps the capped, cover-stacked layout). */
  #contentScreen .lesson-grid {
    max-width: none;
    margin-inline: 0;
    grid-template-columns:
      clamp(96px, 16vw, 132px) clamp(28px, 5vw, 40px)
      repeat(5, minmax(0, 1fr));
    column-gap: 8px;
  }

  /* Book cover back in column 1, spanning its two week rows (auto-placed like
     PC — override the portrait full-width-row placement). */
  #contentScreen .book-title-card {
    grid-column: auto;
    grid-row: span 2;
    justify-self: stretch;
    align-self: stretch;
    width: 100%;
    min-height: 0;
    aspect-ratio: auto;
    margin: 0;
  }

  /* Month buttons: ~60% of their portrait size. Use fixed-width columns centered
     as a group (instead of width:60% inside full 1fr cells) so the two buttons
     sit close together rather than spread far apart. The height floor comes from
     the higher-specificity level-theme rule (min-height:137px), so the override
     must match that specificity to take effect. */
  #monthScreen .month-grid {
    grid-template-columns: repeat(2, 180px);
    justify-content: center;
    column-gap: 18px;
  }

  .month-button {
    width: 100%;
    padding: 8px 12px;
  }

  #monthScreen[class*="level-theme-"] .month-button {
    min-height: 80px;
  }

  .month-button strong {
    font-size: 24px;
  }

  .month-button span {
    font-size: 11px;
  }
}

/* ----------------------------------------------------------------------
   Video player modal (Level 1 / March only)
   A custom shell matching the site's tactile design. The modal is opened
   from app.js only on the Level 1 / March content page; markup is shared
   but inert elsewhere. Controls (Play/Pause/Stop/Repeat/Maximize) +
   progress bar drive a Vimeo video via the Vimeo Player SDK. Themed off
   the active level via --level-accent (yellow on Level 1), with a
   macaw-blue fallback.
   ---------------------------------------------------------------------- */

.video-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.video-modal[hidden] {
  display: none;
}

body.video-open {
  overflow: hidden;
}

.video-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(28, 28, 28, 0.62);
  backdrop-filter: blur(2px);
  animation: vp-fade 0.18s ease both;
}

.video-player-card {
  position: relative;
  width: 50vw;
  max-width: 1100px;
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  padding: 16px;
  background: var(--canvas);
  border-radius: var(--radius-card);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
  animation: vp-pop 0.22s cubic-bezier(0.2, 0.9, 0.3, 1.2) both;
}

@keyframes vp-fade {
  from {
    opacity: 0;
  }
}

@keyframes vp-pop {
  from {
    opacity: 0;
    transform: scale(0.96);
  }
}

@media (prefers-reduced-motion: reduce) {
  .video-modal-overlay,
  .video-player-card {
    animation: none;
  }
}

/* Context title — what is playing (e.g. "Opening Song · Week 2 · Wed"), led by
   a small aqua accent dot to tie it to the player's controls. Hidden if empty. */
.vp-title {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 44px 10px 4px;
  font-family: "Readex Pro", var(--font-ui);
  font-size: 15px;
  font-weight: 600;
  color: #9a9a9a;
}

.vp-title::before {
  content: "";
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  background: var(--macaw-blue);
  border-radius: 50%;
}

.vp-title:empty {
  display: none;
}

/* Round "x" close button, top-right, slightly overlapping the card corner.
   Flat aqua (no border, no shadow); thick white "x". */
.vp-close {
  position: absolute;
  top: -16px;
  right: -16px;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  background: var(--macaw-blue);
  border: 0;
  border-radius: 50%;
  color: var(--canvas);
  cursor: pointer;
}

.vp-close svg {
  width: 24px;
  height: 24px;
}

.vp-close:hover {
  background: var(--macaw-blue-shadow);
}

/* 16:9 video stage. translateZ(0) promotes the stage to its own layer so the
   rounded corners actually clip the Vimeo iframe (Chrome won't clip a child
   iframe by an ancestor's border-radius otherwise). */
.vp-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  /* Soft dark-aqua wash instead of flat black, so the buffering state reads as
     "loading" rather than "broken"; the video covers it once it plays. */
  background: radial-gradient(circle at center, #15303d 0%, #000 75%);
  border-radius: 12px;
  overflow: hidden;
  transform: translateZ(0);
}

.vp-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* The iframe is SQUARE (no radius) and overscans the stage by 1px on every
   side, so the stage's rounded clip always cuts through solid video — never
   the dark stage background. (Rounding the iframe itself left a thin dark
   antialiased seam where the stage bg peeked through at the corners.) */
.vp-frame iframe {
  position: absolute;
  top: -1px;
  left: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  border: 0;
}

/* Transparent layer over the video to capture play/pause clicks (the
   cross-origin Vimeo iframe would otherwise swallow them). */
.vp-click-layer {
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}

/* End-of-video overlay — covers Vimeo's related-videos end screen with our own
   scene + a Replay button. Sits above the click layer; matches the stage wash. */
.vp-end-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  background: radial-gradient(circle at center, #15303d 0%, #000 80%);
}

.vp-end-overlay[hidden] {
  display: none;
}

.vp-replay {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 26px 14px 20px;
  background: var(--macaw-blue);
  border: 0;
  border-radius: 999px;
  color: var(--canvas);
  font-family: var(--font-ui);
  font-size: 17px;
  font-weight: 800;
  cursor: pointer;
  transition: background 0.12s ease;
}

.vp-replay svg {
  width: 26px;
  height: 26px;
}

.vp-replay:hover {
  background: var(--macaw-blue-shadow);
}

.vp-replay:focus-visible {
  outline: 3px solid var(--canvas);
  outline-offset: 3px;
}

/* Control bar — two tiers: full-width progress row on top, transport row below
   (so the seek bar stays usable, especially on mobile). */
.vp-controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 6px 4px;
}

.vp-progress-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Three zones: Repeat (left) · Play+Stop (center) · Maximize (right). */
.vp-transport {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

.vp-transport-left {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-self: start;
}

.vp-transport-center {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-self: center;
}

.vp-transport-right {
  justify-self: end;
}

/* Monospaced-feel time labels, fixed width so the bar doesn't jitter. */
.vp-time {
  flex: 0 0 auto;
  min-width: 40px;
  font-family: var(--font-nav);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #555555;
  text-align: center;
}

/* Flat aqua control buttons — no bevel, no drop shadow, white icons. */
.vp-btn {
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  flex: 0 0 auto;
  padding: 0;
  background: var(--macaw-blue);
  border: 0;
  border-radius: 50%;
  color: var(--canvas);
  cursor: pointer;
  transition: background 0.12s ease;
}

.vp-btn svg {
  width: 24px;
  height: 24px;
}

.vp-btn:hover {
  background: var(--macaw-blue-shadow);
}

/* Play/Pause is the primary action — make it a touch larger than the rest. */
.vp-toggle {
  width: 58px;
  height: 58px;
}

.vp-toggle svg {
  width: 28px;
  height: 28px;
}

/* Repeat button pressed/active state: filled deeper aqua. */
.vp-btn[aria-pressed="true"] {
  background: var(--deep-blue);
}

/* Play / Pause toggle: show the icon matching the current state. */
.vp-toggle .vp-icon-pause {
  display: none;
}

.vp-toggle[data-playing="true"] .vp-icon-play {
  display: none;
}

.vp-toggle[data-playing="true"] .vp-icon-pause {
  display: block;
}

/* Mute toggle: swap volume/muted icon, and show an active (deep-blue) state. */
.vp-mute .vp-icon-muted {
  display: none;
}

.vp-mute[data-muted="true"] .vp-icon-volume {
  display: none;
}

.vp-mute[data-muted="true"] .vp-icon-muted {
  display: block;
}

.vp-mute[data-muted="true"] {
  background: var(--deep-blue);
}

/* Inline volume control: mute button + a compact slider beside it. Reuses the
   progress bar's visual language (aqua fill + white thumb) at a smaller scale. */
.vp-volume {
  position: relative;
  display: flex;
  align-items: center;
}

/* The slider floats to the RIGHT of the sound icon and is revealed on
   hover/focus, so it neither sits permanently next to the progress bar nor
   overlaps it (floating above the icon overlapped the play bar). */
.vp-volume-slider {
  position: absolute;
  left: calc(100% + 12px);
  top: 50%;
  width: 116px;
  height: 13px;
  padding: 0;
  background: var(--hairline);
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  touch-action: none;
  opacity: 0;
  transform: translate(-6px, -50%);
  transform-origin: left center;
  pointer-events: none;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
  transition:
    opacity 0.14s ease,
    transform 0.14s ease;
  z-index: 4;
}

/* Invisible bridge over the gap so moving the pointer from the icon across to
   the floating slider doesn't drop the hover. */
.vp-volume-slider::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 100%;
  width: 16px;
}

.vp-volume:hover .vp-volume-slider,
.vp-volume:focus-within .vp-volume-slider {
  opacity: 1;
  transform: translate(0, -50%);
  pointer-events: auto;
}

/* Driven by the --vol custom property set in JS (reflectVolumeUI). Horizontal
   desktop slider: --vol -> fill width / thumb left. The vertical mobile popover
   remaps --vol to height / bottom (see the mobile-portrait block). */
.vp-volume-fill {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--vol, 100%);
  height: 100%;
  background: var(--macaw-blue);
  border-radius: 999px;
}

.vp-volume-thumb {
  position: absolute;
  top: 50%;
  left: var(--vol, 100%);
  width: 21px;
  height: 21px;
  transform: translate(-50%, -50%);
  background: var(--canvas);
  border: 5px solid var(--macaw-blue);
  border-radius: 50%;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  pointer-events: none;
  transition: transform 0.1s ease;
}

.vp-volume-slider:hover .vp-volume-thumb,
.vp-volume-slider.is-dragging .vp-volume-thumb {
  transform: translate(-50%, -50%) scale(1.15);
}

.vp-volume-slider:focus-visible {
  outline: 3px solid var(--deep-blue);
  outline-offset: 3px;
}

/* Narrow screens: hide the inline slider, keep just the mute toggle. */
@media (max-width: 560px) {
  .vp-volume-slider {
    display: none;
  }
}

/* Keyboard focus ring (buttons are shadowless flat aqua, so this matters). */
.vp-btn:focus-visible,
.vp-close:focus-visible,
.vp-progress:focus-visible {
  outline: 3px solid var(--deep-blue);
  outline-offset: 3px;
}

/* Progress bar: full-width track + aqua fill + draggable thumb. */
.vp-progress {
  position: relative;
  flex: 1 1 auto;
  height: 16px;
  min-width: 80px;
  padding: 0;
  background: var(--hairline);
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  touch-action: none;
}

/* Buffered (loaded) portion — a lighter aqua behind the played fill. */
.vp-progress-buffer {
  position: absolute;
  left: 0;
  top: 0;
  width: 0%;
  height: 100%;
  background: rgba(28, 176, 246, 0.32);
  border-radius: 999px;
}

.vp-progress-fill {
  position: absolute;
  left: 0;
  top: 0;
  width: 0%;
  height: 100%;
  background: var(--macaw-blue);
  border-radius: 999px;
}

.vp-progress-thumb {
  position: absolute;
  top: 50%;
  left: 0%;
  width: 20px;
  height: 20px;
  transform: translate(-50%, -50%);
  background: var(--canvas);
  border: 4px solid var(--macaw-blue);
  border-radius: 50%;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  pointer-events: none;
  transition: transform 0.1s ease;
}

.vp-progress:hover .vp-progress-thumb,
.vp-progress.is-dragging .vp-progress-thumb {
  transform: translate(-50%, -50%) scale(1.15);
}

/* Fullscreen: the card fills the screen and the video grows; the title and
   controls become YouTube-style auto-hiding overlays. Keyed on both the
   :fullscreen pseudo (real fullscreen) and a .vp-fullscreen class that app.js
   toggles on fullscreenchange (so the behaviour is testable). :is() parses
   forgivingly, so an unsupported :fullscreen never invalidates the rule. */
.video-player-card:is(:fullscreen, .vp-fullscreen) {
  width: 100vw;
  max-width: none;
  height: 100vh;
  max-height: none;
  justify-content: center;
  padding: 0;
  border-radius: 0;
  background: #000;
}

.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-stage {
  width: auto;
  height: 100%;
  max-width: 100vw;
  max-height: 100vh;
  aspect-ratio: 16 / 9;
  border-radius: 0;
}

/* Title overlays the top, controls overlay the bottom — each over a readability
   scrim — instead of sitting in flow above/below the video. */
.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-title {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  margin: 0;
  padding: 18px 24px;
  color: var(--canvas);
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), transparent);
  z-index: 5;
}

.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-controls {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 32px 24px 18px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.55), transparent);
  z-index: 5;
}

.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-time {
  color: rgba(255, 255, 255, 0.85);
}

.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-close {
  top: 18px;
  right: 18px;
  z-index: 6;
}

/* Auto-hide: the chrome fades out by default and is revealed on pointer/tap
   activity (app.js adds .vp-controls-visible, then removes it after a pause). */
.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-title,
.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-controls,
.video-player-card:is(:fullscreen, .vp-fullscreen) .vp-close {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

.video-player-card:is(:fullscreen, .vp-fullscreen).vp-controls-visible
  .vp-title,
.video-player-card:is(:fullscreen, .vp-fullscreen).vp-controls-visible
  .vp-controls,
.video-player-card:is(:fullscreen, .vp-fullscreen).vp-controls-visible
  .vp-close {
  opacity: 1;
  pointer-events: auto;
}

/* Hide the cursor too while the chrome is hidden. */
.video-player-card:is(:fullscreen, .vp-fullscreen):not(.vp-controls-visible) {
  cursor: none;
}

/* Narrow screens: honor a wider share of the viewport so the player stays
   usable (the 50vw spec is for typical desktop/tablet widths). */
@media (max-width: 760px) {
  .video-player-card {
    width: 92vw;
  }
}

/* Mobile portrait (windowed AND fullscreen). Touch has no hover, so the desktop
   hover-reveal volume popover never opens by tap. Two changes:
   (1) shrink the oversized control buttons to ~80% so they fit the small card;
   (2) turn the volume slider into a tap-to-reveal VERTICAL popover above the
   speaker — tapping #vpMute toggles `.vp-volume-open` (app.js). Same breakpoint
   string as the JS matchMedia in `vpVolVertical()` — keep them in sync. */
@media (max-width: 767px) and (orientation: portrait) {
  .video-player-card:not(.vp-fullscreen) .vp-btn {
    width: 40px;
    height: 40px;
  }

  .video-player-card:not(.vp-fullscreen) .vp-btn svg {
    width: 20px;
    height: 20px;
  }

  .video-player-card:not(.vp-fullscreen) .vp-toggle {
    width: 46px;
    height: 46px;
  }

  .video-player-card:not(.vp-fullscreen) .vp-toggle svg {
    width: 23px;
    height: 23px;
  }

  .video-player-card:not(.vp-fullscreen) .vp-transport-left,
  .video-player-card:not(.vp-fullscreen) .vp-transport-center {
    gap: 8px;
  }

  /* Vertical volume popover floating above the speaker icon. Hidden by default;
     revealed only when app.js adds `.vp-volume-open` (tap). z-index sits above
     the fullscreen scrim (5/6). Higher specificity than the (max-width:560px)
     display:none rule, so it wins. */
  .vp-volume {
    position: relative;
  }

  .vp-volume .vp-volume-slider {
    display: block;
    position: absolute;
    left: 50%;
    right: auto;
    top: auto;
    bottom: calc(100% + 12px);
    width: 14px;
    height: 120px;
    padding: 8px 0;
    background: var(--hairline);
    border-radius: 999px;
    opacity: 0;
    pointer-events: none;
    transform: translateX(-50%) translateY(8px);
    transform-origin: bottom center;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.22);
    z-index: 7;
    transition:
      opacity 0.14s ease,
      transform 0.14s ease;
  }

  /* Neutralise the desktop hover/focus-within reveal on touch: tapping the
     speaker focuses it (:focus-within), which would otherwise show the slider in
     the wrong (horizontal) position. Only `.vp-volume-open` opens it. Declared
     before the open rule so the open rule wins by source order when both match. */
  .vp-volume:hover .vp-volume-slider,
  .vp-volume:focus-within .vp-volume-slider {
    opacity: 0;
    pointer-events: none;
    transform: translateX(-50%) translateY(8px);
  }

  .vp-volume.vp-volume-open .vp-volume-slider {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0);
  }

  /* Remap the shared --vol fill/thumb from horizontal to vertical (fills from
     the bottom up). */
  .vp-volume .vp-volume-fill {
    left: 0;
    bottom: 0;
    top: auto;
    width: 100%;
    height: var(--vol, 100%);
  }

  .vp-volume .vp-volume-thumb {
    left: 50%;
    bottom: var(--vol, 100%);
    top: auto;
    transform: translate(-50%, 50%);
  }

  .vp-volume-slider:hover .vp-volume-thumb,
  .vp-volume-slider.is-dragging .vp-volume-thumb {
    transform: translate(-50%, 50%) scale(1.15);
  }

  .vp-volume .vp-volume-slider::after {
    display: none;
  }
}

/* ---- "No access" popup (grade 3) ---------------------------------------
   A small, friendly modal shown when a grade-3 viewer clicks a video button.
   Self-contained block; shares the overlay/centering idiom of .video-modal. */
.noaccess-modal {
  position: fixed;
  inset: 0;
  z-index: 1100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.noaccess-modal[hidden] {
  display: none;
}

body.noaccess-open {
  overflow: hidden;
}

.noaccess-overlay {
  position: absolute;
  inset: 0;
  background: rgba(28, 28, 28, 0.55);
  backdrop-filter: blur(2px);
  animation: vp-fade 0.18s ease both;
}

.noaccess-card {
  position: relative;
  width: min(360px, 92vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 32px 28px 28px;
  background: var(--canvas);
  border-radius: var(--radius-card);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
  animation: vp-pop 0.22s cubic-bezier(0.2, 0.9, 0.3, 1.2) both;
}

.noaccess-emoji {
  font-size: 64px;
  line-height: 1;
}

.noaccess-title {
  margin: 0;
  font-family: "Sniglet", sans-serif;
  font-weight: 800;
  font-size: 30px;
  color: var(--macaw-blue);
}

.noaccess-text {
  margin: 0;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
}

.noaccess-ok {
  margin-top: 6px;
  min-width: 120px;
  padding: 12px 26px;
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 17px;
  color: var(--canvas);
  background: var(--macaw-blue);
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s ease;
}

.noaccess-ok:hover {
  background: var(--macaw-blue-shadow);
}

.noaccess-ok:focus-visible {
  outline: 3px solid var(--deep-blue);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .noaccess-overlay,
  .noaccess-card {
    animation: none;
  }
}

/* ====================================================================
   Admin content manager (Phase 2) — a simplified GRAY mirror of the
   user content board. Header entry buttons, the board, and the slot
   editor modal. Self-contained; uses neutral grays, not level themes.
   ==================================================================== */

/* Right-side header cluster: keeps Admin / Log out / Login grouped together at
   the right edge (the level nav is absolutely centered, so without this wrapper
   the buttons would spread across the middle and collide with it). */
.topbar-actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 12px;
}

/* Admin/Log out icons: present in markup for the mobile circular-icon variant,
   but hidden on desktop/tablet where the buttons show their text label. */
.action-icon {
  display: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Header buttons (shown only for a signed-in admin). */
.admin-nav-button,
.admin-logout-button {
  padding: 9px 16px;
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 14px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}
.admin-nav-button {
  color: var(--canvas);
  background: var(--macaw-blue);
}
.admin-nav-button:hover {
  background: var(--macaw-blue-shadow);
}
.admin-logout-button {
  color: #555;
  background: #ededed;
}
.admin-logout-button:hover {
  background: #e0e0e0;
}
.admin-nav-button[hidden],
.admin-logout-button[hidden] {
  display: none;
}

/* Login error line. */
.login-error {
  margin: 0;
  color: #d23b3b;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
}
.login-error[hidden] {
  display: none;
}

/* Admin screen shell. */

/* Admin body area: unify ALL text (title, hint, members, board, slot names,
   etc.) to the admin font so the tool reads distinctly from the kid-facing site
   AND its Korean labels render in a high-readability face (Noto Sans KR). The id
   + universal selector outranks the per-element class fonts below (Sniglet /
   Nunito / Inter) without needing !important. The two admin-only modals
   (#adminSlotModal, #memberEditModal) live outside #adminScreen, so they are
   included explicitly here for the same Korean-readable typography. */
#adminScreen,
#adminScreen *,
#adminSlotModal,
#adminSlotModal *,
#memberEditModal,
#memberEditModal * {
  font-family: var(--font-admin);
}

.admin-inner {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Admin body uses (nearly) the full viewport width instead of the site's 80%
   content width, so the weekday board has room and never needs a horizontal
   scrollbar. Capped at the site max and centered, with a >=50px side gutter.
   Overrides only the inline padding of .section-inner (higher specificity);
   the block padding from .section-inner is kept. Admin-only via #adminScreen. */
#adminScreen .admin-inner {
  width: 100%;
  max-width: var(--site-max-width);
  margin-inline: auto;
  padding-right: max(50px, 4vw);
  padding-left: max(50px, 4vw);
}

.admin-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

/* Admin section menu: centered, plain-text tabs at the very top of the admin
   body that switch between the Content and Members panels (each a .admin-view).
   Deliberately text-only (no pill/box) so it reads differently from the
   kid-facing header nav buttons. The .admin-view[hidden] guard keeps a hidden
   panel collapsed even though .admin-view sets display:flex. */
.admin-menu {
  display: flex;
  justify-content: center;
  gap: 28px;
}
.admin-menu-btn {
  padding: 2px 2px 6px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: #9a9a9a;
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  transition:
    color 0.15s ease,
    border-color 0.15s ease;
}
.admin-menu-btn:hover {
  color: var(--macaw-blue);
}
.admin-menu-btn.active {
  color: var(--ink);
  border-bottom-color: var(--macaw-blue);
}
.admin-view {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.admin-view[hidden] {
  display: none;
}

.admin-title {
  margin: 0;
  font-family: "Sniglet", sans-serif;
  font-weight: 800;
  font-size: 30px;
  color: #3a3a3a;
}
.admin-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}
.admin-select {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: #555;
}
.admin-select select {
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  padding: 8px 12px;
  border: 1.5px solid #d6d6d6;
  border-radius: 12px;
  background: #fff;
  color: #333;
  cursor: pointer;
}
.admin-status {
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--macaw-blue);
  min-width: 70px;
}
.admin-hint {
  margin: 0;
  font-family: "Nunito", sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: #777;
}

/* Member management panel (admin screen). */
.admin-members {
  margin-top: 28px;
  padding-top: 22px;
  border-top: 2px solid #eee;
}
.admin-subtitle {
  margin: 0 0 14px;
  font-family: "Nunito", sans-serif;
  font-weight: 900;
  font-size: 20px;
  color: #444;
}
.admin-member-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}
.admin-member-input,
.admin-member-select {
  height: 42px;
  padding: 0 14px;
  border: 2px solid #e2e2e2;
  border-radius: 12px;
  background: #fafafa;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: #333;
}
.admin-member-input {
  flex: 1 1 150px;
  min-width: 120px;
}
.admin-member-input:focus,
.admin-member-select:focus {
  outline: none;
  border-color: var(--macaw-blue);
}
.admin-member-add {
  height: 42px;
  padding: 0 20px;
  border: 0;
  border-radius: 12px;
  background: var(--macaw-blue);
  box-shadow: 0 4px 0 var(--macaw-blue-shadow);
  color: var(--canvas);
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 14px;
  cursor: pointer;
}
.admin-member-add:active {
  transform: translateY(4px);
  box-shadow: none;
}
.admin-member-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 14px;
}
.admin-member-empty {
  margin: 4px 0;
  font-family: "Nunito", sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: #999;
}
.admin-member-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: #f4f4f4;
  border-radius: 12px;
}
.admin-member-row.is-inactive {
  opacity: 0.55;
}
.admin-member-info {
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: #333;
}
.admin-member-actions {
  display: flex;
  flex: 0 0 auto;
  gap: 8px;
}
.admin-member-toggle,
.admin-member-edit {
  flex: 0 0 auto;
  height: 34px;
  padding: 0 14px;
  border: 2px solid #d8d8d8;
  border-radius: 10px;
  background: #fff;
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 13px;
  color: #555;
  cursor: pointer;
}
.admin-member-toggle:hover,
.admin-member-edit:hover {
  border-color: var(--macaw-blue);
  color: var(--macaw-blue);
}
.admin-signup-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: #555;
  cursor: pointer;
}
.admin-signup-toggle input {
  width: 18px;
  height: 18px;
  accent-color: var(--macaw-blue);
}

/* Sign-up entry point on the login page (placeholder, hidden by default). */
.login-signup {
  margin-top: 18px;
  width: 100%;
}
.login-signup-sep {
  margin: 0 0 12px;
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 14px;
  color: var(--muted-ink);
  text-align: center;
}
.login-note {
  margin: 4px 0 0;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--macaw-blue);
  text-align: center;
}

/* The gray board. */
.admin-board {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 18px;
  background: #f4f4f4;
  border-radius: 20px;
}
.admin-songs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.admin-grid {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.admin-book {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: 16px;
  align-items: stretch;
}
/* Level 1 single-cover block: keep the one cover at its current size and center
   it vertically against the four week rows instead of stretching it full-height. */
.admin-book--single .admin-cover {
  align-self: center;
}
.admin-weeks {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 10px;
  justify-content: center;
}
.admin-week-row {
  display: grid;
  grid-template-columns: 70px repeat(5, minmax(0, 1fr));
  gap: 8px;
  align-items: stretch;
}
.admin-week-label {
  display: grid;
  place-items: center;
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 14px;
  color: #777;
  background: #e9e9e9;
  border-radius: 12px;
}

/* Editable slot button. */
.admin-slot {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 3px;
  min-height: 58px;
  padding: 9px 12px;
  text-align: left;
  background: #fff;
  border: 1.5px solid #dcdcdc;
  border-radius: 12px;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.admin-slot:hover {
  border-color: var(--macaw-blue);
  box-shadow: 0 0 0 2px rgba(40, 160, 220, 0.15);
}
.admin-slot[data-filled="true"] {
  border-color: var(--macaw-blue);
  background: #f2fbff;
}
.admin-slot-name {
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 13px;
  color: #444;
}
.admin-slot-url {
  font-family: "Inter", sans-serif;
  font-weight: 400;
  font-size: 11px;
  color: #8a8a8a;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-slot[data-filled="true"] .admin-slot-url {
  color: var(--macaw-blue);
}

/* Cover dropzone card. */
.admin-cover {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 2px;
  min-height: 150px;
  padding: 10px;
  background: #fff;
  background-size: cover;
  background-position: center;
  border: 2px dashed #cfcfcf;
  border-radius: 16px;
  cursor: pointer;
  overflow: hidden;
}
.admin-cover.has-cover {
  border-style: solid;
  border-color: #d6d6d6;
}
.admin-cover.is-dragover {
  border-color: var(--macaw-blue);
  box-shadow: 0 0 0 3px rgba(40, 160, 220, 0.2);
}
.admin-cover-label,
.admin-cover-hint {
  position: relative;
  font-family: "Nunito", sans-serif;
  text-align: center;
}
.admin-cover-label {
  font-weight: 800;
  font-size: 13px;
  color: #555;
}
.admin-cover-hint {
  font-weight: 600;
  font-size: 11px;
  color: #999;
}
/* On an uploaded cover, sit the labels on a readable scrim. */
.admin-cover.has-cover .admin-cover-label,
.admin-cover.has-cover .admin-cover-hint {
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
}

/* Slot editor modal. */
.admin-modal {
  position: fixed;
  inset: 0;
  z-index: 1100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.admin-modal[hidden] {
  display: none;
}
body.admin-modal-open {
  overflow: hidden;
}
.admin-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(28, 28, 28, 0.55);
  backdrop-filter: blur(2px);
}
.admin-modal-card {
  position: relative;
  width: min(440px, 92vw);
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 24px;
  background: var(--canvas);
  border-radius: var(--radius-card);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}
.admin-modal-title {
  margin: 0;
  font-family: "Sniglet", sans-serif;
  font-weight: 800;
  font-size: 22px;
  color: #3a3a3a;
}
.admin-modal-sub {
  margin: 0;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--macaw-blue);
}
.admin-modal-label {
  margin-top: 6px;
  font-family: "Nunito", sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: #666;
}
.admin-modal-input {
  font-family: "Inter", sans-serif;
  font-size: 14px;
  padding: 12px 14px;
  border: 1.5px solid #d6d6d6;
  border-radius: 12px;
  background: #fff;
  color: #333;
}
.admin-modal-input:focus {
  outline: none;
  border-color: var(--macaw-blue);
  box-shadow: 0 0 0 3px rgba(40, 160, 220, 0.18);
}
.admin-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
}
.admin-btn {
  padding: 10px 18px;
  font-family: "Nunito", sans-serif;
  font-weight: 800;
  font-size: 14px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
}
.admin-btn-ghost {
  color: #555;
  background: #ededed;
}
.admin-btn-ghost:hover {
  background: #e0e0e0;
}
.admin-btn-primary {
  color: var(--canvas);
  background: var(--macaw-blue);
}
.admin-btn-primary:hover {
  background: var(--macaw-blue-shadow);
}

@media (max-width: 760px) {
  .admin-book {
    grid-template-columns: 1fr;
  }
  .admin-cover {
    min-height: 120px;
  }
  .admin-week-row {
    grid-template-columns: 56px repeat(5, minmax(0, 1fr));
  }
}
