/* test-selection.css — the test chooser for one grade at one duration.

   Page-specific only. The shell comes from elsewhere and must NOT be
   duplicated here:
     critical.css  — tokens, reset, @font-face, base body, nav, skip link
     common.css    — ad slots, .page-layout grid, footer
   Tokens live only in critical.css; read them, never redefine them.

   Position in the funnel:
     typing-test.html   1 / 3 / 5 minute duration pages
     grade-selection    8 grade tiles  (grade-selection.css)
     THIS PAGE          the tests available for that grade + duration
     the test itself

   The <head> here is a TEMPLATE preview: one file serves grade 1-8 across all
   three durations, with the title, canonical and schema generated in Twig from
   the URL on live. Anything written here has to hold for all 24 combinations.

   Built one piece at a time; sections get added below as they are made. */

/* ══════════════════════════
   HERO — page heading. Same construction as the heroes on typing-test.html and
   grade-selection.html so all three steps of the funnel read as one family:
   same clamp, same weight, same accent word, same fade-up.

   `tsel` = test-selection, kept short because every class on this page carries
   it. Tokens come from critical.css; none are redefined here.
══════════════════════════ */
.tsel-hero {
  padding: 48px 0 32px;
  text-align: center;
}

.tsel__h1 {
  font-size: clamp(28px, 3.8vw, 52px);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.5px;
  color: #eef6ff;
  text-wrap: balance;            /* keeps "for Grade 1" off a line of its own */
}

.tsel__h1 .c-yellow {
  color: var(--yellow);
}

/* Both halves are Twig variables. nowrap so neither "1 Minute" nor "Grade 1"
   can split across a line break — a lone "1" at the end of a line reads as a
   list number, not as part of the phrase. */
.tsel__h1-length,
.tsel__h1 .c-yellow {
  white-space: nowrap;
}

/* H1 fades up on load; the grade floats in just after it settles. .float-in
   itself lives in critical.css — only its delay is overridden. */
.tsel__h1--anim {
  opacity: 0;
  transform: translateY(20px);
  animation: tselHeadIn 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.1s forwards;
}
.tsel__h1--anim .float-in {
  animation-delay: 0.55s;
}

/* CMS region — the paragraph arrives from TinyMCE with no class, so every text
   property sits on the WRAPPER and inherits down. Anything that must target an
   element uses a descendant selector. Identical construction to .grade__intro
   and .test__intro, so the three heroes read as one family.

   The BLOCK is centred under the heading; the TEXT inside runs left. Centred
   text gives two ragged edges, so uneven line lengths show on both sides at
   once; left-aligning gives one straight edge to sit against. */
.tsel__intro {
  max-width: 68ch;
  margin: 14px auto 0;
  text-align: left;
  font-size: clamp(15px, 1.5vw, 18px);
  font-weight: 600;
  line-height: 1.9;
  color: var(--text-dim);
  opacity: 0;
  animation: tselHeadIn 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.75s forwards;
}
/* Direct child, so the measure cap can never reach a <p> the editor drops
   inside a table cell or a list. */
.tsel__intro > p { text-wrap: pretty; }   /* no lone word on the last line */
.tsel__intro > p + p { margin-top: 12px; }
.tsel__intro strong { color: var(--text-strong); }
.tsel__intro a {
  color: var(--yellow);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.tsel__intro a:hover { color: #ffffff; }

/* Defensive: if an editor picks "Heading 1" in TinyMCE the page ends up with
   two h1s. The real fix is restricting block_formats in the editor — this only
   stops the second one looking broken until then. */
.tsel__intro h1,
.tsel__intro h2 {
  font-size: clamp(20px, 2.2vw, 28px);
  font-weight: 700;
  line-height: 1.25;
  color: #eef6ff;
}

@keyframes tselHeadIn {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* The heading is decoration on a page you came to in order to pick a test. */
@media (prefers-reduced-motion: reduce) {
  .tsel__h1--anim,
  .tsel__intro {
    opacity: 1;
    transform: none;
    animation: none;
  }
}

@media (max-width: 640px) {
  .tsel-hero { padding: 28px 0 20px; }
  /* At phone width the block already fills the column, so there is no centred
     box left to preserve -- and short lines make a ragged left edge more
     obvious than the raggedness it was fixing. */
  .tsel__intro {
    text-align: center;
    line-height: 1.75;
  }
}

/* ══════════════════════════
   SECTION HEAD — heading + sub, animated as one block, the same grouping as
   .grades__head on grade-selection.html and .section-picker__head on the
   lesson picker.
══════════════════════════ */
.tsel-tests {
  padding: 8px 0 48px;
}

.tsel__head {
  margin-bottom: 26px;
  text-align: center;
  opacity: 0;
  animation: tselHeadIn 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.85s forwards;
}

.tsel__h2 {
  margin: 0;
  font-size: clamp(20px, 2.4vw, 28px);
  font-weight: 700;
  letter-spacing: -0.2px;
  color: #eef6ff;
}

.tsel__sub {
  margin: 10px 0 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.6;
  color: var(--text-dim);
}

/* ══════════════════════════
   TEST GRID — the same card as .grade-card on grade-selection.html, three
   across, at a shorter 125px instead of 180px.

   Why the same card and not a compact row: the grade page one step back is a
   grid of icon-over-label tiles, and a child who has just used it should not
   have to learn a second way of reading a list of choices. Same surface, same
   divider, same hover, same neutral icon — only the height and the icon size
   come down, because there are 21 of these rather than 8 and they do not need
   to be as loud.

   min-height, NOT a fixed height. No label wraps at three columns, but the
   test names come from the database and a longer one in a higher grade must
   not be cropped. Grid stretches every card in a row to match its tallest, so
   a wrapped label lifts its whole row evenly and the grid stays rectangular.
══════════════════════════ */

/* THREE columns, not four. Three gives each card 285px of width instead of
   211px, and at 285px every one of the 21 names fits on a single line — at
   four across, three of them broke to two. It also lands 21 items as an exact
   7 x 3, where four across left one card alone on a sixth row.

   The gap is 22px against the grade grid 18px. These cards are wider and
   shorter than the grade tiles, so they read as bands rather than blocks, and
   the extra air is what keeps seven rows of them from running together.

   Nothing here assumes 21 items — the test count differs per grade, so a
   ragged last row still has to survive. */
.test-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.test-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 100%;
  min-height: 125px;
  padding: 18px 16px 14px;
  background: var(--card-bg);
  border: 1px solid var(--card-bdr);
  border-radius: 16px;
  text-align: center;
  text-decoration: none;
  transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
}

/* No tile behind the icon — it sits straight on the card, like .grade-card and
   .sec-card. Neutral, because colour on an icon means a STATE elsewhere in
   this flow (green done, --yellow current) and nothing here has one. */
.test-card__icon {
  display: block;
  color: rgba(255, 255, 255, 0.6);
  transition: transform 0.18s ease;
}
.test-card__icon svg {
  display: block;
  width: 38px;
  height: 38px;
}

/* Label under a divider — icon, rule, name. Same three-part structure as the
   grade tile and the lesson section card. margin-top:auto pins the rule to the
   foot so the dividers line up across a row even when one label wraps.

   16px with 0.4px tracking, matching .grade-card__name exactly. Measured: a
   card offers 250px of usable width and the longest label, "Academic
   Vocabulary Words", comes to 229px at this size — 21px spare, with "Common
   Core Words - Math" close behind at 225px. 17px was the next step up and
   lands at 242px, which is not real headroom, so 16 is the ceiling here.

   If a longer test name in a higher grade ever does wrap, nothing breaks:
   min-height plus the grid row-stretch lifts the whole row evenly. That is
   what min-height is for. */
.test-card__name {
  width: 100%;
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--card-bdr);
  font-size: 16px;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: 0.4px;
  color: rgba(241, 250, 255, 0.85);
}

.test-card:hover {
  transform: translateY(-3px);
  border-color: rgba(219, 238, 255, 0.25);
  background: rgba(255, 255, 255, 0.07);
}
.test-card:hover .test-card__icon { transform: scale(1.06); }

.test-card:focus-visible {
  outline: 2px solid var(--yellow);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .tsel__head {
    opacity: 1;
    transform: none;
    animation: none;
  }
  .test-card,
  .test-card__icon { transition: none; }
  .test-card:hover { transform: none; }
  .test-card:hover .test-card__icon { transform: none; }
}

/* 3 -> 2, the same breakpoint as the grade grid. Three columns at phone width
   leaves about 110px a card, and these names are far longer than "Grade 1". */
@media (max-width: 720px) {
  .test-grid { grid-template-columns: repeat(2, 1fr); gap: 14px; }
  .test-card { min-height: 116px; padding: 16px 12px 12px; gap: 10px; }
  .test-card__icon svg { width: 34px; height: 34px; }
  .test-card__name { padding-top: 10px; font-size: 14px; }
}

/* ══════════════════════════
   SEO BLOCK — the prose panel under the grid. Identical construction to
   .grade-info on grade-selection.html, and for the same reasons:

   Card and placement from .lesson-guide on typing-lesson.html — a --card-bg
   panel with --card-bdr and --r-md, inside col-content directly below the
   picker. It does not break out to full width the way .test-info does on
   typing-test.html; that block only spans the ad column because a four-column
   benchmark table is unreadable at the content measure. No table here.

   Left-aligned text and the accent rule under the h2 come from .test-info
   instead of .lesson-guide, because this block has headings and .lesson-guide
   has one centred paragraph.

   CMS region — the content is authored in TinyMCE and arrives as bare
   h2/h3/p/ul/strong/a with no classes, so every rule targets ELEMENTS through
   the wrapper. A rule hung on a class would never match.
══════════════════════════ */
.tsel-info {
  margin-top: 40px;
}

.tsel-info__inner {
  padding: 36px;
  background: var(--card-bg);
  border: 1px solid var(--card-bdr);
  border-radius: var(--r-md);
  font-size: clamp(15px, 1.5vw, 16px);
  font-weight: 600;
  line-height: 1.8;
  /* NOT --text-dim. That token is white-at-58%, and --card-bg lifts the
     background 5%, so it lands at 5.68:1 here. 0.62 restores it to ~6.2:1 —
     the same correction, for the same reason, as .test-info__inner. */
  color: rgba(255, 255, 255, 0.62);
}

/* h1 is styled defensively in case an editor reaches for it, but the page h1
   is the hero — a second one here is wrong for search and for screen-reader
   navigation. The real fix is limiting TinyMCE block_formats to Heading 2,
   Heading 3 and Paragraph. */
.tsel-info__inner h1,
.tsel-info__inner h2 {
  position: relative;
  padding-bottom: 15px;                /* room for the accent rule */
  font-size: clamp(20px, 2.2vw, 25px);
  font-weight: 800;
  line-height: 1.3;
  color: var(--text-strong);
}

/* A pseudo-element because the heading comes from the CMS and cannot carry
   extra markup. h3 deliberately has no rule — its absence is what separates
   the two heading levels. */
.tsel-info__inner h1::after,
.tsel-info__inner h2::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 46px;
  height: 3px;
  border-radius: 2px;
  background: var(--yellow);
}

.tsel-info__inner h3 {
  font-size: clamp(17px, 1.8vw, 19px);
  font-weight: 800;
  line-height: 1.35;
  color: var(--text-strong);
}

/* Spacing as sibling relationships, not fixed margins on each element: an
   editor can reorder blocks freely, and `> * + *` covers pairs nobody thought
   to enumerate. */
.tsel-info__inner > * + *  { margin-top: 14px; }
.tsel-info__inner > * + h2 { margin-top: 36px; }
.tsel-info__inner > * + h3 { margin-top: 30px; }
.tsel-info__inner > h1 + *,
.tsel-info__inner > h2 + *,
.tsel-info__inner > h3 + * { margin-top: 12px; }

/* The global reset in critical.css sets `ul { list-style: none }`, so a list
   from the CMS arrives with no marker at all — and `li::marker` cannot bring
   one back once list-style is gone. A dash drawn with ::before restores it and
   echoes the heading rule. `ol` is untouched by that reset and keeps its
   numbers: an editor who picks a numbered list wants numbers. */
.tsel-info__inner ul { padding-left: 0; }
.tsel-info__inner ul > li {
  position: relative;
  padding-left: 22px;
}
.tsel-info__inner ul > li::before {
  content: '–';
  position: absolute;
  left: 2px;
  top: 0;
  font-weight: 800;
  color: var(--yellow);
}
.tsel-info__inner ol { padding-left: 22px; }
.tsel-info__inner ol > li::marker { color: var(--yellow); font-weight: 800; }
.tsel-info__inner li + li { margin-top: 8px; }

.tsel-info__inner strong { font-weight: 800; color: var(--text-strong); }
.tsel-info__inner em { font-style: italic; }

.tsel-info__inner a {
  color: var(--yellow);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.tsel-info__inner a:hover { color: #ffffff; }

@media (max-width: 720px) {
  /* 36px of card padding leaves under 290px of text on a 360px phone. */
  .tsel-info { margin-top: 28px; }
  .tsel-info__inner { padding: 24px 18px; }
}
