/* ==========================================================================
   Intercambio Cultural — Design System
   Reusable CSS custom properties + utility classes.
   ========================================================================== */

/* ==========================================================================
   Colors
   ========================================================================== */

:root {
  /* Terracotta — one shade per chapter, lightest to darkest */
  --capitulo-1: #f5c4b3;
  --capitulo-2: #f1ac93;
  --capitulo-3: #f0997b;
  --capitulo-4: #e37d56;
  /* Next-chapter preview shade only — chapter 4 is the last real chapter,
     so nothing is ever styled with this as its own background. Used by
     exercise-label.hbs's "next chapter" coloring (see nextCapituloNumber
     in src/app.js). */
  --capitulo-5: #d5703f;

  /* Dark warm-brown text, used on all four terracotta backgrounds */
  --text-on-terracotta: #4a1b0c;

  /* Amber — vocabulary highlighting */
  --amber-bg: #fac775;
  --amber-text: #412402;

  /* Teal — interactive elements (buttons, links, clickable card borders) */
  --teal: #1d9e75;
  --teal-text: #04342c;

  /* Audio player accent — same teal as --teal above; its own named
     variable per the audio-player.hbs component spec, kept as a single
     source of truth rather than a duplicate hex value. */
  --audio-accent: var(--teal);

  /* Corner rounding, used consistently across cards, buttons, images, video frames */
  --radius: 12px;

  /* Neutral border for plain content boxes (e.g. speech-bubble text boxes)
     that don't carry a chapter/accent color of their own. */
  --border-light: rgba(0, 0, 0, 0.15);
}

/* Chapter color classes — apply one to a container to set its chapter theme */
.capitulo-1 {
  background-color: var(--capitulo-1);
  color: var(--text-on-terracotta);
}

.capitulo-2 {
  background-color: var(--capitulo-2);
  color: var(--text-on-terracotta);
}

.capitulo-3 {
  background-color: var(--capitulo-3);
  color: var(--text-on-terracotta);
}

.capitulo-4 {
  background-color: var(--capitulo-4);
  color: var(--text-on-terracotta);
}

/* body carries capitulo-{{chapterNumber}} (see layouts/leccion.hbs) purely
   for the dark-terracotta text color above — every page's *background* is
   white by default, not terracotta. Sections alternate white/terracotta
   individually (.seccion-escucha is explicitly #fff, .seccion-lectura is
   explicitly var(--capitulo-1)), so terracotta only ever appears where a
   section actually asks for it. Without this override, any gap that
   reveals the body underneath (e.g. .leccion-header's margin-bottom down
   to the first section) would show the *same* terracotta as the chapter
   shade, making it read as more chapter-color instead of an actual gap.
   body.capitulo-N (element+class) is more specific than .capitulo-N alone,
   so this wins without touching what .capitulo-N does for every other
   element (header box, video boxes, etc.) that still wants the real
   terracotta fill. */
body.capitulo-1,
body.capitulo-2,
body.capitulo-3,
body.capitulo-4 {
  background-color: #fff;
}

/* ==========================================================================
   Typography
   ========================================================================== */

/* Spanish-language content */
.text-es {
  font-family: Georgia, "Times New Roman", serif;
}

/* Danish-language content — instructions, UI labels */
.text-da {
  font-family: Helvetica, Arial, sans-serif;
}

/* Google Material Symbols icon font — loaded in head.hbs. Boilerplate
   settings recommended by Google so the glyph ligature (e.g.
   "arrow_forward") renders as an icon instead of literal text; font-size
   and color are left to callers (icons inherit `color` via currentColor
   like any glyph). */
.material-symbols-outlined {
  font-family: "Material Symbols Outlined";
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  -webkit-font-smoothing: antialiased;
}

/* ==========================================================================
   Site nav: fixed logo/hamburger trigger + sidebar panel
   (see site-nav.hbs, sidebar-nav.hbs, public/js/site-nav.js)
   ========================================================================== */

/* Persistent top-left trigger. Solid pill (not just colored text on a
   transparent background) since it's fixed and needs to stay legible over
   whatever's scrolled underneath it — the terracotta header at the top of
   the page, white sections, terracotta sections further down. Background
   + text color come from the capitulo-{{chapterNumber}} class applied
   alongside this one in site-nav.hbs (same chapter-shade convention as
   the lesson header/sections), not hardcoded here — deliberately no
   background/color declared in this rule so .capitulo-N's own values win
   instead of fighting them. z-index is set high enough to clear every
   other positioned element on the page (badges, the header's own sun
   glow, exercise labels) but still under the sidebar overlay (100), so
   opening the sidebar covers it like everything else. */
.site-nav-trigger {
  position: fixed;
  top: 24px;
  left: 24px;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.25rem 0.6rem 0.75rem;
  border: none;
  border-radius: 999px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
  font-size: 1rem;
  font-weight: bold;
  cursor: pointer;
  transition:
    transform 0.35s ease,
    opacity 0.35s ease;
}

/* Teal, not the button's own inherited dark-terracotta text color —
   matches the site's "teal = interactive element" convention (buttons,
   links, clickable card borders elsewhere in design-system.css) used to
   flag that this icon specifically is the clickable trigger. */
.site-nav-icon {
  color: var(--teal);
  font-size: 28px;
}

.site-nav-wordmark {
  white-space: nowrap;
}

/* Toggled by public/js/site-nav.js's scroll-direction handler (reused
   from Aprendo's general.js) — slides/fades the trigger out of view on
   scroll-down, back in on scroll-up. pointer-events:none so it can't be
   clicked while transitioned off-screen. */
.site-nav-trigger--hidden {
  transform: translateY(-140%);
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 600px) {
  .site-nav-trigger {
    top: 16px;
    left: 16px;
  }

  .site-nav-wordmark {
    font-size: 0.9rem;
  }
}

/* Fullscreen dark backdrop behind the sidebar panel — same pattern as
   Aprendo's .modalOverlay: display:none by default, toggled to block by
   site-nav.js on open, and clicking the backdrop itself (not the panel)
   closes it again. */
.modal-overlay {
  position: fixed;
  display: none;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 100;
  overflow: auto;
  background-color: rgba(0, 0, 0, 0.4);
}

.sidebar-panel {
  width: 320px;
  max-width: 84vw;
  height: 100%;
  overflow-y: auto;
  background: #fff;
  color: var(--text-on-terracotta);
}

/* Slide-in-from-left + fade, matching Aprendo's .animateLeft keyframes. */
.sidebar-panel--animate-in {
  animation: sidebar-slide-in 0.3s ease;
}

@keyframes sidebar-slide-in {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.sidebar-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem;
  border-bottom: 1px solid var(--border-light);
}

.sidebar-panel-title {
  font-size: 1.1rem;
  font-weight: bold;
}

.sidebar-close {
  display: flex;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
}

.sidebar-nav-list {
  display: flex;
  flex-direction: column;
}

.sidebar-nav-list a {
  padding: 1rem 1.5rem;
  border-bottom: 1px solid var(--border-light);
  color: var(--text-on-terracotta);
  text-decoration: none;
}

.sidebar-nav-list a:hover {
  background: var(--capitulo-1);
}

/* ==========================================================================
   Lesson header + footer (see leccion-header.hbs and layouts/leccion.hbs)
   ========================================================================== */

/* Chapter-colored box at the top of every lesson page. Background/text
   color come entirely from the .capitulo-N class applied alongside this one
   (see leccion-header.hbs) — same terracotta shades used everywhere else,
   not redefined here. min-height plus justify-content:center keeps the
   grouped three-line block vertically centered within a consistent box
   height, regardless of how short the three lines are. */
/* margin-bottom (see the 600px media query below for the mobile value)
   gives breathing room down to the first section's straddling badge —
   same 96px/48px responsive values used for .seccion-escucha/.seccion-lectura's
   own padding, so the spacing rhythm stays consistent down the page. Must
   be margin here, not padding: the header and the page background are
   already the same terracotta shade, so there's no color-box to pad —
   margin is what pushes the section (and its badge) down. */
/* position:relative + overflow:hidden is what makes the "sun" (below)
   read as a big circle that's genuinely bigger than this box: the circle
   itself is sized well past the box's own height, so it visibly spills
   past the top/bottom edges — overflow:hidden crops that spill cleanly at
   the box boundary instead of letting it bleed into the page, which is
   what actually sells the "peeking sun" look rather than just a soft
   gradient patch. */
.leccion-header {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 420px;
  padding: 2.5rem 1.5rem 1rem;
  margin-bottom: 96px;
  overflow: hidden;
  text-align: center;
}

/* The sun itself: a large round radial gradient, centered on the box and
   sized well past its min-height (700px circle vs. a ~220px-tall box), so
   .leccion-header's overflow:hidden above crops it top and bottom —
   that's what makes it read as a big sun the box is too small to fully
   contain, rather than a gradient sized to fit. z-index:0 (plus z-index:1
   on .leccion-header-main below) keeps the text stacked above it. circle
   (not ellipse) since the ask specifically was for it to look round, like
   an actual sun, not an oval smear. */
.leccion-header::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 0;
  width: 700px;
  height: 700px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, #fac775 0%, transparent 70%);
}

/* Fades the box's bottom edge into white instead of cutting off hard into
   the white margin-bottom gap below. transparent→#fff lets whatever's
   underneath (the capitulo-N background color, or the sun where it
   reaches this low) show through at the top of the fade and gradually
   overpaints to solid white by the box's own bottom edge — works
   automatically for any chapter's shade without hardcoding a color here.
   height:10% (not a fixed px) is relative to .leccion-header's own
   height (the nearest positioned ancestor), so the fade only ever covers
   the last tenth of the box and scales automatically with it — no
   separate mobile override needed. Sits at the same z-index as the sun
   (below the z-index:1 text), and above it in paint order since it comes
   second in the DOM. */
.leccion-header::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  height: 20%;
  background: linear-gradient(to bottom, transparent, #fff);
  pointer-events: none;
}

.leccion-header-main {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

/* line-height: 1 on all three lines (title/lesson/chapter) — without it,
   each line's default "normal" line-height reserves invisible leading
   space proportional to its own font-size, so a larger line (e.g.
   Lección 1 at 1.25rem) carries visibly more empty space around it than a
   smaller one (Capítulo 1... at 0.9rem), even though .leccion-header-main's
   flex gap between them is the same 0.5rem either way. Tight line-height
   makes each box hug its glyphs, so the gap reads equal top and bottom of
   the title. */
.leccion-header-title {
  margin: 0;
  font-size: 2rem;
  font-weight: bold;
  line-height: 1;
}

.leccion-header-lesson {
  margin: 0;
  font-size: 1.25rem;
  line-height: 1;
}

/* margin-top adds on top of .leccion-header-main's own 0.5rem gap (flex
   gap and an item's own margin stack, they don't collapse), so the space
   above this line reads larger than the lesson-label/title gap above it —
   now a reliable difference since line-height:1 above removes the
   font-size-proportional leading that made equal-looking values behave
   inconsistently before. */
.leccion-header-chapter {
  margin: 0;
  margin-top: 0.5rem;
  font-size: 0.9rem;
  line-height: 1;
}

/* Minimal site footer — deliberately plain for now, easy to expand later. */
.leccion-footer {
  padding: 1rem;
  border-top: 1px solid var(--border-light);
  text-align: center;
  font-size: 0.9rem;
}

/* ==========================================================================
   Layout Utilities
   ========================================================================== */

/* Responsive grid for side-by-side boxes (exercise pairs, comprehension-check
   cards). Cards auto-wrap to a single full-width column on narrow screens —
   no manual breakpoint needed. */
.exercise-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

/* Fixed 2-column grid for listening-exercise cards — always exactly 2
   columns on desktop/tablet, regardless of viewport width. If the card
   count is odd, the last card is centered on its own row instead of
   sitting flush left. Collapses to 1 column on mobile. */
.exercise-grid--wide {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

.exercise-grid--wide > *:last-child:nth-child(odd) {
  grid-column: 1 / -1;
  max-width: calc(50% - 0.5rem);
  justify-self: center;
}

/* Flexbox row for text-beside-image sections (headers, content blocks).
   Stacks into a column below 600px viewport width. */
.text-image-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 1.5rem;
}

@media (max-width: 600px) {
  .text-image-row {
    flex-direction: column;
  }

  .exercise-grid--wide {
    grid-template-columns: minmax(0, 1fr);
  }

  .exercise-grid--wide > *:last-child:nth-child(odd) {
    max-width: none;
    justify-self: stretch;
  }
}

/* ==========================================================================
   Components
   ========================================================================== */

/* Clickable/interactive box: rounded corners, teal accent border on the left.
   Defaults to a white background — .ejercicio-escucha overrides this to
   terracotta below, since that card needs the opposite treatment. */
.interactive-card {
  margin: 0.5rem;
  border-radius: var(--radius);
  border-left: 4px solid var(--teal);
  background: #fff;
}

/* Boxed treatment for the main lesson video: terracotta background with
   generous padding so it visibly peeks around the video-embed inside.
   Spacing around it comes from the parent .seccion-escucha's gap/padding,
   not its own margin — it's always placed inside that wrapper.
   position: relative anchors its A.1 exercise-label. */
.video-box {
  position: relative;
  padding: 2rem;
  border-radius: var(--radius);
  background: var(--capitulo-1);
}

/* Click-to-load video embed: thumbnail + play button until clicked, then
   swapped for a live iframe by public/js/video-embed.js. Aspect ratio is
   set per-instance via inline style (see video-embed.hbs). */
/* Optional heading + short text block above a video embed — only rendered
   when introText is passed to the partial (see video-embed.hbs). Used for
   the main lesson video; the five exercise-card videos don't pass
   introText, since they already show exerciseName as their own heading.
   The heading reuses .ejercicio-escucha-heading directly (same element,
   <h3>) rather than its own styling, so the two stay visually identical.
   margin-top here (not on the shared heading) is what separates the two
   — .ejercicio-escucha-heading itself stays margin:0 since its other use
   (the exercise-card exerciseName) gets its spacing from the parent
   .ejercicio-escucha's flex gap instead. */
.video-embed-intro {
  margin: 0.75rem 0 1.5rem;
  color: var(--text-on-terracotta);
}

.video-embed {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: var(--aspect);
  overflow: hidden;
  border-radius: var(--radius);
  background: #000;
  cursor: pointer;
}

.video-embed-thumbnail {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-embed-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 64px;
  height: 64px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.video-embed-play-triangle {
  width: 0;
  height: 0;
  margin-left: 4px; /* optical centering */
  border-top: 12px solid transparent;
  border-bottom: 12px solid transparent;
  border-left: 20px solid white;
}

.video-embed iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: none;
}

/* Listening-exercise card: A.N label + ear/pencil icons in a header row,
   exerciseName as its own title below, then intro/vocab/video tabs. Tab
   switching is handled by public/js/tabs.js; unstyled beyond the .active
   class for now. Overrides .interactive-card's white default with
   terracotta — the tab-content panel inside (.ejercicio-escucha-panels)
   has no background of its own, so the whole card reads as one consistent
   terracotta color throughout. position: relative anchors the card's
   exercise-label. */
.ejercicio-escucha {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem;
  background: var(--capitulo-1);
}

/* White section wrapping both the main video box and the listening-exercise
   cards, so there's one continuous white area behind them — terracotta
   only ever appears as each individual box's own color (.video-box,
   .ejercicio-escucha), never in the space around or between them. */
/* padding-top/padding-bottom overrides (see the 600px media query for the
   mobile values) give breathing room above/below the section's own content,
   beyond the general 2rem padding — padding-top below the straddling
   ¡Escucha! badge, padding-bottom above the next section's straddling badge.
   Deliberately padding, not margin: this space must stay filled with the
   section's own background color. A margin here would instead reveal the
   body's own background — which is the *same* terracotta shade as the next
   section's own background whenever the two are adjacent (body is
   var(--capitulo-1), same as .seccion-lectura below) — so the true
   white/terracotta color seam would land at this section's outer edge
   instead of the next section's top edge, decoupling it from that section's
   badge (which straddles its own top edge). Padding keeps the seam and the
   badge's straddle point at the same place. */
.seccion-escucha {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
  padding-top: 96px;
  padding-bottom: 96px;
  background: #fff;
}

.ejercicio-escucha-heading {
  margin: 0;
}

/* Indents the exercise-card heading (exerciseName) to line up with the tab
   buttons below (.ejercicio-escucha-tabs' own padding-left: 1rem) and the
   panel content beside/beneath them (.ejercicio-escucha-panels' padding:
   1rem) — without this, the heading sits flush with the card's own edge,
   1rem left of everything else. Scoped to this direct-child case (not
   .ejercicio-escucha-heading itself) since the same class is reused as-is,
   unindented, for the main A.1 video's intro heading in .video-box, which
   has no tabs/panel offset to match. */
.ejercicio-escucha > .ejercicio-escucha-heading {
  margin-left: 1rem;
}

/* Ear/pencil icons, pushed to the right so the top-left corner stays
   clear for the card's exercise-label. Spacing before the exercise-name
   title and tabs below comes from .ejercicio-escucha's own flex gap, not
   a margin here. */
.ejercicio-escucha-header {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

/* padding-left matches .ejercicio-escucha-panels' own padding below, so
   the tab buttons line up with the panel content's left edge rather than
   just the panel box's outer edge. */
.ejercicio-escucha-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding-left: 1rem;
}

/* Stacks all three tab panels in the same grid cell so the container's
   height is always the tallest panel's height, regardless of which tab is
   active — switching tabs no longer resizes the card. Only this panel area
   uses the stacking trick; the heading and tab buttons stay in normal flow
   above it. */
.ejercicio-escucha-panels {
  display: grid;
  padding: 1rem;
  border-radius: var(--radius);
}

.ejercicio-escucha-panels > [data-tab-content] {
  grid-row: 1;
  grid-column: 1;
  visibility: hidden;
}

.ejercicio-escucha-panels > [data-tab-content].active {
  visibility: visible;
}

.ejercicio-escucha-placeholder {
  padding: 1rem;
  border-radius: var(--radius);
  background: rgba(0, 0, 0, 0.05);
  font-style: italic;
}

/* Ear + pencil icon pair in the card header, grouped on the right of the
   exerciseName — visible regardless of which tab is active. min-height
   matches .ejercicio-escucha-icon's own height so the row still reserves
   its usual footprint even when left empty (see .comunica-instructions'
   header in leccion1.hbs, which has no icon asset yet) — a future icon
   slots in without any layout shift. */
.ejercicio-escucha-icons {
  display: flex;
  gap: 0.5rem;
  min-height: 64px;
}

.ejercicio-escucha-icon {
  width: 64px;
  height: 64px;
}

/* Tab-bar buttons: dark-terracotta outline/text when inactive, so the
   card's own terracotta background shows through; inverts to a solid
   dark-terracotta fill with white text when .active. tabs.js only toggles
   the .active class — all the visual logic lives here. transition
   duration is 300ms (slower than most of this file's UI transitions) so
   the .tab-label--complete swap below reads as a clearly noticeable
   animation, not an instant snap. */
/* min-width fits "Introducción" (the longest of the three static labels,
   ~143px at 1rem body text) plus a little slack, so all three buttons
   render at the same width in every layout — one row on desktop, wrapped
   2-then-1 on mobile (see .ejercicio-escucha-tabs' flex-wrap and the
   600px override centering that wrapped last row). text-align keeps the
   two shorter labels centered in that shared width rather than hugging
   the button's left edge. */
.tab-label {
  min-width: 9.5rem;
  padding: 0.75rem 1.5rem;
  border: 2px solid var(--text-on-terracotta);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-on-terracotta);
  font: inherit;
  text-align: center;
  cursor: pointer;
  transition:
    background-color 300ms ease,
    border-color 300ms ease,
    color 300ms ease;
}

.tab-label.active {
  background: var(--text-on-terracotta);
  border-color: var(--text-on-terracotta);
  color: #fff;
}

/* Third tab state (see public/js/tema1-vocabulario.js's onComplete):
   teal background/border/text, distinct from both the dark-terracotta
   inactive outline and active fill above — signals "vocab is done, video
   is ready" on the Vídeo tab specifically, before the learner has
   actually switched to it. .tab-label.active (two classes, higher
   specificity than this single class) still wins once the tab really is
   the active one, so clicking into it shows the normal active look
   instead of fighting this teal state. */
.tab-label--complete {
  background: var(--teal);
  border-color: var(--teal);
  color: #fff;
}

/* Inline shortcut link (e.g. "Træn ordforråd") that jumps to another tab
   within the same card — see public/js/tabs.js. Plain hyperlink look, not
   a button: no border/fill, just underlined teal text. Sits on its own
   line below the paragraph it follows. */
.ejercicio-escucha-inline-tab-trigger {
  display: block;
  width: fit-content;
  margin-top: 0.75rem;
  padding: 0;
  border: none;
  background: none;
  color: var(--teal);
  text-decoration: underline;
  font: inherit;
  cursor: pointer;
}

/* ==========================================================================
   Vocabulary matching exercise (public/js/match1-engine.js)
   Adapted from Aprendo's c04Flex exercise pattern — engine itself is
   unchanged; only these styles and the markup are new.
   ========================================================================== */

/* Word-bank container: unwrapped row, original order reversed.
   position:relative anchors .match-complete-message, which is absolutely
   positioned and sized to this container specifically. */
.c04Flex-container {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  flex-direction: row-reverse;
  justify-content: space-around;
  align-items: center;
  border-radius: var(--radius);
  height: auto;
}

/* Completion state (see public/js/tema1-vocabulario.js): the word bank
   shrinks away to a hairline once every pair is matched and
   .match-complete-message has been moved out to the instructions box
   above, so the (now genuinely empty) space it leaves reads as "everything
   moved up" rather than a lingering blank box. height starts this
   transition from a JS-set explicit pixel value (animating from `auto`
   doesn't transition), so this rule only supplies the transition + the
   overflow:hidden needed to clip the still-in-the-DOM (visibility:hidden)
   word chips as the box shrinks past them. overflow stays visible the
   rest of the time so word-chip hover tooltips (.vocab-word::after) can
   still pop up past this box's own edge. */
.c04Flex-container.is-collapsing {
  overflow: hidden;
  transition: height 400ms ease;
}

/* Answer-box container: single column, newest-filled slot on top. Kept as
   its own rule (not reusing .c04Flex-container) since it needs the
   opposite flex-direction/wrap behavior. */
.c04SvarBoks {
  display: flex;
  flex-direction: column-reverse;
  flex-wrap: nowrap;
}

/* Clickable word chip. Base styling is the Spanish-word treatment (amber
   fill); .c04Flex-element--da overrides only the background for Danish
   words — border and text color stay the same amber accent on both, so
   the only visual difference is the fill. */
.c04Flex-element {
  border: solid var(--amber-text) 1px;
  font-size: 1.2em;
  margin: 5px;
  padding: 8px;
  height: 2em;
  border-radius: var(--radius);
  cursor: pointer;
  user-select: none;
  background-color: var(--amber-bg);
  color: var(--amber-text);
  transition:
    background-color 180ms ease,
    transform 180ms ease,
    opacity 250ms ease;
}

.c04Flex-element:hover {
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
}

.c04Flex-element--da {
  background-color: #fff;
}

/* Selected state: transparent teal (was transparent blue) — must be a
   compound selector on .c04Flex-element, since the shared .is-selected
   rule below only supplies the pop animation, not a color. */
.c04Flex-element.is-selected {
  background-color: rgba(29, 158, 117, 0.18);
}

/* Filled answer-box slot — now matches the Spanish (amber) word styling
   instead of the old white/grey/green look. */
.svarCss {
  background-color: var(--capitulo-1);
  border: none;
  border-bottom: solid var(--amber-text) 1px;
  color: var(--amber-text);
  font-size: 1.2em;
  margin: 5px;
  padding: 8px;
  height: 2em;
  border-radius: 0;
}

/* Shared engine states below — unchanged from the original exercise. */
.is-selected {
  animation: selectPop 160ms ease-out;
}
@keyframes selectPop {
  0% {
    transform: scale(0.98);
  }
  100% {
    transform: scale(1);
  }
}

.is-wrong {
  animation: shakeX 240ms ease-in-out;
}
@keyframes shakeX {
  0% {
    transform: translateX(0);
  }
  20% {
    transform: translateX(-6px);
  }
  40% {
    transform: translateX(6px);
  }
  60% {
    transform: translateX(-4px);
  }
  80% {
    transform: translateX(4px);
  }
  100% {
    transform: translateX(0);
  }
}

.is-matched {
  opacity: 0.55;
  pointer-events: none;
}

.fade-out-02 {
  pointer-events: none;
  animation: fade-out-02 1.2s ease-out forwards;
}
@keyframes fade-out-02 {
  0% {
    opacity: 1;
    visibility: visible;
  }
  100% {
    opacity: 0;
    visibility: hidden;
  }
}

/* ==========================================================================
   Vocab instructions + exercise area (see match-exercise.hbs)
   ========================================================================== */
/* position:relative anchor for .match-complete-message — see
   match-exercise.hbs's comment on this wrapper and
   public/js/tema1-vocabulario.js's onComplete. */
.match-instructions-stack {
  position: relative;
}

/* Instructions text — fades out in place on completion (see
   .is-fading-out) while .match-complete-message fades in over it —
   opacity only, never a layout change, so this box stays exactly the
   height its own instructions text needs. */
.match-instructions {
  margin: 0 0 1.5rem;
  color: var(--text-on-terracotta);
  transition: opacity 300ms ease;
}

/* Toggled by public/js/tema1-vocabulario.js's onComplete once
   .match-complete-message is about to fade in on top of this text within
   the same .match-instructions-stack box. */
.match-instructions.is-fading-out {
  opacity: 0;
}

/* Vocab-complete message — revealed by public/js/tema1-vocabulario.js
   once every pair is matched. Starts out inside #{{prefix}}-vocab-root
   (.c04Flex-container), but the JS moves it into .match-instructions-stack
   right as the exercise completes, so it ends up absolutely positioned
   and centered over the (fading-out) instructions text instead — while
   .c04Flex-container itself collapses away (see .is-collapsing below).
   pointer-events:none on the inactive state keeps it from blocking clicks
   on whatever's underneath while still fading in/out. */
.match-complete-message {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 1rem;
  color: var(--text-on-terracotta);
  text-align: center;
  opacity: 0;
  transform: translateY(10px) scale(0.97);
  pointer-events: none;
  /* Deliberately slower and later than the rest of the completion sequence
     (.tab-label--complete, .vocab-video-link.is-visible, .is-collapsing —
     all triggered immediately in public/js/tema1-vocabulario.js) — this
     message only starts fading/rising in once those have finished, via a
     setTimeout there, so it isn't just one more thing moving at the same
     moment. Landing last (and taking its own beat: 450ms, versus their
     300ms) is what makes it register as the actual instruction to act on,
     rather than a fourth simultaneous animation. The rise + soft
     scale-up reads as this message specifically arriving, without a
     bouncy/overshooting easing that would tip it into gimmicky. */
  transition:
    opacity 450ms ease-out,
    transform 450ms ease-out;
}

.match-complete-message.active {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

/* "Se video!" shortcut link (see match-exercise.hbs) — starts invisible
   and fades in on the same 300ms schedule, triggered on the same
   animation frame, as the Vídeo tab's own .tab-label--complete highlight
   (see public/js/tema1-vocabulario.js), so the two read as one synced
   "you're done" signal instead of two separate events. hidden (removed
   by JS) controls whether it's in the flow at all — the fade only
   governs its opacity once shown. The [hidden] override is needed
   because .ejercicio-escucha-inline-tab-trigger sets its own
   display:block at equal specificity — without it, that rule would beat
   the browser's default [hidden] { display: none } and this would stay
   visible even before completion (same gotcha called out on
   .video-embed-post-overlay above). */
.vocab-video-link[hidden] {
  display: none;
}

.vocab-video-link {
  opacity: 0;
  transition: opacity 300ms ease;
}

.vocab-video-link.is-visible {
  opacity: 1;
}

/* ==========================================================================
   Video pre/post overlays — shown before the video loads and after it
   finishes, for exercise-card videos (whenever preguntas is passed to
   video-embed.hbs). See public/js/video-embed.js for the Vimeo Player API
   wiring behind the post-overlay.
   ========================================================================== */
.video-embed-wrapper {
  position: relative;
}

.video-embed-preguntas-overlay {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  width: 100%;
  height: 100%;
  padding: 1.5rem;
  color: #fff;
  text-align: center;
}

.video-embed-overlay-text {
  margin: 0;
  font-size: 1.25rem;
  font-weight: bold;
}

.video-embed-preguntas-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.video-embed-play-large {
  width: 88px;
  height: 88px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--teal);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.video-embed-play-triangle-large {
  width: 0;
  height: 0;
  margin-left: 6px; /* optical centering */
  border-top: 16px solid transparent;
  border-bottom: 16px solid transparent;
  border-left: 26px solid white;
}

.video-embed-post-overlay {
  position: absolute;
  inset: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 1.5rem;
  background: rgba(0, 0, 0, 0.85);
  color: #fff;
  text-align: center;
}

/* display:flex only applies once [hidden] is removed — otherwise the
   [hidden] attribute's display:none (from the browser's default
   stylesheet) would lose to this same-specificity author rule and the
   overlay would stay visually visible even while .hidden is toggled. */
.video-embed-post-overlay:not([hidden]) {
  display: flex;
}

.video-embed-rewatch-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0;
  border: none;
  background: none;
  color: #fff;
  font: inherit;
  cursor: pointer;
}

.video-embed-rewatch-label {
  font-weight: bold;
}

/* ==========================================================================
   Speech-bubble reading text (see speech-bubble-text.hbs)
   Tema 1 Section B's five-speaker structure specifically — not a universal
   reading-text pattern, so this stays separate from .text-image-row.
   DOM order is always photo-then-text; :nth-of-type(even) flips only the
   visual side via row-reverse, and moves the speech-bubble tail to match.
   nth-of-type (not nth-child) so the section-title-badge span sitting
   before these rows in .seccion-lectura doesn't shift the count.
   ========================================================================== */
/* Wrapper section, matching .seccion-escucha's own padding so Section B
   reads as a continuation of the same page layout. Terracotta background
   (matching .video-box/.ejercicio-escucha's own hardcoded capitulo-1
   shade) sits behind the white speech-bubble boxes; position: relative
   anchors the ¡Lee! badge below. */
/* padding-bottom is the space down to the next section (see
   .seccion-escucha above for why this must be padding, not margin — a
   margin here would reveal the body's own background, which is the same
   capitulo-1 terracotta as this section, so it'd read as more of this
   section's own color rather than a gap, and would shift the seam away
   from Section C's badge below). */
.seccion-lectura {
  position: relative;
  padding: 2rem;
  padding-top: 96px;
  padding-bottom: 96px;
  background: var(--capitulo-1);
}

/* Mobile padding-top/padding-bottom override for both sections above.
   Placed here (after both rules, not merged into the earlier 600px query
   near the top of the file) so it wins on source order — an
   equal-specificity override earlier in the file would lose to the
   unconditional padding-top/-bottom: 96px rules above, the same trap
   already hit once with .speech-bubble-row. */
@media (max-width: 600px) {
  .seccion-escucha,
  .seccion-lectura {
    padding-top: 48px;
    padding-bottom: 48px;
  }

  /* Extra room below Section B's content, on top of the shared 48px
     above — otherwise the gap before Comunica reads as noticeably
     smaller than the one before Lee. */
  .seccion-lectura {
    padding-bottom: 72px;
  }

  /* Shrink the white side padding around Section A's boxes (.video-box,
     .interactive-card cards, .vocab-support-box) to a sliver, so they run
     nearly edge-to-edge instead of losing width to it. */
  .seccion-escucha {
    padding-left: 0.125rem;
    padding-right: 0.125rem;
  }

  /* .interactive-card's own side margin (see the base rule earlier in this
     file) is what made A.2–A.6 sit narrower than A.1 (.video-box) and the
     vocab boxes, which have no side margin of their own and rely on
     .seccion-escucha's padding alone — dropping it here makes all of
     Section A's boxes line up flush with the same edge. */
  .interactive-card {
    margin-left: 0;
    margin-right: 0;
  }

  /* Once the tabs wrap (2 buttons, then Vídeo alone below — see
     .tab-label's shared min-width and .ejercicio-escucha-tabs' flex-wrap),
     center each wrapped row instead of hugging the left edge, so the lone
     last button reads as centered under the pair above it rather than
     stranded on the left. padding-left is dropped too — it existed only
     to line the (left-aligned) row up with the panel content below, which
     no longer applies once the row is centered. */
  .ejercicio-escucha-tabs {
    justify-content: center;
    padding-left: 0;
  }

  .leccion-header {
    margin-bottom: 48px;
  }

  .leccion-header::before {
    width: 420px;
    height: 420px;
  }
}

/* Wraps the B.1 label + title + all rows in one column, matching the
   rows'/title's own 720px width — so the label's top-left position lands
   at that same column's corner, not the wider section's edge. Also the
   scroll target for the "B.1" hash link (data-scroll-id, set in the
   .hbs). position: relative anchors the exercise-label. */
.speech-bubble-box {
  position: relative;
  max-width: 720px;
  margin: 0 auto;
}

/* Reading-instructions checklist, shown above .speech-bubble-title when
   readingInstructions is passed (see speech-bubble-text.hbs). Bordered
   box so it reads as a distinct callout; generous margin-bottom is what
   separates it from the title below. Border color follows the same
   next-chapter-shade rule as .exercise-label's tooltip: the
   --next-chapter-color custom property is set by the
   .reading-instructions--capitulo-N modifiers below (chapterNumber + 1,
   capped at capitulo-5 — see nextCapituloNumber in src/app.js), not
   hardcoded per chapter. position:relative anchors the B.1 exercise-label
   rendered inside it, top-left, same row as the read icon on the right
   (.ejercicio-escucha-header/.ejercicio-escucha-icons, reused directly
   from the A.2–A.6 cards' own left/right split). */
.reading-instructions {
  position: relative;
  max-width: 720px;
  margin: 0 auto 2.5rem;
  padding: 0.75rem 1.5rem 2rem;
  border: 1px solid var(--next-chapter-color, var(--text-on-terracotta));
  border-radius: var(--radius);
  color: var(--text-on-terracotta);
}

.reading-instructions--capitulo-2 {
  --next-chapter-color: var(--capitulo-2);
}

.reading-instructions--capitulo-3 {
  --next-chapter-color: var(--capitulo-3);
}

.reading-instructions--capitulo-4 {
  --next-chapter-color: var(--capitulo-4);
}

.reading-instructions--capitulo-5 {
  --next-chapter-color: var(--capitulo-5);
}

/* Spacing before the checklist below — .ejercicio-escucha-header itself
   relies on its parent's flex gap for this everywhere else (A.2–A.6's
   .ejercicio-escucha), but .reading-instructions is a plain block
   container with no gap of its own, so this box needs its own explicit
   margin (same reasoning as .comunica-instructions .ejercicio-escucha-header).
   Kept small — the 64px icon row above already takes up a lot of this
   box's height relative to its short 3-line list, so a bigger margin
   here read as a big dead gap down to the text. */
.reading-instructions .ejercicio-escucha-header {
  margin-bottom: 0.25rem;
}

/* Bullet-less list — each item is a flex row so its icon and text align
   on one line regardless of text length. */
.reading-instructions-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.reading-instructions-list li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.reading-instructions-list .material-symbols-outlined {
  font-size: 1.1rem;
}

/* Reading-text heading, shown above the whole list when readingTitle is
   passed. Plain styled text sitting directly on the section's own
   terracotta background — no box, border, or fill of its own. */
.speech-bubble-title {
  max-width: 720px;
  margin: 0 auto 2rem;
  color: var(--text-on-terracotta);
  font-size: 1.75rem;
  font-weight: bold;
  text-align: center;
}

/* Capped and centered within the wider terracotta section, so alternating
   rows nudge the bubble slightly left/right of a shared center column
   (iMessage-style) instead of each row independently spanning the full
   section width. */
.speech-bubble-row {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 1.5rem;
  max-width: 720px;
  margin: 0 auto 2rem;
}

.speech-bubble-row:last-child {
  margin-bottom: 0;
}

.speech-bubble-row:nth-of-type(even) {
  flex-direction: row-reverse;
}

.speech-bubble-photo {
  flex-shrink: 0;
  width: 120px;
  height: 120px;
  border-radius: var(--radius);
  object-fit: cover;
}

/* Border follows the same next-chapter-shade rule as .reading-instructions/
   .exercise-label's tooltip: the --next-chapter-color custom property is
   set by the .speech-bubble-text-box--capitulo-N modifiers below
   (chapterNumber + 1, capped at capitulo-5 — see nextCapituloNumber in
   src/app.js), not hardcoded per chapter. Falls back to the neutral
   --border-light grey if a caller ever omits the modifier. */
.speech-bubble-text-box {
  position: relative;
  flex: 1;
  max-width: 65ch;
  padding: 1.25rem;
  border: 1px solid var(--next-chapter-color, var(--border-light));
  border-radius: var(--radius);
  background: #fff;
}

.speech-bubble-text-box--capitulo-2 {
  --next-chapter-color: var(--capitulo-2);
}

.speech-bubble-text-box--capitulo-3 {
  --next-chapter-color: var(--capitulo-3);
}

.speech-bubble-text-box--capitulo-4 {
  --next-chapter-color: var(--capitulo-4);
}

.speech-bubble-text-box--capitulo-5 {
  --next-chapter-color: var(--capitulo-5);
}

.speech-bubble-text {
  margin: 0;
  line-height: 1.5;
}

/* Speech-bubble tail: a small square rotated 45deg, half-overlapping the
   box edge facing the photo. Two of its four borders (the ones facing
   outward, away from the box) match the box's own border, so it reads as
   a pointed continuation of the box rather than a separate shape; the
   other two sides are borderless so they disappear against the box's own
   background where they overlap it. Same --next-chapter-color (falling
   back to --border-light) as the box's own border above, so the tail
   reads as a continuation of the exact same color. */
.speech-bubble-text-box::before {
  content: "";
  position: absolute;
  top: 24px;
  left: -8px;
  width: 16px;
  height: 16px;
  background: #fff;
  border-left: 1px solid var(--next-chapter-color, var(--border-light));
  border-bottom: 1px solid var(--next-chapter-color, var(--border-light));
  transform: rotate(45deg);
}

/* Even rows: photo is on the right (after row-reverse), so the tail moves
   to the box's right edge and points the opposite way. */
.speech-bubble-row:nth-of-type(even) .speech-bubble-text-box::before {
  left: auto;
  right: -8px;
  border-left: none;
  border-bottom: none;
  border-right: 1px solid var(--next-chapter-color, var(--border-light));
  border-top: 1px solid var(--next-chapter-color, var(--border-light));
}

/* Placed after the rules above (not merged into the earlier 600px query)
   so it wins on source order: an equal-specificity override earlier in
   the file would lose to .speech-bubble-row:nth-of-type(even) above it. */
@media (max-width: 600px) {
  .speech-bubble-row,
  .speech-bubble-row:nth-of-type(even) {
    flex-direction: column;
  }

  /* .speech-bubble-row's own align-items:flex-start (base rule above)
     left the fixed-width photo stuck flush left once stacked in a
     column — the text box next to it stays full-width regardless (a
     paragraph naturally wraps to fill the available space), so only the
     photo needs its own override to center over it. */
  .speech-bubble-photo {
    align-self: center;
  }

  .speech-bubble-text-box::before {
    display: none;
  }
}

/* ==========================================================================
   Alternating image/text reading rows (see imagen-texto-alterno.hbs)
   Second Section B format, alongside speech-bubble-text.hbs's chat-bubble
   layout above — a lesson picks whichever fits its content; neither rule
   set depends on the other. DOM order is always thumbnail-then-text; CSS
   nth-child alone flips the visual side on even rows, no per-item
   branching in the template.
   ========================================================================== */
/* Matches .speech-bubble-box's own max-width/centering exactly, so both
   Section B formats occupy the same column width regardless of which one
   a lesson uses. */
.alterno-box {
  position: relative;
  max-width: 720px;
  margin: 0 auto;
}

/* Rows live in their own wrapper (not direct siblings of the optional
   .reading-instructions/.speech-bubble-title above) purely so the
   nth-child alternation below always starts clean on row 1 — it never has
   to account for whatever optional, non-row content happens to precede
   it. */
.alterno-rows {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.alterno-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 1.5rem;
}

/* Odd rows (1st, 3rd, ...): thumbnail-then-text in DOM order already reads
   image-left/text-right, so nothing to flip. Even rows: row-reverse swaps
   the visual side only — DOM order (and so reading/tab order) is
   untouched. */
.alterno-row:nth-child(even) {
  flex-direction: row-reverse;
}

/* Square thumbnail button — no default button chrome, just a clickable
   frame around the image (see public/js/imagen-texto-alterno.js for the
   click-to-expand behavior). Fixed size + overflow:hidden is what lets the
   image scale up on hover below without pushing the row's own layout
   around — the button's own box stays put; only the image inside it grows
   and gets clipped back to that box's (rounded) edges. */
.alterno-thumb-btn {
  flex-shrink: 0;
  display: block;
  position: relative;
  overflow: hidden;
  padding: 0;
  border: none;
  border-radius: var(--radius);
  background: none;
  cursor: pointer;
}

/* transform (not width/height) so this is a cheap, GPU-composited
   animation rather than one that reflows layout on every frame. Scaling
   the img itself, not its .alterno-thumb-btn wrapper, is what makes the
   wrapper's own overflow:hidden clip the zoomed image back to the
   original frame instead of the whole frame growing. Hover- and
   focus-visible-triggered (not the wrapper's own :hover, which would
   include the moment the mouse first lands on its padding/border) so
   keyboard focus gets the same "this is clickable" affordance as a mouse
   hover. */
.alterno-thumb {
  display: block;
  width: 180px;
  height: 180px;
  border-radius: var(--radius);
  object-fit: cover;
  transition: transform 250ms ease;
}

.alterno-thumb-btn:hover .alterno-thumb,
.alterno-thumb-btn:focus-visible .alterno-thumb {
  transform: scale(1.08);
}

/* Same 65ch measure as .speech-bubble-text-box, so both Section B formats
   wrap body text at the same readable width. */
.alterno-text {
  flex: 1;
  max-width: 65ch;
}

.alterno-paragraph {
  margin: 0 0 1rem;
  color: var(--amber-text);
  line-height: 1.5;
}

/* Overrides .speech-bubble-title's own default (--text-on-terracotta) only
   inside this reading format — that class is shared with
   speech-bubble-text.hbs's chat-bubble format (Lección 1's own reading
   title), which should keep its original color untouched. */
.alterno-box .speech-bubble-title {
  color: var(--amber-text);
}

.alterno-paragraph:last-child {
  margin-bottom: 0;
}

@media (max-width: 600px) {
  .alterno-row,
  .alterno-row:nth-child(even) {
    flex-direction: column;
  }

  .alterno-thumb-btn {
    align-self: center;
  }
}

/* Full-screen click-to-expand overlay. Same fixed full-viewport
   dark-backdrop pattern as .modal-overlay (sidebar nav), but centers a
   single image instead of a side panel — clicking the backdrop itself
   (not the image) closes it, same as that overlay (see
   public/js/imagen-texto-alterno.js). z-index clears the sidebar overlay
   (100) so opening an image while the sidebar happens to be open still
   shows the image on top. [hidden] (not a class toggle) since visibility
   is the only thing this overlay ever needs to transition. */
.alterno-overlay {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 2rem;
  background: rgba(0, 0, 0, 0.85);
}

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

/* Natural aspect ratio, never cropped — constrained to fit any viewport via
   max-width/max-height rather than a fixed box. */
.alterno-overlay-image {
  display: block;
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--radius);
}

.alterno-overlay-close {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
  cursor: pointer;
}

.alterno-overlay-close .material-symbols-outlined {
  font-size: 28px;
}

/* ==========================================================================
   Custom audio player (see audio-player.hbs / public/js/audio-player.js)
   A hidden native <audio> element driven entirely by this UI — never the
   browser's own <audio controls>. One clean horizontal row on desktop; the
   seek bar drops to its own full-width row as space runs out, so the
   transport controls and time/speed readouts stay legible instead of just
   shrinking in place.
   ========================================================================== */
/* transparent (not a card of its own color) so the player reads as part of
   the reading text it sits in — whatever chapter-color background its
   container has (e.g. .alterno-box inside .seccion-lectura) shows straight
   through, with no separate white box to reconcile against it. max-width
   + auto margins inset it slightly narrower than its container (e.g.
   .alterno-box's own 720px text column) rather than spanning it edge to
   edge.
   --current-chapter-color/--next-chapter-color are declared here (by the
   --current-capitulo-N/--capitulo-N modifiers below) rather than on the
   individual controls that use them, so every descendant — the speed
   select's background+border, the seek bar's inactive track — reads off
   the same two values instead of each needing its own copy of this
   chapter/next-chapter logic. */
.audio-player {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  max-width: calc(100% - 2rem);
  margin: 0 auto 2rem;
  padding: 0.75rem 1.25rem;
  background: transparent;
  border-radius: var(--radius);
}

.audio-player--current-capitulo-1 {
  --current-chapter-color: var(--capitulo-1);
}

.audio-player--current-capitulo-2 {
  --current-chapter-color: var(--capitulo-2);
}

.audio-player--current-capitulo-3 {
  --current-chapter-color: var(--capitulo-3);
}

.audio-player--current-capitulo-4 {
  --current-chapter-color: var(--capitulo-4);
}

.audio-player--capitulo-2 {
  --next-chapter-color: var(--capitulo-2);
}

.audio-player--capitulo-3 {
  --next-chapter-color: var(--capitulo-3);
}

.audio-player--capitulo-4 {
  --next-chapter-color: var(--capitulo-4);
}

.audio-player--capitulo-5 {
  --next-chapter-color: var(--capitulo-5);
}

.audio-player-audio {
  display: none;
}

/* Circular play/pause toggle, far left. Both icons always sit in the DOM
   (see audio-player.hbs); only one is ever displayed at a time via
   .is-playing below, toggled in public/js/audio-player.js — CSS owns the
   swap, JS only owns the state. */
.audio-player-toggle {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--audio-accent);
  color: #fff;
  cursor: pointer;
  transition:
    transform 150ms ease,
    background-color 150ms ease;
}

.audio-player-toggle:hover {
  transform: scale(1.05);
}

.audio-player-toggle:active {
  transform: scale(0.96);
}

.audio-player-icon {
  width: 17px;
  height: 17px;
  /* Play triangle's own visual center sits slightly left of the glyph's
     box (all its area is left of the tip) — nudges it right so it reads
     as centered inside the circular button instead of the button. */
  margin-left: 2px;
  fill: currentColor;
}

.audio-player-icon--pause {
  display: none;
  margin-left: 0;
}

.audio-player-toggle.is-playing .audio-player-icon--play {
  display: none;
}

.audio-player-toggle.is-playing .audio-player-icon--pause {
  display: block;
}

/* Seek bar — a heavily restyled native <input type="range">, not a
   from-scratch custom control: it gives click-to-seek, drag, and full
   keyboard support (arrow keys, Home/End, Page Up/Down) for free, plus
   slider semantics screen readers already understand. The played portion
   is painted via a background gradient whose stop position
   public/js/audio-player.js updates on every frame while playing
   (Chrome/Safari/Edge read the element's own background through the
   track); Firefox instead uses ::-moz-range-progress below, which
   resizes to the value automatically with no JS help needed. The inactive
   track uses --next-chapter-color (declared on .audio-player above) —
   same accent as the speed control's border — instead of a plain grey, so
   both read as the same "next chapter" preview color; JS references the
   variable by name rather than a literal hex, so it never needs to know
   which chapter is actually active. */
.audio-player-seek {
  flex: 1 1 160px;
  min-width: 0;
  height: 6px;
  margin: 0;
  border-radius: 999px;
  background: linear-gradient(
    to right,
    var(--audio-accent) 0%,
    var(--next-chapter-color, var(--capitulo-2)) 0%
  );
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.audio-player-seek:focus-visible {
  outline: 2px solid var(--audio-accent);
  outline-offset: 3px;
}

/* Transparent so the input's own background gradient above shows through
   as the track — this pseudo-element only needs to give the track its
   height/shape. */
.audio-player-seek::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: transparent;
}

/* margin-top centers the 16px thumb on the 6px track: (6 - 16) / 2. */
.audio-player-seek::-webkit-slider-thumb {
  width: 16px;
  height: 16px;
  margin-top: -5px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--audio-accent);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.audio-player-seek::-moz-range-track {
  height: 6px;
  border-radius: 999px;
  background: var(--next-chapter-color, var(--capitulo-2));
}

.audio-player-seek::-moz-range-progress {
  height: 6px;
  border-radius: 999px;
  background: var(--audio-accent);
}

.audio-player-seek::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--audio-accent);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
  cursor: pointer;
}

/* Background follows the *current* chapter's own shade
   (--current-chapter-color, declared on .audio-player above) — the same
   terracotta the rest of the page is already in, unlike
   .reading-instructions/.exercise-label's border-only next-chapter
   treatment. Border instead uses --next-chapter-color (also declared on
   .audio-player, same modifier pattern as .reading-instructions elsewhere
   in this file) as a preview accent, so the two colors read as "where we
   are" (fill) vs "where we're headed" (outline) rather than being the
   same shade repeated twice — this is also the seek bar's inactive-track
   color above, so both controls preview the next chapter consistently.
   Both fall back to chapter 1/2 if a caller ever omits chapterNumber. */
.audio-player-speed {
  flex-shrink: 0;
  padding: 0.35rem 1.5rem 0.35rem 0.6rem;
  border: 1px solid var(--next-chapter-color, var(--capitulo-2));
  border-radius: 8px;
  background: var(--current-chapter-color, var(--capitulo-1));
  color: var(--amber-text);
  font-size: 0.9rem;
  cursor: pointer;
}

.audio-player-speed:focus-visible {
  outline: 2px solid var(--audio-accent);
  outline-offset: 2px;
}

.audio-player-time {
  flex-shrink: 0;
  min-width: 88px;
  color: var(--amber-text);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

@media (max-width: 600px) {
  /* Seek bar claims its own full-width row — it's the one control that
     actually needs the width; button + speed + time still fit comfortably
     on the row above it even at narrow phone widths without the label
     that used to also compete for that space. */
  .audio-player-seek {
    order: 10;
    flex-basis: 100%;
  }
}

/* ==========================================================================
   Section-title badge (see section-title-badge.hbs)
   Reusable label straddling the top boundary of whatever section it's
   placed in. Requires that section to have position: relative — the badge
   sits on that section's own top edge, only 30% overlapping the color
   above it, with the majority (70%) in the section's own color below.
   Square (no border-radius), solid-fill — distinct from
   .speech-bubble-title's plain unboxed text look.
   ========================================================================== */
.section-title-badge {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 1;
  padding: 0.5rem 1.5rem;
  transform: translate(-50%, -30%);
  background: var(--text-on-terracotta);
  color: #fff;
  font-size: 2.5rem;
  font-weight: bold;
  white-space: nowrap;
}

/* Used when there's no adjacent content section above to straddle into
   (see the noOverlap doc comment in section-title-badge.hbs) — drops the
   upward overlap entirely so the badge sits fully within its own
   section's color instead of poking into whatever's above it. */
.section-title-badge--no-overlap {
  transform: translate(-50%, 0%);
}

/* ==========================================================================
   Exercise numbering label (see exercise-label.hbs)
   A.N/B.N label + copy-link icon, always top-left via position: absolute
   — every caller gives its own element position: relative so this
   anchors there regardless of whatever else (icons, headers) also sits
   in that element. See public/js/exercise-label.js for the click (copy
   link + pushState) and load-time (scroll to matching hash) behavior.
   Label text + icon are static dark terracotta, matching body text — no
   hover effect of their own. Only the icon reacts on hover (see
   .exercise-label-copy below); the --next-chapter-color custom property
   set by the .exercise-label--capitulo-N modifiers below is used purely
   for the copy-icon's tooltip border, not for the label's own color.
   ========================================================================== */
.exercise-label {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  color: var(--text-on-terracotta);
  font-size: 1.1rem;
  font-weight: bold;
}

/* Next-chapter shade modifiers (see nextCapituloNumber in src/app.js) —
   only one of these ever applies per instance. Sets a custom property
   rather than `color` — consumed by .exercise-label-copy's tooltip
   border below, so the tooltip's accent still follows the next
   chapter's shade even though the label/icon itself no longer does. */
.exercise-label--capitulo-2 {
  --next-chapter-color: var(--capitulo-2);
}

.exercise-label--capitulo-3 {
  --next-chapter-color: var(--capitulo-3);
}

.exercise-label--capitulo-4 {
  --next-chapter-color: var(--capitulo-4);
}

.exercise-label--capitulo-5 {
  --next-chapter-color: var(--capitulo-5);
}

/* Icon button: transparent, no border — color comes entirely from
   .exercise-label's own `color` via inheritance/currentColor. position:
   relative anchors the tooltip + its triangle (below) precisely on the
   icon rather than the wider label. The hover "pop" (scale + lift) is a
   transform only, so it never shifts the label text next to it. */
.exercise-label-copy {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
  transition: transform 150ms ease;
}

.exercise-label-copy:hover {
  transform: scale(1.15) translateY(-2px);
}

.exercise-label-copy .material-symbols-outlined {
  font-size: 1.4rem;
}

/* Copy-link tooltip, shown above the icon on hover. Static Danish label,
   not tied to `label`/`scrollId` since it always describes the same
   action. Border color comes from --next-chapter-color (set by the
   .exercise-label--capitulo-N modifiers above); falls back to the
   standard dark terracotta if a caller ever omits that modifier. */
.exercise-label-copy::after {
  content: "Kopier link til øvelsen";
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  z-index: 10;
  transform: translateX(-50%);
  padding: 0.4rem 0.75rem;
  border: 2px solid var(--next-chapter-color, var(--text-on-terracotta));
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
  color: var(--text-on-terracotta);
  font-size: 0.8rem;
  font-weight: normal;
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: opacity 150ms ease;
}

/* Tooltip's downward-pointing tail: same rotated-square technique as
   .speech-bubble-text-box::before, just pointing down at the icon
   instead of sideways at a photo — the square straddles the tooltip's
   own bottom edge, and the two borders on its outward-facing (bottom
   and right) sides match the tooltip's border and background so it
   reads as one continuous bubble. */
.exercise-label-copy::before {
  content: "";
  position: absolute;
  bottom: calc(100% + 4px);
  left: 50%;
  z-index: 9;
  width: 12px;
  height: 12px;
  transform: translateX(-50%) rotate(45deg);
  border-right: 2px solid var(--next-chapter-color, var(--text-on-terracotta));
  border-bottom: 2px solid var(--next-chapter-color, var(--text-on-terracotta));
  background: #fff;
  opacity: 0;
  visibility: hidden;
  transition: opacity 150ms ease;
}

.exercise-label-copy:hover::after,
.exercise-label-copy:hover::before {
  opacity: 1;
  visibility: visible;
}

/* Toast shown by exercise-label.js after a successful clipboard copy.
   Fades in/out via the .visible class the script toggles; the element
   itself is created and removed by the script, not present in markup. */
.exercise-label-toast {
  position: fixed;
  left: 50%;
  bottom: 2rem;
  z-index: 100;
  transform: translateX(-50%);
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius);
  background: var(--text-on-terracotta);
  color: #fff;
  font-weight: bold;
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}

.exercise-label-toast.visible {
  opacity: 1;
}

/* ==========================================================================
   Comunica section (see leccion1.hbs) — reuses .seccion-escucha for its
   white bg/terracotta-box scheme, but its instructions+questions box is
   its own component (.comunica-instructions below) rather than reusing
   .reading-instructions/-list: unlike B.1's box, this one is solid
   terracotta (matching the vocab boxes below it) instead of
   border-only/next-chapter-shade — text/icons stay the standard dark
   terracotta throughout though, same as every other terracotta box on
   the site (.video-box, .ejercicio-escucha, .vocab-support-box, etc.).
   ========================================================================== */

/* Single box holding both the task instructions and the closing-task
   questions — one element, not two, so their "questions are subordinate
   to the instructions" relationship has to come from spacing/indentation
   inside it (see .comunica-questions-list below) rather than being two
   separate boxes. Solid --capitulo-1 fill (hardcoded, same as
   .vocab-support-box/.video-box/etc. elsewhere on this page) instead of
   .reading-instructions' border-only treatment; color here is the
   inherited base color both child lists key off. */
.comunica-instructions {
  position: relative;
  max-width: 720px;
  margin: 0 auto;
  padding: 2rem;
  padding-top: 0.75rem;
  padding-bottom: 3rem;
  border-radius: var(--radius);
  background: var(--capitulo-1);
  color: var(--text-on-terracotta);
}

/* Icon-header row (C.1 label overlaid top-left via .exercise-label's own
   absolute positioning, right-side icon slot via .ejercicio-escucha-icons
   — same left/right split as every other numbered card). Scoped to this
   box specifically, not a change to .ejercicio-escucha-header itself,
   since that class's other use (A.2–A.6) already gets its spacing from
   its parent's flex gap instead. Kept small now that the icon slot is
   actually filled (see .ejercicio-escucha-icons:empty below) — the 64px
   icon row itself already provides plenty of height, so the old 2rem
   margin (sized back when this row was empty) read as a big dead gap
   down to the Presentación heading, same issue as .reading-instructions
   had. */
.comunica-instructions .ejercicio-escucha-header {
  margin-bottom: 0.5rem;
}

/* .ejercicio-escucha-icons normally reserves 64px (min-height) so a future
   icon can slot in without shifting layout — but until Comunica actually
   has an icon, that reserved space plus the header's own margin-bottom
   above just reads as a big dead gap above the Presentación title. :empty
   zeroes it out only while the div has no icon inside; the moment a real
   <img> is added here it stops being :empty and the 64px reservation
   kicks back in automatically, so no other change is needed then. */
.comunica-instructions .ejercicio-escucha-icons:empty {
  min-height: 0;
}

/* Space between the Presentación title and the instructions list right
   below it — .ejercicio-escucha-heading's own margin:0 relies on a flex
   gap for spacing everywhere else (see A.2–A.6's .ejercicio-escucha), but
   .comunica-instructions is a plain block container with no gap of its
   own, so this box needs its own explicit margin. */
.comunica-instructions .ejercicio-escucha-heading {
  margin-bottom: 1rem;
}

/* Bullet-less task-instruction list — identical structure to
   .reading-instructions-list (arrow_forward icon + flex row per item),
   just under its own class since this box is a solid terracotta fill
   rather than .reading-instructions' bordered/white-background look. */
.comunica-instructions-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.comunica-instructions-list li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.comunica-instructions-list .material-symbols-outlined {
  font-size: 1.1rem;
}

/* Closing-task questions — sits between the instructions list and the
   ANALOG/print line below (see .comunica-print-link), inside the same
   box. margin-top (the box's own flex/block flow has no gap of its own)
   is the spacing separating it from the instructions above; padding-left
   indents the list further than .comunica-instructions-list's icon+gap
   so it reads as nested/subordinate, not a sibling of equal weight.
   Plain browser bullets (not the arrow-icon treatment) are the visual
   cue that this is a different, subordinate list. */
.comunica-questions-list {
  margin: 1.5rem 0 0;
  padding-left: 3rem;
  color: var(--text-on-terracotta);
}

.comunica-questions-list li {
  margin-bottom: 0.5rem;
}

.comunica-questions-list li:last-child {
  margin-bottom: 0;
}

.comunica-questions-list li::marker {
  color: var(--text-on-terracotta);
}

/* Numbered (1, 2, ...) task list — alternative to
   .comunica-instructions-list/.comunica-questions-list's single-list-plus-
   single-list pairing above, for a Comunica exercise made of several
   distinct tasks that each need their own guiding questions (see
   data/leccion03.js's comunicaTasks). Indented like
   .comunica-questions-list rather than flush with
   .comunica-instructions-list's icon+gap, for the same "subordinate to
   the box's own heading" reason. */
.comunica-tasks-list {
  margin: 1.5rem 0 0;
  padding-left: 1.5rem;
  color: var(--text-on-terracotta);
}

.comunica-tasks-list > li {
  margin-bottom: 1.25rem;
}

.comunica-tasks-list > li:last-child {
  margin-bottom: 0;
}

.comunica-tasks-list > li::marker {
  font-weight: bold;
}

.comunica-task-instruction {
  margin: 0;
}

/* In-text scroll link (e.g. "A-opgaverne"/"B-teksten" — see
   data/leccion03.js and the data-scroll-to click handler in
   public/js/exercise-label.js). Reads as part of the same sentence, not a
   differently-styled link: color:inherit overrides the browser's default
   blue/visited-purple, and only the underline + pointer cursor signal
   it's clickable. */
.comunica-inline-link {
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* "task.question"-numbered (1.1, 1.2, ...) guiding questions for one task
   — same nested/subordinate indentation as .comunica-questions-list, just
   one level deeper since it now nests inside a numbered task instead of
   sitting directly in the box. list-style:none since the number is
   written out as its own element (see .comunica-task-question-number)
   rather than a native ::marker — the "1.1" format isn't something
   list-style-type can produce, unlike the plain digits/letters used
   elsewhere on this page. */
.comunica-task-questions {
  margin: 0.5rem 0 0;
  padding-left: 1.5rem;
  list-style: none;
  color: var(--text-on-terracotta);
}

.comunica-task-questions li {
  margin-bottom: 0.25rem;
}

.comunica-task-questions li:last-child {
  margin-bottom: 0;
}

.comunica-task-question-number {
  font-weight: bold;
}

/* Closing wrap-up line after the numbered tasks (see comunicaClosing in
   data/leccion03.js) — plain paragraph, same margin-top-only spacing
   pattern as .comunica-tasks-list above it. */
.comunica-closing {
  margin: 1.5rem 0 0;
}

/* "ANALOG: Print øvelsen!" — last thing in the box, below the questions.
   Deliberately breaks from the lists' look above it (no arrow-icon/disc
   bullet, bold, underlined) so it doesn't read as another list item; the
   top border (translucent dark terracotta, since a solid
   var(--text-on-terracotta) line would be too heavy) is its separator
   from the questions above — margin-top alone wouldn't visually detach
   it. */
.comunica-print-link {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 0.5rem;
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(74, 27, 12, 0.35);
  color: var(--text-on-terracotta);
  font-weight: bold;
  text-decoration: underline;
}

/* Comunica vocab-support boxes — unlike .exercise-grid--wide (a fixed
   2-column grid that stretches each card to fill its column, used by the
   A.2–A.6 cards above), these wrap as a flex row so the boxes sit at
   their own content-driven width and are centered as a group, with
   .vocab-support-box's flex-basis/max-width giving ~2 per row on
   desktop/tablet and a lone last box (5 categories, an odd count)
   centered on its own row instead of stretched full-width. */
.vocab-support-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
}

.vocab-support-box {
  flex: 1 1 300px;
  max-width: 480px;
  padding: 2rem;
  border-radius: var(--radius);
  background: var(--capitulo-1);
}

.vocab-support-label {
  margin: 0 0 0.75rem;
  color: var(--text-on-terracotta);
  text-align: center;
}

.vocab-word-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Each word: same amber fill/border/text as the Vocabulario exercise's
   Spanish-word chips (.c04Flex-element's --amber-bg/--amber-text) — a
   different component (no drag/select behavior here, just a hover
   tooltip), so it's its own class rather than reusing that one directly.
   position: relative anchors the tooltip below. */
.vocab-word {
  position: relative;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--amber-text);
  border-radius: var(--radius);
  background: var(--amber-bg);
  color: var(--amber-text);
}

/* Hover tooltip — same mechanic as .exercise-label-copy's tooltip
   (border + box-shadow bubble above, rotated-square triangle pointing
   down at the word), border color swapped to --amber-text to tie it to
   the word chip instead of a chapter shade. content: attr(data-tooltip)
   reads the per-word Spanish translation (or the "check your notes"
   message) set on the <li> in leccion1.hbs, so no per-word CSS is
   needed. max-width + normal wrapping (not nowrap, unlike the shorter
   copy-link tooltip) since some translations run long. */
.vocab-word::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  z-index: 10;
  transform: translateX(-50%);
  width: max-content;
  max-width: 220px;
  padding: 0.4rem 0.75rem;
  border: 2px solid var(--amber-text);
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
  color: var(--text-on-terracotta);
  font-size: 0.8rem;
  font-weight: normal;
  text-align: center;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  transition: opacity 150ms ease;
  pointer-events: none;
}

.vocab-word::before {
  content: "";
  position: absolute;
  bottom: calc(100% + 4px);
  left: 50%;
  z-index: 9;
  width: 12px;
  height: 12px;
  transform: translateX(-50%) rotate(45deg);
  border-right: 2px solid var(--amber-text);
  border-bottom: 2px solid var(--amber-text);
  background: #fff;
  opacity: 0;
  visibility: hidden;
  transition: opacity 150ms ease;
}

.vocab-word:hover::after,
.vocab-word:hover::before {
  opacity: 1;
  visibility: visible;
}
