#sa-widget,
  #sa-widget * {
    box-sizing: border-box;
  }

  #sa-widget * {
    font-family: inherit;
    font-weight: 500;
  }

  #sa-widget button {
    margin: 0;
    padding: 0;
    min-width: 0;
    min-height: 0;
    line-height: normal;
  }

  #sa-widget {
    font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
    color: var(--text);
    width: 100%;
    max-width: 100%;
    margin: 0 auto;
    display: block;
    position: relative;
  }

  #sa-widget {
    --card: #ffffff;
    --text: #16233d;
    --muted: #1f2b45;
    --border: #e6e8ef;
    --primary: #2f6bff;
    --primary-2: #1f52d6;
    --primary-soft: #eef4ff;
    --accent: #10b981;
    --accent-2: #059669;
    --danger: #dc2626;
    --danger-2: #b91c1c;
    --shadow:
      0 1px 2px rgba(16, 24, 40, .05),
      0 2px 6px -1px rgba(16, 24, 40, .05),
      0 20px 34px -22px rgba(31, 43, 69, .30);
    --radius: 13px;
    --card-radius: 13px;
    /* Neutral, very slightly cool grey rather than the old pale blue
       (#EAF1FF). The card sits half on the tinted hero and half on the
       white section below it; a blue-tinted border disappears entirely
       against white, which is what made the bottom of the card look
       like it was floating with no edge. A neutral border reads against
       both. Paired with the layered shadow above: a tight contact
       shadow for the edge, a wide ambient one for lift. */
    --card-border: #e3e8f2;
    --card-border-solid: #3b82f6;
    --overlay: rgba(15, 23, 42, .55);
  }

  #sa-widget .card {
    width: 100%;
    min-height: 500px;
    background: var(--card);
    border-radius: var(--card-radius);
    box-shadow: var(--shadow);
    padding: 1.375rem 1.625rem 1.125rem;
    display: flex;
    flex-direction: column;
    gap: 1.125rem;
    overflow: hidden;
    position: relative;
    border: 1.5px solid var(--card-border-solid);
    margin: 0 auto;
  }

  /* Toggled by openJudgePanel/closeJudgePanel. The judge popover has no
     height cap, so a long entry needs somewhere to go; without this it
     would be clipped at the card edge with nothing to indicate more
     text exists. The status band radiuses its own top corners, so
     lifting the clip costs nothing visually. */
  #sa-widget .card.sa-judge-open {
    overflow: visible;
  }

  #sa-widget .title {
    text-align: left;
    font-family: inherit;
    font-weight: 600;

    font-size: clamp(1rem, 0.79rem + 0.94vw, 1.125rem);

    padding-right: 90px;
    margin: 0px 0 0.1rem;
    color: #16233d;
  }

  #sa-widget .screen {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    min-height: 0;
    flex: 1;
  }

  #sa-widget .hidden {
    display: none !important;
  }

  #lbBackdrop .hidden {
    display: none !important;
  }

  #sa-widget .subtitle {
    text-align: left;
    font-size: 0.9125rem;
    font-weight: 400;
    color: #7a8699;
    margin: 0 0 0.375rem;
    line-height: 1.4;
  }

  #sa-widget .content {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    min-height: 0;
    align-items: flex-start;
    overflow: hidden;
  }

  #sa-widget .col-left,
  #sa-widget .col-mid {
    width: 100%;
    min-width: 0;
  }

  /* Duration + Accent share one row from 521px up, stacked below it. */
  #sa-widget .col-mid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.25rem;
  }

  /* Settings layout: the picker block (difficulty / grade / tier / word
     list) spans the full card width, with Duration + Accent on a single
     row beneath it. The progress strip used to sit in a third column
     (.col-right) inside .content; it is now a full-width band between
     .content and the Start button. Spare card height is absorbed by
     .content (flex: 1), so pickers stay pinned to the top and the
     progress band + CTA stay pinned to the bottom — new elements can be
     added later without re-tuning the layout. */
  @media (min-width: 521px) {
    #sa-widget .content {
      gap: 0.875rem;
      overflow: visible;
      align-items: stretch;
    }
    #sa-widget .col-mid {
      grid-template-columns: 1.4fr 1fr;
      column-gap: 1.75rem;
    }
  }

  #sa-widget .section-label {
    font-size: 0.6975rem;
    letter-spacing: .08em;
    font-weight: 600;
    color: var(--text);
    margin: 0.375rem 0 0.5rem;
  }

  #sa-widget .list {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
  }

  #sa-widget .pill {
    height: 52px;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: #fff;
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0 0.75rem;
    cursor: pointer;
    user-select: none;
    width: 100%;
    transition: transform .12s ease, box-shadow .12s ease, background .12s ease, border-color .12s ease;
  }

  #sa-widget .pill:active {
    transform: scale(.99);
  }

  #sa-widget .pill .icon {
    width: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
  }

  #sa-widget .pill .txt {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
  }

  #sa-widget .pill.active-primary {
    background: var(--primary-soft);
    border-color: var(--primary);
    box-shadow: none;
  }

  #sa-widget .pill.active-primary .txt {
    color: var(--primary-2);
  }

  #sa-widget .pill.active-accent {
    background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
    border-color: transparent;
    /*box-shadow: 0 10px 22px rgba(16, 185, 129, .18);*/
  }

  #sa-widget .pill.active-accent .txt {
    color: #fff;
  }

#sa-widget .duration-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: nowrap;
  width: 100%;
}

#sa-widget .chip {
  flex: 1 1 0;
  min-width: 0;
  height: 48px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--text);
  cursor: pointer;
  user-select: none;
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease, border-color .12s ease;
}

  #sa-widget .chip:active {
    transform: scale(.99);
  }

  #sa-widget .chip.active {
    background: var(--primary-soft);
    border-color: var(--primary);
    color: var(--primary-2);
    box-shadow: none;
  }

  #sa-widget .accent {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    margin-top: 0.125rem;
    flex-wrap: nowrap;
  }

  #sa-widget .flag {
    font-size: 0.9375rem;
    line-height: 1;
  }

  #sa-widget .accent .pill {
    height: 48px;
    justify-content: center;
    gap: 0.5rem;
    padding: 0 0.625rem;
    width: 100%;
  }

  @media (min-width: 521px) {
    /* Placed after the base .list / .pill rules on purpose — an override
       declared before them is silently ignored at equal specificity. */
    #sa-widget .list {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 0.625rem;
    }
    #sa-widget .duration-row .chip {
      height: 40px;
    }
    #sa-widget .accent {
      flex-direction: row;
      gap: 0.5rem;
    }
    #sa-widget .accent .pill {
      flex: 1 1 0;
      width: auto;
      min-width: 0;
      height: 44px;
      padding: 0 0.375rem;
      gap: 0.25rem;
    }
  }

  /* Progress band. Full card width, no fill and no radius — just a
     hairline rule above and below, so the only "cards" on this screen
     are the pickers. The rule under it doubles as the divider above the
     Start button, which is why the CTA needs no wrapper of its own. */
  #sa-widget .progress {
    width: 100%;
    min-width: 0;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    padding: 1.5rem 0;
    display: flex;
    flex-direction: column;
  }

  #sa-widget .progress-grid {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: 0.75rem;
  }

  /* Equal thirds, then left / centre / right text alignment so the outer
     two metrics sit flush with the card's content edges. */
  #sa-widget .metric {
    flex: 1 1 0;
    min-width: 0;
    display: grid;
    gap: 0.5625rem;
    text-align: left;
  }

  #sa-widget .metric:nth-child(2) {
    text-align: center;
  }

  #sa-widget .metric:last-child {
    text-align: right;
  }

  /* Same colour + weight as .section-label so every uppercase micro-label
     on the settings screen (DIFFICULTY / DURATION / ACCENT / GRADE LEVEL /
     TIER and the progress band) reads as one family. */
  #sa-widget .metric .label {
    font-size: 0.625rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--text);
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  #sa-widget .metric .value {
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.05;
    white-space: nowrap;
  }

  #sa-widget .value.primary {
    color: var(--primary-2);
  }

  #sa-widget .value.accuracy {
    color: #0f9d6e;
  }

  #sa-widget .value.orange {
    color: #f97316;
  }

  #sa-widget .flame {
    margin-left: 0rem;
    font-size: 0.9375rem;
    display: inline-flex;
    align-items: center;
    vertical-align: -0.12em;
  }

  #sa-widget .start {
    align-self: center;
    width: 100%;
    height: 55px;
    padding: 0 2.75rem;
    margin: 0;
    border-radius: 13px;
    border: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    background: linear-gradient(180deg, var(--text) 0%, var(--muted) 100%);
    color: #fff;
    font-weight: 600;
    font-size: .99rem;
    cursor: pointer;
    /*box-shadow: 0 4px 12px rgba(47, 107, 255, .28);*/
    transition: filter .12s ease, box-shadow .12s ease, transform .12s ease;
  }

  #sa-widget .start-label {
    line-height: 1;
    font-weight: 600;

  }

  #sa-widget .start-arrow {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    transition: transform .18s ease;
  }

  #sa-widget .start:hover {
    filter: brightness(1.2);
  }

  #sa-widget .start:hover .start-arrow {
    transform: translate(3px, 0px);
  }

  #sa-widget .start:active {
    transform: translateY(1px);
  }

  /* =====================================================================
     TEST SCREEN
     Three zones, no competing boxes: a full-bleed status band pinned to
     the top, one centred focal group (replay circle → input → note →
     tips), and an action row pinned to the bottom behind a full-bleed
     hairline. The status band and the button rule use negative margins
     to cancel .card's horizontal padding, so both run edge to edge like
     real card furniture rather than reading as two more panels.
     ===================================================================== */
  #sa-widget .test-wrap {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 0;
  }

  /* Negative margins mirror .card's padding (1.375rem top / 1.625rem
     sides). Top corners are radiused explicitly rather than relying on
     .card's overflow:hidden — .card switches to overflow:visible below
     521px, and square corners would poke past the card's rounded edge
     there. */
  #sa-widget .status-bar {
    display: flex;
    align-items: center;
    gap: 1.125rem;
    margin: -1.375rem -1.625rem 0;
    padding: 0.8125rem 1.625rem;
    border: 0;
    border-bottom: 1px solid var(--border);
    border-radius: var(--card-radius) var(--card-radius) 0 0;
    background: #fafbfd;
    flex-wrap: nowrap;
    min-width: 0;
  }

  #sa-widget .status-item {
    display: flex;
    align-items: center;
    gap: 0.4375rem;
    min-width: 0;
    white-space: nowrap;
  }

  /* Counters group left, clock pushed right. */
  #sa-widget .status-item.right {
    margin-left: auto;
  }

  #sa-widget .dot {
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: #16a34a;
    flex: 0 0 auto;
  }

  #sa-widget .dot.miss {
    background: #ef4444;
  }

  #sa-widget .status-key {
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 500;
    color: #64748b;
    letter-spacing: .01em;
  }

  #sa-widget .status-val {
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
  }

  #sa-widget .timer-text {
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    letter-spacing: .04em;
    display: inline-flex;
    align-items: center;
  }

  /* Under one minute the clock turns red — the only urgency cue on the
     screen, so it doesn't need a border or a badge to be noticed. */
  #sa-widget .timer-text.low {
    color: #dc2626;
  }

  /* The focal group. flex:1 + centring means it stays optically centred
     between the band and the buttons at any card height, so adding a
     row later (the bee judge already does this) never needs re-tuning. */
  #sa-widget .test-main {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1.875rem;
    padding: 0.5rem 0;
    /* Positioning context for the spelling-bee judge, which sits in the
       top-right corner of this zone rather than in the column flow. */
    position: relative;
  }

  #sa-widget .replay-block {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.925rem;
  }

  #sa-widget .replay-btn {
    width: 78px;
    height: 78px;
    border-radius: 999px;
    border: 0;
    padding: 0;
    background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 8px 20px -8px rgba(15, 23, 42, .45);
    transition: transform .14s ease, filter .14s ease, box-shadow .14s ease;
  }

  #sa-widget .replay-btn .sa-svg {
    width: 30px;
    height: 30px;
  }

  #sa-widget .replay-btn:hover {
    filter: brightness(1.06);
    box-shadow: 0 10px 24px -8px rgba(15, 23, 42, .5);
  }

  #sa-widget .replay-btn:active {
    transform: scale(.96);
  }

  /* Fires on every playback (auto or manual) so the circle visibly
     acknowledges the tap. Replaces the old "Replaying…" text, which
     used to overwrite the correction the user was still reading. */
  #sa-widget .replay-btn.is-playing {
    animation: saReplayPulse .5s ease-out;
  }

  @keyframes saReplayPulse {
    0%   { transform: scale(1); }
    35%  { transform: scale(1.07); }
    100% { transform: scale(1); }
  }

  #sa-widget .replay-caption {
    font-family: inherit;
    font-size: 0.625rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: #94a3b8;
    font-weight: 500;
    text-align: center;
    line-height: 1;
  }

  /* Inherits the card's family (Inter) like every other control —
     the widget previously used a monospace stack here and in the status
     band, which read as a different product. Wide letter-spacing keeps
     a half-typed word easy to check letter by letter without needing a
     second typeface. */
  #sa-widget .input {
    width: 100%;
    height: 72px;
    border-radius: 14px;
    border: 1.5px solid var(--border);
    padding: 0 1rem;
    font-family: inherit;
    font-size: 1.375rem;
    outline: none;
    background: #f8fafc;
    color: var(--text);
    text-align: center;
    letter-spacing: 0.1em;
    font-weight: 500;
    transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
  }

  #sa-widget .input::placeholder {
    color: #b4bfcd;
    font-weight: 500;
    letter-spacing: 0.08em;
  }

  /* State classes, not inline styles. start_test() used to write
     element.style.border directly, which silently outranked every rule
     below and made the wrong/right tints impossible. */
  #sa-widget .input.is-live {
    border-color: var(--primary);
    background: #fff;
  }

  #sa-widget .input.is-live:focus {
    box-shadow: 0 0 0 3px var(--primary-soft);
  }

  #sa-widget .input.is-wrong {
    border-color: #f2b8b8;
    background: #fdeeee;
    box-shadow: none;
  }

  #sa-widget .input.is-right {
    border-color: #a7dfc4;
    background: #edfaf3;
    box-shadow: none;
  }

  /* Reserves its own height so revealing the correction never shifts
     the input or the buttons. */
  #sa-widget .answer-note {
    min-height: 1.125rem;
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.15;
    text-align: center;
    color: #94a3b8;
  }

  #sa-widget .answer-note.is-wrong {
    color: #dc2626;
  }

  #sa-widget .answer-note.is-right {
    color: #0f9d6e;
  }

  #sa-widget .tips-line {
    font-family: inherit;
    font-size: 0.75rem;
    color: #94a3b8;
    text-align: center;
    line-height: 1;
  }

  #sa-widget .tip-key {
    color: var(--text);
    font-weight: 600;
  }

  #sa-widget .tip-sep {
    color: #cbd5e1;
    margin: 0 0.5rem;
  }

  /* Hairline runs edge to edge like the status band, so the action row
     reads as a footer rather than a fifth panel. */
  #sa-widget .buttons {
    display: flex;
    gap: 0.75rem;
    margin: 0 -1.625rem;
    padding: 1rem 1.625rem 0;
    border-top: 1px solid var(--border);
  }

  #sa-widget .btn {
    height: 54px;
    border-radius: 13px;
    border: 0;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.9375rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform .12s ease, filter .12s ease, background .12s ease, border-color .12s ease;
    color: #fff;
  }

  #sa-widget .btn:hover {
    filter: brightness(1.06);
    transform: none;
  }

  #sa-widget .btn:active {
    transform: translateY(1px);
  }

  #sa-widget .btn:disabled {
    opacity: .45;
    cursor: not-allowed;
    box-shadow: none !important;
    filter: saturate(.75);
  }

  #sa-widget .btn:disabled:hover,
  #sa-widget .btn:disabled:active {
    transform: none;
  }

  /* Deliberately lopsided: Check is the action taken on every single
     word, End test is taken once. Equal widths gave them equal weight. */
  #sa-widget .btn-primary {
    flex: 2.4 1 0;
    min-width: 0;
    background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
    box-shadow: 0 4px 11px rgba(47, 107, 255, .22);
  }

  /* Ghost, not red: ending a practice run is a neutral exit, and the
     old danger gradient shouted louder than the primary action. */
  #sa-widget .btn-ghost {
    flex: 1 1 0;
    min-width: 0;
    background: #fff;
    border: 1px solid var(--border);
    color: var(--muted);
    box-shadow: none;
  }

  #sa-widget .btn-ghost:hover {
    filter: none;
    background: #f8fafc;
    border-color: #cbd5e1;
  }

  /* =====================================================================
     RESULTS SCREEN
     One column, four stacked zones: hero (ring + verdict), a single
     four-cell stat strip, the missed-words panel, and a full-bleed
     action footer. The old layout put the missed words in a fixed 240px
     side column, which meant two competing scroll contexts, a panel
     that vanished entirely below 521px, and a duplicate mobile-only
     download button. Stacking removes all three: one column reflows at
     any width, so the breakpoint only has to retune spacing.

     Height discipline: .miss-list is the only flexible zone and it is
     flex-basis 0, so a 40-word run and a 2-word run produce exactly the
     same card height — the list scrolls internally instead of growing
     the card. Every other zone is intrinsically sized.
     ===================================================================== */
  #sa-widget .results-shell {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 1.125rem;
  }

  /* ---- Hero: accuracy ring + verdict --------------------------------- */
  #sa-widget .r-hero {
    display: flex;
    align-items: center;
    gap: 1.125rem;
    flex: 0 0 auto;
  }

  /* The ring is the conic-gradient track; fillResults() rewrites the
     background inline with the score and the band colour. */
  #sa-widget .r-ring {
    width: 88px;
    height: 88px;
    border-radius: 50%;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: conic-gradient(var(--primary) 0% 0%, #e8ecf4 0% 100%);
  }

  #sa-widget .r-ring-inner {
    width: 66px;
    height: 66px;
    border-radius: 50%;
    background: var(--card);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  #sa-widget .r-ring-pct {
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--primary-2);
    line-height: 1;
  }

  #sa-widget .r-ring-label {
    font-size: 0.5rem;
    font-weight: 700;
    color: #94a3b8;
    letter-spacing: .09em;
    margin-top: 0.1875rem;
  }

  #sa-widget .r-hero-text {
    min-width: 0;
    flex: 1 1 auto;
  }

  #sa-widget .r-hero-title {
    font-size: clamp(1.0625rem, 0.86rem + 0.9vw, 1.375rem);
    font-weight: 700;
    color: var(--text);
    line-height: 1.2;
  }

  #sa-widget .r-hero-tip {
    font-size: 0.84375rem;
    font-weight: 400;
    color: #7a8699;
    margin-top: 0.3125rem;
    display: flex;
    align-items: flex-start;
    gap: 0.375rem;
    line-height: 1.4;
  }

  #sa-widget .r-tip-icon {
    display: inline-flex;
    flex: 0 0 auto;
    margin-top: 0.1875rem;
  }

  #sa-widget .r-tip-icon svg {
    width: 13px;
    height: 13px;
  }

  /* Personal-best line. Small on purpose — it is a returning-visitor
     nudge, not a result, so it must not compete with the verdict above
     it or the missed words below it. */
  #sa-widget .r-hero-meta {
    margin-top: 0.4375rem;
    font-size: 0.6875rem;
    font-weight: 500;
    color: #94a3b8;
    letter-spacing: .02em;
    display: flex;
    align-items: center;
    gap: 0.4375rem;
    flex-wrap: wrap;
  }

  #sa-widget .r-hero-meta b {
    color: var(--muted);
    font-weight: 700;
  }

  #sa-widget .r-hero-meta-dot {
    width: 3px;
    height: 3px;
    border-radius: 999px;
    background: #cbd5e1;
    flex: 0 0 auto;
  }

  /* ---- Stat strip ---------------------------------------------------- */
  /* One outlined box divided by 1px gaps showing the container's own
     background, rather than four separate bordered cards. The same rule
     produces the 2x2 arrangement at the mobile breakpoint with no extra
     border bookkeeping — only grid-template-columns changes. */
  #sa-widget .r-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1px;
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: 12px;
    overflow: hidden;
    flex: 0 0 auto;
  }

  #sa-widget .r-stat {
    background: #fafbfd;
    padding: 0.75rem 0.75rem 0.8125rem;
    min-width: 0;
  }

  #sa-widget .r-stat-key {
    font-size: 0.625rem;
    font-weight: 600;
    color: #94a3b8;
    letter-spacing: .11em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  #sa-widget .r-stat-val {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--text);
    line-height: 1.2;
    margin-top: 0.3125rem;
    display: flex;
    align-items: center;
  }

  #sa-widget .r-stat-val.is-correct { color: #0f9d6e; }
  #sa-widget .r-stat-val.is-missed  { color: #dc2626; }

  #sa-widget .r-stat-val .sa-timer-infinity {
    width: 18px;
    height: 18px;
    color: var(--text);
  }

  /* ---- Missed words -------------------------------------------------- */
  /* flex: 1 1 0 (basis zero, not auto) is what keeps the card height
     constant: the list takes the leftover column space and scrolls,
     instead of contributing its content height and pushing the footer
     down. min-height keeps the empty state legible when the card is
     short. */
  #sa-widget .r-miss {
    flex: 1 1 0;
    min-height: 7.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  #sa-widget .r-miss-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    flex: 0 0 auto;
  }

  #sa-widget .r-miss-label {
    font-size: 0.6875rem;
    font-weight: 600;
    color: #94a3b8;
    letter-spacing: .11em;
    text-transform: uppercase;
  }

  #sa-widget .r-miss-label b {
    color: var(--muted);
    font-weight: 700;
  }

  /* Text link, not a filled button. Downloading is an optional follow-up
     to reviewing the list, so it sits beside the list's own label
     instead of taking a full-width slab under it — that slab was also
     the reason the panel needed a duplicate mobile-only copy. */
  #sa-widget .download-btn {
    border: 0;
    background: none;
    padding: 0;
    font-size: 0.78125rem;
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    display: inline-flex;
    align-items: center;
    gap: 0.3125rem;
    flex: 0 0 auto;
    white-space: nowrap;
    transition: color .12s ease;
  }

  #sa-widget .download-btn:hover { color: var(--primary); }
  #sa-widget .download-btn:active { transform: translateY(1px); }

  #sa-widget .download-btn:disabled {
    opacity: .45;
    cursor: not-allowed;
  }

  #sa-widget .download-btn:disabled:hover { color: var(--muted); }

  #sa-widget .misspelled-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--card);
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }

  /* Slim, always-visible track so a clipped list reads as scrollable
     rather than truncated. Firefox uses the scrollbar-* pair. */
  #sa-widget .misspelled-list {
    scrollbar-width: thin;
    scrollbar-color: #cbd5e1 transparent;
  }

  #sa-widget .misspelled-list::-webkit-scrollbar {
    width: 6px;
  }

  #sa-widget .misspelled-list::-webkit-scrollbar-thumb {
    background: #cbd5e1;
    border-radius: 999px;
  }

  #sa-widget .misspelled-list::-webkit-scrollbar-track {
    background: transparent;
  }

  /* Hairline between rows only — the panel already has an outer border,
     so a border on every row would double up at the edges.

     .r-miss is a query container (declared below) rather than relying on
     a viewport media query, for the same reason as the bee tier picker:
     the card can be narrow inside an Elementor column while the window
     is wide, and it is the row's own width that decides whether
     "conscientious" plus "you typed X" fit side by side. */
  #sa-widget .miss-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.625rem 0.875rem;
    border-bottom: 1px solid var(--border);
  }

  #sa-widget .miss-row:last-child {
    border-bottom: 0;
  }

  #sa-widget .miss-word {
    font-weight: 600;
    color: var(--text);
    font-size: 0.875rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Two-tone: the "you typed" label is chrome and stays muted grey, the
     misspelling itself is the content and keeps the red. The whole line
     used to be one red string, which made the label compete with the
     word it introduces. min-width:0 on the wrapper plus the ellipsis on
     the value keeps a very long misspelling from pushing the correct
     word out of the row. */
  #sa-widget .miss-typed {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 0.3125rem;
    font-size: 0.75rem;
    text-align: right;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    flex: 0 1 auto;
  }

  #sa-widget .miss-typed-key {
    font-weight: 500;
    color: #94a3b8;
    flex: 0 0 auto;
  }

  #sa-widget .miss-typed-val {
    font-weight: 600;
    color: #dc2626;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  #sa-widget .miss-empty {
    height: 100%;
    min-height: 5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 1rem 0.875rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: #94a3b8;
  }

  /* Query container for the missed-words rows. .r-miss is a flex child
     of .results-shell (a column flex box), so its inline size comes from
     the parent and never from its contents — inline-size containment is
     safe here. Browsers without @container support simply keep the
     single-line row with its existing ellipsis, which is the previous
     behaviour, so this degrades to exactly what shipped before. */
  #sa-widget .r-miss {
    container-type: inline-size;
    container-name: sa-miss;
  }

  /* Below ~330px the correct word and "you typed X" cannot share a line
     without one of them ellipsising away. Stacking gives each the full
     row width, so nothing is hidden. */
  @container sa-miss (max-width: 330px) {
    #sa-widget .miss-row {
      flex-direction: column;
      align-items: flex-start;
      gap: 0.0625rem;
      padding: 0.5rem 0.75rem;
    }
    #sa-widget .miss-word {
      max-width: 100%;
    }
    #sa-widget .miss-typed {
      justify-content: flex-start;
      text-align: left;
      max-width: 100%;
    }
  }

  /* ---- Footer -------------------------------------------------------- */
  /* Same full-bleed hairline treatment as the test screen's action row,
     so both screens end the same way. Negative margins mirror .card's
     side padding. */
  #sa-widget .results-buttons {
    display: flex;
    gap: 0.75rem;
    margin: 0 -1.625rem;
    padding: 1rem 1.625rem 0;
    border-top: 1px solid var(--border);
    flex: 0 0 auto;
  }

  /* Lopsided on purpose, matching Check word / End test: Try again is
     the expected next action, New test is the occasional detour. */
  #sa-widget .rbtn {
    flex: 1 1 0;
    min-width: 0;
    height: 52px;
    border-radius: 13px;
    cursor: pointer;
    font-weight: 600;
    font-size: 0.9375rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform .12s ease, filter .12s ease, background .12s ease, border-color .12s ease;
    background: #fff;
    color: var(--muted);
    border: 1px solid var(--border);
  }

  #sa-widget .rbtn.primary {
    flex: 2.4 1 0;
    background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
    color: #fff;
    border: 0;
    box-shadow: 0 4px 11px rgba(47, 107, 255, .22);
  }

  #sa-widget .rbtn:hover {
    background: #f8fafc;
    border-color: #cbd5e1;
  }

  #sa-widget .rbtn.primary:hover {
    background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
    filter: brightness(1.06);
    border-color: transparent;
  }

  #sa-widget .rbtn:active {
    transform: translateY(1px);
  }

  #sa-widget .trophy {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: #f8fafc;
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1rem;
    user-select: none;
    overflow: visible;
    transition: border-color .12s ease, transform .12s ease;
  }

  #sa-widget .trophy:hover {
    border-color: var(--primary);
    transform: scale(1.06);
  }
  #sa-widget .trophy:active {
    transform: scale(0.96);
  }
  #sa-widget .trophy-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    width: 12px;
    height: 12px;
    border-radius: 999px;
    background: #ef4444;
    border: 2px solid #ffffff;
    display: none;
    box-shadow: 0 8px 18px rgba(239, 68, 68, .35);
  }

  #sa-widget .trophy.has-badge .trophy-badge {
    display: block;
  }

  @keyframes trophyPulse {
    0% {
      transform: scale(1);
      box-shadow: 0 0 0 rgba(37, 99, 235, 0);
    }
    35% {
      transform: scale(1.12);
      box-shadow: 0 0 0 10px rgba(37, 99, 235, .18);
    }
    70% {
      transform: scale(1.04);
      box-shadow: 0 0 0 16px rgba(37, 99, 235, .08);
    }
    100% {
      transform: scale(1);
      box-shadow: 0 0 0 rgba(37, 99, 235, 0);
    }
  }

  #sa-widget .trophy.pulse {
    animation: trophyPulse 1.05s ease-in-out 0s 1;
  }

  #sa-widget .info-btn {
    position: absolute;

    top: 18px;

    right: 56px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 2px solid var(--text);
    background: #fff;
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--text);
    user-select: none;
    z-index: 45;
    transition: border-color .12s ease, color .12s ease, transform .12s ease;
  }
  #sa-widget .info-btn .sa-svg {
    width: 14px;
    height: 14px;
  }
  #sa-widget .info-btn:hover {
    border-color: var(--primary);
    color: var(--primary);
    transform: scale(1.06);
  }
  #sa-widget .info-btn:active {
    transform: scale(0.96);
  }
  #sa-widget .info-btn.active {
    border-color: var(--primary);
    color: var(--primary);
    background: var(--primary-soft);
  }

  #sa-widget .info-tooltip {
    position: absolute;
    top: 50%;
    right: calc(100% + 10px);
    transform: translateY(-50%) translateX(6px);
    background: #fff;
    border: 1px solid var(--card-border);
    border-radius: 8px;
    box-shadow: 0 10px 24px -10px rgba(15, 23, 42, .28);
    padding: 0.375rem 0.625rem;
    font-size: 0.7875rem;
    font-weight: 400;
    color: var(--text);
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    z-index: 47;
    transition: opacity .16s ease, transform .16s ease, visibility 0s linear .16s;
  }
  #sa-widget .info-tooltip::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 100%;
    margin-left: -4px;
    width: 8px;
    height: 8px;
    background: #fff;
    border-right: 1px solid var(--card-border);
    border-top: 1px solid var(--card-border);
    transform: translateY(-50%) rotate(45deg);
  }

  #sa-widget .trophy:hover .info-tooltip,
  #sa-widget .trophy:focus-visible .info-tooltip {
    opacity: 1;
    visibility: visible;
    transform: translateY(-50%) translateX(0);
    transition: opacity .16s ease, transform .16s ease;
  }

  #sa-widget .info-btn .info-tooltip {
    opacity: 1;
    visibility: visible;
    transform: translateY(-50%) translateX(0);
  }
  #sa-widget .info-btn.active .info-tooltip {
    opacity: 0 !important;
    visibility: hidden !important;
  }

  #sa-widget .card:has(.trophy:hover) .info-btn .info-tooltip,
  #sa-widget .card:has(.trophy:focus-visible) .info-btn .info-tooltip {
    opacity: 0 !important;
    visibility: hidden !important;
  }

  #sa-widget .trophy-tooltip {
    right: calc(100% + 44px);
  }

  #sa-widget .info-popover {
    position: absolute;
    top: 54px;
    right: 14px;
    width: 260px;
    max-width: calc(100% - 28px);
    background: #fff;
    border: 1px solid var(--card-border);
    border-radius: 14px;
    box-shadow: 0 20px 40px -16px rgba(15, 23, 42, .28);
    padding: 1.125rem 1.25rem 1.25rem;
    z-index: 46;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px) scale(0.97);
    transform-origin: top right;
    transition: opacity .14s ease, transform .14s ease, visibility 0s linear .14s;
  }
  #sa-widget .info-popover.open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
    transition: opacity .14s ease, transform .14s ease;
  }

  #sa-widget .info-popover::before {
    content: "";
    position: absolute;
    top: -5px;
    right: 50px;
    width: 10px;
    height: 10px;
    background: #fff;
    border-left: 1px solid var(--card-border);
    border-top: 1px solid var(--card-border);
    transform: rotate(45deg);
    border-radius: 2px 0 0 0;
  }
  #sa-widget .info-popover-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.875rem;
  }
  #sa-widget .info-popover-title {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text);
  }
  #sa-widget .info-popover-close {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: none;
    background: #f1f5f9;
    color: #64748b;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
  }
  #sa-widget .info-popover-close svg {
    width: 13px;
    height: 13px;
  }
  #sa-widget .info-popover-close:hover {
    background: #e2e8f0;
    color: #1e293b;
  }
  #sa-widget .info-popover-list {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: sa-info-step;
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
  }
  #sa-widget .info-popover-list li {
    position: relative;
    counter-increment: sa-info-step;
    padding-left: 1.875rem;
    min-height: 20px;
    font-size: 0.75rem;
    font-weight: 400;
    line-height: 1.4;
    color: #475569;
  }
  #sa-widget .info-popover-list li::before {
    content: counter(sa-info-step);
    position: absolute;
    left: 0;
    top: 0;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
  }
  #sa-widget .info-popover-list li:not(:last-child)::after {
    content: "";
    position: absolute;
    left: 9px;
    top: 22px;
    bottom: -14px;
    width: 2px;
    background: var(--primary);
    opacity: 0.28;
  }
  #sa-widget .info-popover-list li b {
    color: var(--text);
    font-weight: 600;
  }

  /* =====================================================================
     LEADERBOARD MODAL
     Lives at <body> level (relocated by sa-tool.js), so it is outside
     #sa-widget and inherits none of the card's CSS custom properties by
     cascade. sa-tool.js copies --primary / --primary-2 / --text / --muted
     / --border onto #lbBackdrop itself during relocation, which is why
     var() works below. Anything added here must use one of those five or
     a literal — a var() the widget sets on .card alone resolves to
     nothing at this level and silently falls back.

     Four bands: dark header, stat strip, filter row, scrolling rows,
     footer.
     ===================================================================== */
  #lbBackdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, .55);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    z-index: 99999;
    font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
    color: #16233d;
  }

  #lbBackdrop *,
  #lbBackdrop *::before,
  #lbBackdrop *::after {
    box-sizing: border-box;
  }

  #lbBackdrop button {
    font-family: inherit;
    margin: 0;
    min-width: 0;
    min-height: 0;
    line-height: normal;
  }

  #lbBackdrop .modal {
    width: min(640px, 100%);
    max-height: calc(100vh - 2rem);
    max-height: calc(100dvh - 2rem);
    background: #fff;
    border-radius: 18px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, .28);
    border: 1px solid rgba(15, 23, 42, .07);
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }

  /* ---- Header -------------------------------------------------------- */
  #lbBackdrop .modal-head {
    padding: 1.125rem 1.375rem 1.25rem;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    background: linear-gradient(140deg, #1e2c49 0%, #131d33 100%);
    flex: 0 0 auto;
  }

  #lbBackdrop .modal-head-left {
    min-width: 0;
  }

  #lbBackdrop .lb-eyebrow {
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .55);
  }

  #lbBackdrop .modal-title {
    font-size: 1.3125rem;
    font-weight: 700;
    color: #fff;
    line-height: 1.2;
    margin-top: 0.375rem;
  }

  #lbBackdrop .modal-sub {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, .62);
    font-weight: 400;
    margin-top: 0.25rem;
  }

  #lbBackdrop .lb-close-btn {
    width: 30px;
    height: 30px;
    border-radius: 999px;
    border: 0;
    background: rgba(255, 255, 255, .1);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, .75);
    flex: 0 0 auto;
    padding: 0;
    transition: background .15s ease, color .15s ease, transform .15s ease;
  }

  #lbBackdrop .lb-close-btn:hover {
    background: rgba(255, 255, 255, .2);
    color: #fff;
    transform: rotate(90deg);
  }

  #lbBackdrop .lb-close-btn svg {
    width: 13px;
    height: 13px;
    display: block;
    flex-shrink: 0;
  }

  /* ---- Stat strip ---------------------------------------------------- */
  /* Same 1px-gap construction as the results screen's stat strip, so the
     two read as the same component in two places. */
  #lbBackdrop .lb-summary {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1px;
    background: var(--border, #e6e8ef);
    border-bottom: 1px solid var(--border, #e6e8ef);
    flex: 0 0 auto;
  }

  #lbBackdrop .lb-chip {
    background: #fafbfd;
    padding: 0.75rem 0.875rem 0.8125rem;
    min-width: 0;
  }

  #lbBackdrop .lb-chip-k {
    font-size: 0.625rem;
    font-weight: 600;
    color: #94a3b8;
    letter-spacing: .11em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  #lbBackdrop .lb-chip-v {
    font-size: 1.0625rem;
    font-weight: 700;
    color: #16233d;
    line-height: 1.2;
    margin-top: 0.3125rem;
  }

  /* ---- Filter pills -------------------------------------------------- */
  /* Only rendered for modes whose runs span more than one word list
     (home difficulties, kids-grade years, spelling-bee tiers). PTE and
     IELTS lock the list, so the row would be a single dead "All" pill —
     sa-tool.js omits the element entirely there rather than hiding it,
     which also keeps the padding below from doubling up. */
  #lbBackdrop .lb-filters {
    display: flex;
    gap: 0.5rem;
    padding: 0.875rem 1.375rem;
    overflow-x: auto;
    scrollbar-width: none;
    flex: 0 0 auto;
    border-bottom: 1px solid var(--border, #e6e8ef);
  }

  #lbBackdrop .lb-filters::-webkit-scrollbar {
    display: none;
  }

  #lbBackdrop .lb-filter {
    flex: 0 0 auto;
    height: 32px;
    padding: 0 0.875rem;
    border-radius: 999px;
    border: 1px solid var(--border, #e6e8ef);
    background: #fff;
    color: var(--muted, #1f2b45);
    font-size: 0.78125rem;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    transition: background .12s ease, color .12s ease, border-color .12s ease;
  }

  #lbBackdrop .lb-filter:hover {
    border-color: #cbd5e1;
    background: #f8fafc;
  }

  #lbBackdrop .lb-filter.active {
    background: var(--primary, #2f6bff);
    border-color: var(--primary, #2f6bff);
    color: #fff;
  }

  #lbBackdrop .lb-filter.active:hover {
    background: var(--primary-2, #1f52d6);
    border-color: var(--primary-2, #1f52d6);
  }

  /* ---- Rows ---------------------------------------------------------- */
  #lbBackdrop .lb-rows-wrap {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 0.25rem 1.375rem;
    scrollbar-width: thin;
    scrollbar-color: #cbd5e1 transparent;
  }

  #lbBackdrop .lb-rows-wrap::-webkit-scrollbar {
    width: 6px;
  }

  #lbBackdrop .lb-rows-wrap::-webkit-scrollbar-thumb {
    background: #cbd5e1;
    border-radius: 999px;
  }

  #lbBackdrop .lb-rows {
    display: flex;
    flex-direction: column;
  }

  /* Rows are separated by a hairline rather than being boxed. Ten boxed
     cards in a scroll area produced more borders than content; the rank
     column already gives the list its structure. */
  #lbBackdrop .lb-row {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 0.75rem;
    padding: 0.8125rem 0;
    border-bottom: 1px solid var(--border, #e6e8ef);
  }

  #lbBackdrop .lb-row:last-child {
    border-bottom: 0;
  }

  #lbBackdrop .lb-rank {
    font-size: 0.75rem;
    font-weight: 700;
    color: #94a3b8;
    text-align: center;
    align-self: center;
  }

  /* Medal tint on the number itself — the old filled tiles competed with
     the accuracy figure, which is the actual ranking key. */
  #lbBackdrop .lb-rank.gold   { color: #d99400; font-size: 0.8125rem; }
  #lbBackdrop .lb-rank.silver { color: #7c8ba1; font-size: 0.8125rem; }
  #lbBackdrop .lb-rank.bronze { color: #b1743d; font-size: 0.8125rem; }

  #lbBackdrop .lb-main {
    min-width: 0;
  }

  #lbBackdrop .lb-line {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    min-width: 0;
  }

  #lbBackdrop .lb-acc-v {
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.15;
    flex: 0 0 auto;
  }

  #lbBackdrop .lb-meta-1 {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--muted, #1f2b45);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  #lbBackdrop .acc-hi { color: #0f9d6e; }
  #lbBackdrop .acc-mid { color: #2563eb; }
  #lbBackdrop .acc-lo { color: #ef4444; }

  #lbBackdrop .lb-bar-track {
    width: 100%;
    height: 3px;
    border-radius: 3px;
    background: #eef1f5;
    overflow: hidden;
    margin-top: 0.5rem;
  }

  #lbBackdrop .lb-bar-fill {
    height: 100%;
    border-radius: 3px;
  }

  #lbBackdrop .lb-bar-fill.acc-hi { background: #0f9d6e; }
  #lbBackdrop .lb-bar-fill.acc-mid { background: #2563eb; }
  #lbBackdrop .lb-bar-fill.acc-lo { background: #ef4444; }

  #lbBackdrop .lb-date {
    font-size: 0.625rem;
    color: #b4bfcd;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    text-align: right;
    white-space: nowrap;
    align-self: center;
  }

  #lbBackdrop .empty {
    padding: 2.5rem 1.375rem;
    text-align: center;
    color: #94a3b8;
    font-size: 0.84375rem;
    font-weight: 500;
    line-height: 1.5;
  }

  /* ---- Footer -------------------------------------------------------- */
  #lbBackdrop .lb-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.875rem 1.375rem;
    border-top: 1px solid var(--border, #e6e8ef);
    background: #fafbfd;
    flex: 0 0 auto;
  }

  #lbBackdrop .lb-foot-note {
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: #94a3b8;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Two-step, not a window.confirm(): the second click is the guard, and
     the label states exactly what it will delete. Reverts on close, on
     blur, and after 4s so it can never be left armed. */
  #lbBackdrop .lb-clear {
    border: 0;
    background: none;
    padding: 0;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--muted, #1f2b45);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    flex: 0 0 auto;
    white-space: nowrap;
    transition: color .12s ease;
  }

  #lbBackdrop .lb-clear:hover { color: #dc2626; }

  #lbBackdrop .lb-clear.armed {
    color: #dc2626;
    font-weight: 700;
  }

  /* ---- Modal responsive ---------------------------------------------- */
  @media (max-width: 520px) {
    #lbBackdrop {
      padding: 0.625rem;
    }

    #lbBackdrop .modal {
      border-radius: 16px;
    }

    #lbBackdrop .modal-head {
      padding: 1rem 1.125rem;
    }

    #lbBackdrop .modal-title {
      font-size: 1.125rem;
    }

    #lbBackdrop .lb-summary {
      grid-template-columns: repeat(2, 1fr);
    }

    #lbBackdrop .lb-chip {
      padding: 0.625rem 0.875rem 0.6875rem;
    }

    #lbBackdrop .lb-filters,
    #lbBackdrop .lb-rows-wrap,
    #lbBackdrop .lb-foot {
      padding-left: 1.125rem;
      padding-right: 1.125rem;
    }

    /* Date drops under the meta line: at 320px a right-hand date column
       squeezed the difficulty label down to two or three characters. */
    #lbBackdrop .lb-row {
      grid-template-columns: 22px minmax(0, 1fr);
      row-gap: 0.25rem;
    }

    #lbBackdrop .lb-date {
      grid-column: 2;
      text-align: left;
    }

    /* Wrap rather than ellipsise. Even with the date moved off the row,
       "Everyday · 3 Min · 12 correct, 5 missed" does not fit beside the
       accuracy figure at 320px — measured, 9 of 10 rows were truncated,
       which hid the correct/missed counts on almost every row. A second
       line costs ~16px and keeps the whole string readable. */
    #lbBackdrop .lb-line {
      flex-wrap: wrap;
      row-gap: 0.125rem;
    }

    #lbBackdrop .lb-meta-1 {
      white-space: normal;
      overflow: visible;
      line-height: 1.35;
    }

    #lbBackdrop .lb-foot-note {
      display: none;
    }

    #lbBackdrop .lb-foot {
      justify-content: flex-end;
    }
  }

  @media (max-width: 520px) {
    #sa-widget .card {
      width: 100%;
      min-height: 540px;
      height: auto;
      padding: 1.375rem 1rem 1rem;
      gap: 0.75rem;
      border-radius: var(--card-radius);
      overflow: visible;
    }

    #sa-widget .title {
      padding-right: 88px;
    }

    #sa-widget .info-btn .info-tooltip {
      display: none;
    }

    #sa-widget .list {
      flex-direction: row;
      gap: 0.925rem;
    }

    #sa-widget .pill {
      height: 60px;
      flex: 1;
      width: 100%;
      padding: 0.625rem 0.5rem;
      flex-direction: column;
      justify-content: center;
      gap: 0.375rem;
      border-radius: 14px;
    }

    #sa-widget .duration-row {
      width: 100%;
      gap: 0.5rem;
    }

    #sa-widget .duration-row .chip {
      flex: 1;
      width: auto;
    }

    /* Test screen below 521px. The card's side padding drops from
       1.625rem to 1rem here, so every full-bleed element has to rebase
       its negative margins or the band overhangs the card edge. */
    #sa-widget #screenTest .test-wrap {
      flex: 1;
      justify-content: flex-start;
      gap: 0;
    }

    #sa-widget .status-bar {
      margin: -1.375rem -1rem 0;
      padding: 0.75rem 1rem;
      gap: 0.75rem;
    }

    #sa-widget .status-key {
      font-size: 0.6875rem;
    }

    #sa-widget .test-main {
      gap: 1.375rem;
      padding: 0.375rem 0;
    }

    #sa-widget .replay-btn {
      width: 68px;
      height: 68px;
    }

    #sa-widget .replay-btn .sa-svg {
      width: 26px;
      height: 26px;
    }

    #sa-widget .input {
      height: 62px;
      font-size: 1.1875rem;
      border-radius: 12px;
    }

    #sa-widget .buttons {
      margin: 0 -1rem;
      padding: 0.875rem 1rem 0;
      gap: 0.5rem;
    }

    #sa-widget .btn {
      height: 50px;
      font-size: 0.875rem;
    }

    /* Two thin columns at 320px make "Check word" wrap; 2 : 1 keeps the
       primary label on one line while the exit stays visibly secondary. */
    #sa-widget .btn-primary {
      flex: 2 1 0;
    }

    /* Results screen below 521px. The layout is already one column, so
       this only retunes spacing and rebases the footer's full-bleed
       margins from 1.625rem to the card's 1rem side padding. */
    #sa-widget .results-shell {
      gap: 0.875rem;
    }

    #sa-widget .r-hero {
      gap: 0.875rem;
    }

    /* The verdict tip is the first thing to go on a phone. It costs a
       full line (plus its icon) directly above the missed-words list,
       and everything it says is already carried by the title above it
       and the list below it — so it is duplication, not information.
       The hero collapses to ring + title + personal-best line, which is
       what people actually scan for. Desktop keeps the tip. */
    #sa-widget .r-hero-tip {
      display: none;
    }

    /* With one line gone the text block is shorter than the ring, so
       centre it rather than leaving it top-aligned against a taller
       neighbour. */
    #sa-widget .r-hero {
      align-items: center;
    }

    #sa-widget .r-hero-meta {
      margin-top: 0.3125rem;
    }

    #sa-widget .r-ring {
      width: 76px;
      height: 76px;
    }

    #sa-widget .r-ring-inner {
      width: 58px;
      height: 58px;
    }

    #sa-widget .r-ring-pct {
      font-size: 1.125rem;
    }

    /* 2 x 2: four cells across at 320px leaves ~68px per label and
       "ATTEMPTED" clips. The 1px-gap grid handles the extra row with no
       border changes. */
    #sa-widget .r-stats {
      grid-template-columns: repeat(2, 1fr);
    }

    #sa-widget .r-stat {
      padding: 0.625rem 0.75rem 0.6875rem;
    }

    #sa-widget .r-miss {
      min-height: 6.5rem;
    }

    #sa-widget .results-buttons {
      margin: 0 -1rem;
      padding: 0.875rem 1rem 0;
      gap: 0.5rem;
    }

    #sa-widget .rbtn {
      height: 48px;
      font-size: 0.875rem;
    }

    #sa-widget .rbtn.primary {
      flex: 2 1 0;
    }

    #sa-widget .accent {
      flex-direction: row !important;
      gap: 0.625rem !important;
    }

    #sa-widget .accent .pill {
      flex: 1 !important;
      height: 44px !important;
      flex-direction: row !important;
      padding: 0 0.625rem !important;
      width: 100% !important;
    }

    #sa-widget .progress {
      padding: 1.125rem 0;
    }

    #sa-widget .progress-grid {
      gap: 0.5rem;
    }

    /* Content-width (not equal thirds) below 521px: at 320–360px an equal
       third is narrower than "WORDS PRACTISED" and the label would clip. */
    #sa-widget .metric {
      flex: 0 1 auto;
      gap: 0.5rem;
    }

    #sa-widget .metric .label {
      font-size: 0.5625rem;
      letter-spacing: .08em;
    }

    #sa-widget .metric .value {
      font-size: 0.9375rem;
    }

  }

  @media (min-width: 521px) {
    #sa-widget #screenSettings {
      justify-content: space-between;
      padding-top: 0rem;
      padding-bottom: 0rem;
    }

    /* .content sizes to its own content rather than eating all the spare
       height. Combined with space-between above, the leftover space is
       shared evenly between header/pickers/progress/CTA, so every mode
       reads with the same rhythm even though the picker blocks differ in
       height (bee tiers 1 row, grades 2 rows, mode card 2 lines). */
    #sa-widget #screenSettings .content {
      flex: 0 0 auto;
      padding-top: 0rem;
    }
  }

  #sa-widget .countdown-overlay {
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, 1);
    z-index: 40;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius);
    gap: 0.625rem;
  }

  #sa-widget .countdown-number {
    font-size: 5.5rem;
    font-weight: 800;
    line-height: 1;
    color: var(--primary);
    animation: cdPop 0.85s ease-out forwards;
  }

  #sa-widget .countdown-label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--muted);
    letter-spacing: 0.06em;
  }

  #sa-widget .countdown-go {
    font-size: 3.5rem;
    font-weight: 800;
    color: #10b981;
    animation: cdPop 0.5s ease-out forwards;
  }

  @keyframes cdPop {
    0%   { transform: scale(1.4); opacity: 0; }
    40%  { transform: scale(0.95); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
  }

  #sa-widget .fireworks {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    z-index: 50;
  }

  #sa-widget .spark {
    position: absolute;
    width: 8px;
    height: 8px;
    border-radius: 999px;
    opacity: 0.95;
    transform: translate(-50%, -50%);
    animation: sparkMove 900ms ease-out forwards, sparkFade 900ms linear forwards;
  }

  @keyframes sparkMove {
    to {
      transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy)));
    }
  }

  @keyframes sparkFade {
    to {
      opacity: 0;
    }
  }

  #sa-widget .sa-svg {
    width: 1em;
    height: 1em;
    display: block;
    flex: 0 0 auto;
  }

  #sa-widget .pill .icon .sa-svg {
    width: 16px;
    height: 16px;
  }

  #sa-widget .pill .icon {
    width: 26px;
  }
  #sa-widget .sa-diff-icon {
    width: 22px;
    height: 22px;
    display: block;
    flex: 0 0 auto;
  }
  #sa-widget .sa-svg-infinity {
    width: 20px;
    height: 20px;
  }

  #sa-widget .sa-flag {
    width: 20px;
    height: 13px;
    display: block;
    border-radius: 2px;
    flex: 0 0 auto;
    box-shadow: 0 0 0 1px rgba(0,0,0,.08);
  }
  #sa-widget .flag {
    display: inline-flex;
    align-items: center;
    line-height: 1;
  }

  #sa-widget .flame .sa-svg {
    width: 15px;
    height: 15px;
  }

  #sa-widget .trophy .sa-svg {
    width: 18px;
    height: 18px;
  }

  #sa-widget .sa-ico-inline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: -0.13em;
    margin-right: 0.25rem;
  }
  #sa-widget .sa-ico-inline .sa-svg {
    width: 1em;
    height: 1em;
  }

  /* .timer-text is inline-flex + centred, so the icon needs no
     vertical-align correction any more. */
  #sa-widget .sa-timer-infinity {
    width: 20px;
    height: 20px;
    display: block;
  }

#sa-widget .sa-mode-card {
  width: 100%;
  height: 100%;
  min-height: 200px;
  border-radius: 16px;
  padding: 1.125rem 1rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  position: relative;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(16, 24, 40, .05);
  border: 1.5px solid #e0dfff;
  flex: 1;
}

#sa-widget .sa-mode-card-top {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

#sa-widget .sa-mode-card-icon {
  width: 28px;
  height: 28px;
  border-radius: 10px;
  background: rgba(0,0,0,.06);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  flex: 0 0 28px;
}

#sa-widget .sa-mode-card-icon .sa-diff-icon {
  width: 22px;
  height: 22px;
}

#sa-widget .sa-mode-card-dot {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 11px;
  height: 11px;
  border-radius: 999px;
  border: 2px solid #fff;
}

#sa-widget .sa-mode-card-heading {
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1.3;
}

#sa-widget .sa-mode-card-body {
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.55;
  flex: 1;
}

#sa-widget .sa-mode-card-badge {
  margin-top: auto;
  border-radius: 9px;
  padding: 0.5625rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

#sa-widget .sa-mode-card-badge-label {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

#sa-widget .sa-mode-card-badge-val {
  font-size: 0.875rem;
  font-weight: 600;
}

/* Full card width from 521px up. The card body and the ACTIVE MODE panel
   sit side by side rather than stacked, so the block stays shallow now
   that it spans the whole card instead of a narrow left column. */
@media (min-width: 521px) {
  #sa-widget .sa-mode-card {
    display: grid;
    grid-template-columns: 1.5fr 1fr;
    grid-template-rows: auto auto;
    column-gap: 1.25rem;
    row-gap: 0.5rem;
    align-content: start;
    height: auto;
    min-height: 0;
    flex: none;
    padding: 1rem 1.125rem;
  }
  #sa-widget .sa-mode-card-top {
    grid-column: 1;
    grid-row: 1;
  }
  #sa-widget .sa-mode-card-body {
    grid-column: 1;
    grid-row: 2;
    flex: none;
  }
  #sa-widget .sa-mode-card-badge {
    grid-column: 2;
    grid-row: 1 / span 2;
    margin-top: 0;
    justify-content: center;
  }
}

/* Mode-card tints. Deliberately very light — the card is an information
   panel, not a selectable state, so it must sit quieter than the Start
   button (the only fully saturated element per mode). Body text stays at
   the same saturated colour, so lightening the fill raises contrast
   rather than lowering it. */
#sa-widget[data-mode="pte"] .sa-mode-card {
  background: #f7f7ff;
  border-color: #dedcff;
}
#sa-widget[data-mode="pte"] .sa-mode-card-heading { color: #0d004d; }
#sa-widget[data-mode="pte"] .sa-mode-card-body    { color: #3730a3; }
#sa-widget[data-mode="pte"] .sa-mode-card-badge   { background: rgba(13,0,77,.08); }
#sa-widget[data-mode="pte"] .sa-mode-card-badge-label { color: #6d5cba; }
#sa-widget[data-mode="pte"] .sa-mode-card-badge-val   { color: #0d004d; }

#sa-widget[data-mode="ielts"] .sa-mode-card {
  background: #fff8f8;
  border-color: #fdd9d9;
}
#sa-widget[data-mode="ielts"] .sa-mode-card-heading { color: #7f1d1d; }
#sa-widget[data-mode="ielts"] .sa-mode-card-body    { color: #991b1b; }
#sa-widget[data-mode="ielts"] .sa-mode-card-badge   { background: rgba(220,38,38,.08); }
#sa-widget[data-mode="ielts"] .sa-mode-card-badge-label { color: #b45555; }
#sa-widget[data-mode="ielts"] .sa-mode-card-badge-val   { color: #7f1d1d; }

#sa-widget[data-mode="pte"] .start {
  background: #ffce00;
  box-shadow: 0 4px 12px rgba(255,206,0,.35);
  color: #0d004d;
}
#sa-widget[data-mode="ielts"] .start {
  background: #dc2626;
  box-shadow: 0 4px 12px rgba(220,38,38,.28);
  color: #fff;
}

#sa-widget[data-mode="pte"] .chip.active {
  background: #eeeeff;
  border-color: #9999ff;
  color: #0d004d;
  box-shadow: none;
}
#sa-widget[data-mode="ielts"] .chip.active {
  background: #dc262622;
  border-color: #dc2626;
  color: #b91c1c;
  box-shadow: none;
}

#sa-widget[data-mode="pte"] .pill.active-accent {
  background: #0d004d;
  /*box-shadow: 0 10px 22px rgba(13,0,77,.22);*/
}

#sa-widget[data-mode="pte"] .pill.active-primary {
  background: #0d004d;
  box-shadow: 0 10px 22px rgba(13,0,77,.22);
}

#sa-widget[data-mode="pte"] .btn-primary {
  background: #ffce00;
  color: #0d004d;
  box-shadow: 0 4px 11px rgba(255,206,0,.32);
}
#sa-widget[data-mode="ielts"] .btn-primary {
  background: #dc2626;
  box-shadow: 0 4px 11px rgba(220,38,38,.28);
}

#sa-widget[data-mode="pte"] .rbtn.primary {
  background: #ffce00;
  color: #0d004d;
  box-shadow: 0 4px 11px rgba(255,206,0,.32);
}
#sa-widget[data-mode="ielts"] .rbtn.primary {
  background: #dc2626;
  box-shadow: 0 4px 11px rgba(220,38,38,.28);
}

/* The old per-mode .r-hero / .r-progress tints and .lb-chip tints are
   gone with the panels they filled: the results hero is now a plain
   ring-plus-verdict row and the leaderboard's stat strip is a neutral
   band. Mode identity on both screens comes from --primary (ring, Try
   again, active filter pill), which sa-tool.js sets per mode. */

#sa-widget[data-mode="pte"] .title {
  color: #0d004d;
}
#sa-widget[data-mode="ielts"] .title {
  color: #b91c1c;
}

/* Per-mode card border tint. Home/default keeps the neutral
   --card-border set in the base #sa-widget block above — these rules
   only add specificity on top of it, never replace it. PTE and IELTS
   reuse the exact tints already established for .sa-mode-card's
   border-color so the card edge and the mode-card panel read as one
   family. Kids Grade and Spelling Bee have no existing border tint
   to reuse, so they're derived with color-mix off variables already
   in play for those modes (--accent for kids, the bee-tier amber for
   spelling bee) rather than hardcoding new hex values to maintain. */
#sa-widget[data-mode="pte"] .card {
  border-color: #c1bdfc;
}
#sa-widget[data-mode="ielts"] .card {
  border-color: #fdd9d9;
}
#sa-widget[data-mode="kids-grade"] .card {
  border-color: color-mix(in srgb, var(--accent) 28%, var(--card-border));
}
#sa-widget[data-mode="spelling-bee"] .card {
  border-color: color-mix(in srgb, #fa9f05 60%, var(--card-border));
}

@media (max-width: 520px) {
  #sa-widget .sa-mode-card {
    min-height: unset;
    height: auto;
    border-radius: 14px;
    padding: 0.6875rem 0.625rem;
    flex-direction: column;
    gap: 0.5rem;
  }
  #sa-widget .sa-mode-card-top {
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
  }
  #sa-widget .sa-mode-card-heading { font-size: 0.85rem; }
  #sa-widget .sa-mode-card-body  { display: visible; }
  #sa-widget .sa-mode-card-badge { display: none; }
}

#sa-widget[data-mode="kids-grade"] .sa-grade-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.3125rem;
}
/* Full card width from 521px up: 12 grades as 6 across x 2 rows. */
@media (min-width: 521px) {
  #sa-widget[data-mode="kids-grade"] .sa-grade-grid {
    grid-template-columns: repeat(6, 1fr);
    gap: 0.375rem;
  }
}
#sa-widget[data-mode="kids-grade"] .sa-grade-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  height: 3.40rem;
  border-radius: 10px;
  border: 2px solid;
  background: #fff;
  cursor: pointer;
  user-select: none;
  transition: transform .12s ease, box-shadow .15s ease, background .15s ease;
  padding: 0.25rem 0.125rem;
  font-family: inherit;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-btn:active {
  transform: scale(.96);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-btn.sa-grade-active {
  box-shadow: 0 5px 16px rgba(0,0,0,.16);
  transform: translateY(-1px);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-num {
  font-size: 1rem;
  font-weight: 800;
  line-height: 1;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-sub {
  font-size: 0.75rem;
  font-weight: 600;
  opacity: 0.82;
  line-height: 1;
  text-align: center;
}

#sa-widget[data-mode="kids-grade"] .sa-grade-dd {
  display: none;
  position: relative;
  font-family: inherit;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-trigger {
  width: 100%;
  height: 50px;
  display: flex;
  align-items: center;
  border-radius: 14px;
  border: 1.5px solid var(--border);
  background: linear-gradient(180deg, #ffffff 0%, #fbfbfe 100%);
  padding: 0 0.8125rem 0 2.375rem;
  position: relative;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 3px 12px rgba(15, 23, 42, .07);
  transition: box-shadow .15s ease, transform .15s ease;
  font: inherit;
  text-align: left;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-trigger:hover {
  box-shadow: 0 4px 16px rgba(15, 23, 42, .11);
  transform: translateY(-1px);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-trigger:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--grade-c, var(--primary)) 22%, transparent),
              0 4px 14px rgba(15, 23, 42, .1);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd.open .sa-grade-dd-trigger {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--grade-c, var(--primary)) 22%, transparent),
              0 4px 14px rgba(15, 23, 42, .1);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-trigger::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 6px;
  background: var(--grade-c, var(--primary));
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(0,0,0,.05);
  flex: none;
  margin-right: 0.6875rem;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-label {
  flex: 1;
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-arrow {
  width: 26px;
  height: 26px;
  padding: 5px;
  border-radius: 50%;
  background: rgba(15, 23, 42, .05);
  color: var(--muted);
  flex: none;
  transition: background .12s ease, transform .18s ease;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-trigger:hover .sa-grade-dd-arrow {
  background: rgba(15, 23, 42, .09);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd.open .sa-grade-dd-arrow {
  transform: rotate(180deg);
  background: rgba(15, 23, 42, .09);
}

#sa-widget[data-mode="kids-grade"] .sa-grade-dd-panel {
  list-style: none;
  margin: 0;
  padding: 0.375rem;
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 8px);
  background: #fff;
  border-radius: 14px;
  border: 1px solid var(--border);
  box-shadow: 0 12px 28px rgba(15, 23, 42, .16);
  max-height: 280px;
  overflow-y: auto;
  z-index: 30;
  opacity: 0;
  transform: translateY(-6px) scale(.98);
  pointer-events: none;
  transition: opacity .14s ease, transform .14s ease;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd.open .sa-grade-dd-panel {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-opt {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.6rem 0.7rem;
  border-radius: 10px;
  border-left: 4px solid transparent;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-opt:hover {
  background: rgba(15, 23, 42, .04);
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-opt:focus-visible {
  outline: 2px solid var(--opt-c);
  outline-offset: -2px;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-opt.active {
  background: color-mix(in srgb, var(--opt-c) 10%, white);
  border-left-color: var(--opt-c);
  color: var(--opt-c);
  font-weight: 700;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-opt-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-check {
  width: 16px;
  height: 16px;
  margin-left: auto;
  flex: none;
  color: var(--opt-c);
  opacity: 0;
}
#sa-widget[data-mode="kids-grade"] .sa-grade-dd-opt.active .sa-grade-dd-check {
  opacity: 1;
}
@media (max-width: 520px) {
  #sa-widget[data-mode="kids-grade"] .sa-grade-dd {
    display: block;
    margin-bottom: 0.125rem;
  }
  #sa-widget[data-mode="kids-grade"] .sa-grade-grid {
    display: none;
  }
}

/* The old kids-grade .input / .replay-btn overrides (62px input, wider
   pill replay button) are gone: the shared test screen is now taller
   and the replay control is a fixed circle, so both were either dead or
   actively fighting the new base rules. */
#sa-widget[data-mode="kids-grade"] .btn-primary {
  background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
  box-shadow: 0 4px 11px rgba(47,107,255,.26);
}
#sa-widget[data-mode="kids-grade"] .rbtn.primary {
  background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
  box-shadow: 0 4px 11px rgba(47,107,255,.26);
  color: #fff;
}
#sa-widget[data-mode="kids-grade"] .pill.active-accent {
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
  /*box-shadow: 0 6px 16px rgba(16,185,129,.22);*/
}
#sa-widget[data-mode="spelling-bee"] .btn-primary {
  background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
  box-shadow: 0 4px 11px rgba(47, 107, 255, .26);
}
#sa-widget[data-mode="spelling-bee"] .rbtn.primary {
  background: linear-gradient(180deg, var(--primary) 0%, var(--primary-2) 100%);
  box-shadow: 0 4px 11px rgba(47, 107, 255, .26);
  color: #fff;
}
#sa-widget[data-mode="spelling-bee"] .pill.active-accent {
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
  /*box-shadow: 0 6px 16px rgba(16, 185, 129, .22);*/
}

#sa-widget[data-mode="spelling-bee"] .pill.sa-bee-champion {
  border-color: #1f2937;
}
#sa-widget[data-mode="spelling-bee"] .pill.sa-bee-champion .txt {
  color: #1f2937;
}
#sa-widget[data-mode="spelling-bee"] .pill.active-primary.sa-bee-champion {
  background: linear-gradient(180deg, #374151 0%, #1f2937 100%);
  box-shadow: 0 3px 8px rgba(31, 41, 55, .16);
}
#sa-widget[data-mode="spelling-bee"] .pill.active-primary.sa-bee-champion .txt {
  color: #fff;
}

#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary[data-value="one_bee"] {
  background: #fbbf2426;
  border-color: #fbbf24;
}
#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary[data-value="one_bee"] .txt {
  color: #92660c;
}
#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary[data-value="two_bee"] {
  background: #f59e0b26;
  border-color: #f59e0b;
}
#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary[data-value="two_bee"] .txt {
  color: #9a4b0c;
}
#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary[data-value="three_bee"] {
  background: #d9770626;
  border-color: #d97706;
}
#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary[data-value="three_bee"] .txt {
  color: #7c3f0a;
}

/* =====================================================================
   SPELLING BEE — COMPETITION LEVEL PICKER
   ---------------------------------------------------------------------
   This used to switch to a horizontal icon+label pill at a *viewport*
   breakpoint (min-width: 521px). That is the wrong axis. The card lives
   inside an Elementor column, so its width is a fraction of the window:
   at a 1280px viewport the card can easily be 460px, at which point the
   viewport rule still applies the wide row layout while each pill is
   only ~94px. `.content` also flips to overflow:visible above 521px, so
   the nowrap label escaped the pill entirely instead of being clipped —
   that is the "letters hidden / text outside the box" bug.

   Fixed with a container query on .col-left (which is width:100%, so
   inline-size containment is safe there — its width comes from the
   parent, never from its contents).

   Ordering matters: the STACKED layout is the base rule, and the row
   layout is layered on inside @container. A browser without container
   query support (pre-Chrome 105 / Safari 16 / Firefox 110) simply
   ignores the @container block and gets the stacked layout at every
   width — which fits down to ~70px per pill and never spills. Graceful
   degradation, not breakage.
   ===================================================================== */

#sa-widget[data-mode="spelling-bee"] .col-left {
  container-type: inline-size;
  container-name: sa-tier;
}

/* --- Base: stacked (icon above label). Safe at any container width. --- */
#sa-widget[data-mode="spelling-bee"] #saBeeTier {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.375rem;
}

#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill {
  flex-direction: column;
  height: auto;
  min-height: 3.25rem;
  width: 100%;
  min-width: 0;
  padding: 0.3125rem 0.125rem;
  gap: 0.375rem;
  justify-content: center;
}

#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill .txt {
  font-size: 0.6875rem;
  /* normal, not nowrap: at the very narrowest containers a long label
     wraps to two lines inside the pill instead of overflowing it. */
  white-space: normal;
  text-align: center;
  line-height: 1.15;
  min-width: 0;
  max-width: 100%;
}

#sa-widget[data-mode="spelling-bee"] #saBeeTier .icon {
  width: 18px;
}

#sa-widget[data-mode="spelling-bee"] #saBeeTier .sa-diff-icon {
  width: 22px;
  height: 22px;
}

#sa-widget[data-mode="spelling-bee"] #saBeeTier .pill.active-primary .icon {
  height: 22px;
}

/* Very narrow containers (a ~320px phone leaves ~266px of col-left, so
   ~58px of label room per pill). "Champion" is a single unbreakable
   word, so white-space:normal cannot save it — it needs less type and
   less padding. This is the one label in the set that can't wrap. */
@container sa-tier (max-width: 305px) {
  #sa-widget[data-mode="spelling-bee"] #saBeeTier {
    gap: 0.25rem;
  }
  #sa-widget[data-mode="spelling-bee"] #saBeeTier .pill {
    padding: 0.3125rem 0.0625rem;
  }
  #sa-widget[data-mode="spelling-bee"] #saBeeTier .pill .txt {
    font-size: 0.625rem;
    letter-spacing: -.01em;
  }
}

/* --- Row layout, only once the container is genuinely wide enough. ---
   Widest label is "Champion" (~71px at 13px) + 22px icon + 10px gap +
   24px padding = ~127px of content. Four of those plus three 10px gaps
   needs ~538px, so the switch is at 540px of *container* width. */
@container sa-tier (min-width: 540px) {
  #sa-widget[data-mode="spelling-bee"] #saBeeTier {
    gap: 0.625rem;
  }
  #sa-widget[data-mode="spelling-bee"] #saBeeTier .pill {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    text-align: left;
    height: 52px;
    min-height: 0;
    padding: 0 0.75rem;
    gap: 0.625rem;
  }
  #sa-widget[data-mode="spelling-bee"] #saBeeTier .pill .txt {
    font-size: 0.8125rem;
    white-space: nowrap;
    text-align: left;
    line-height: normal;
  }
}


/* =====================================================================
   SPELLING BEE — ASK THE JUDGE
   Rebuilt as a corner icon + popover, matching the settings-screen
   instructions popover. It used to be a full-width toggle sitting in the
   focal column between the note and the tips, which gave an occasional
   "I'm stuck" action a permanent slot in the one column the user is
   meant to be reading, and made bee mode the only mode whose test
   screen had a different vertical rhythm.

   The wrapper spans the top edge of .test-main at zero height so the
   panel's max-width resolves against the full content width rather than
   against the 26px button. pointer-events are re-enabled on the two
   real controls only, so the invisible strip can't swallow clicks.
   ===================================================================== */
#sa-widget[data-mode="spelling-bee"] .sa-judge {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 0;
  z-index: 30;
  pointer-events: none;
}

/* .test-main's top edge sits flush against the status band's hairline
   (test-wrap has no gap), so top:0 put the button's border right on the
   rule. Inset it instead — the replay circle is optically centred well
   below this, so the offset costs nothing. */
#sa-widget[data-mode="spelling-bee"] .sa-judge-btn {
  position: absolute;
  top: 14px;
  right: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid var(--primary);
  background: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--primary);
  user-select: none;
  pointer-events: auto;
  transition: border-color .12s ease, color .12s ease, background .12s ease, transform .12s ease;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-btn .sa-svg {
  width: 15px;
  height: 15px;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-btn:hover {
  background: var(--primary-soft);
  transform: scale(1.06);
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-btn:active {
  transform: scale(.96);
}
#sa-widget[data-mode="spelling-bee"] .sa-judge.open .sa-judge-btn {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--primary-soft);
}

/* A few expanding rings when the test screen first appears, then it
   settles. The element is inside #screenTest, which is display:none
   until the run starts, so the animation restarts on each new test
   without any JS. Finite iterations on purpose: a control that pulses
   forever next to a live countdown becomes a distraction, and the
   label below already carries the explanation. */
@keyframes saJudgeAttention {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 45%, transparent); }
  70%  { box-shadow: 0 0 0 11px color-mix(in srgb, var(--primary) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 0%, transparent); }
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-btn {
  animation: saJudgeAttention 2s ease-out 0.6s 3;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-btn:hover,
#sa-widget[data-mode="spelling-bee"] .sa-judge.open .sa-judge-btn {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  #sa-widget[data-mode="spelling-bee"] .sa-judge-btn {
    animation: none;
  }
}

/* Persistent, not hover-only: on a touch screen there is no hover, so a
   bare "?" beside a running timer is a control nobody discovers. Same
   always-on treatment as the settings info button. It hides while the
   panel is open, where it would only repeat the panel's own heading. */
#sa-widget[data-mode="spelling-bee"] .sa-judge-tooltip {
  opacity: 1;
  visibility: visible;
  transform: translateY(-50%) translateX(0);
  font-weight: 600;
  color: var(--primary-2);
  border-color: color-mix(in srgb, var(--primary) 30%, #fff);
  background: var(--primary-soft);
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-tooltip::after {
  background: var(--primary-soft);
  border-right-color: color-mix(in srgb, var(--primary) 30%, #fff);
  border-top-color: color-mix(in srgb, var(--primary) 30%, #fff);
}
#sa-widget[data-mode="spelling-bee"] .sa-judge.open .sa-judge-tooltip {
  opacity: 0 !important;
  visibility: hidden !important;
}

/* Height follows the content — no cap, no inner scrollbar. A scroll
   container inside a popover hides the fact that there is more to read;
   the panel is short enough to show every entry in full instead. */
#sa-widget[data-mode="spelling-bee"] .sa-judge-panel {
  position: absolute;
  top: 46px;
  right: 0;
  width: 292px;
  max-width: 100%;
  background: #fff;
  border: 1px solid var(--card-border);
  border-radius: 14px;
  box-shadow: 0 20px 40px -16px rgba(15, 23, 42, .28);
  padding: 0.8125rem 1rem 0.875rem;
  pointer-events: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.97);
  transform-origin: top right;
  transition: opacity .14s ease, transform .14s ease, visibility 0s linear .14s;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge.open .sa-judge-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition: opacity .14s ease, transform .14s ease;
}

#sa-widget[data-mode="spelling-bee"] .sa-judge-panel::before {
  content: "";
  position: absolute;
  top: -5px;
  right: 8px;
  width: 10px;
  height: 10px;
  background: #fff;
  border-left: 1px solid var(--card-border);
  border-top: 1px solid var(--card-border);
  transform: rotate(45deg);
  border-radius: 2px 0 0 0;
}

#sa-widget[data-mode="spelling-bee"] .sa-judge-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.625rem;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-title {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text);
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-close {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: #f1f5f9;
  color: #64748b;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-close svg {
  width: 13px;
  height: 13px;
  display: block;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-close:hover {
  background: #e2e8f0;
  color: #1e293b;
}

/* One field per row. Pairing part-of-speech with origin saved height,
   but origin entries run long ("From Greek 'kynosoura' (dog's tail)…")
   and a half-width column broke them into a ragged eight-line stack. */
#sa-widget[data-mode="spelling-bee"] .sa-judge-body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

#sa-widget[data-mode="spelling-bee"] .sa-judge-item {
  min-width: 0;
  border-top: 1px solid #eef2f7;
  padding-top: 0.5rem;
}
/* The head already provides the rule above the first field. */
#sa-widget[data-mode="spelling-bee"] .sa-judge-item:first-child {
  border-top: 0;
  padding-top: 0;
}

#sa-widget[data-mode="spelling-bee"] .sa-judge-label {
  font-size: 0.59375rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--primary-2);
  margin-bottom: 0.1875rem;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-value {
  font-size: 0.75rem;
  font-weight: 400;
  color: #475569;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
#sa-widget[data-mode="spelling-bee"] .sa-judge-value.sentence {
  font-style: italic;
}

/* Redaction chip: stands in for a root word that would give away the
   spelling. Reads as a deliberate omission rather than missing data, and
   is always three dots wide so it never hints at the answer's length.
   Upright even inside the italic sentence field, so it reads as UI
   rather than as part of the quoted text. */
#sa-widget[data-mode="spelling-bee"] .sa-judge-redacted {
  display: inline-block;
  font-style: normal;
  font-weight: 700;
  letter-spacing: .06em;
  line-height: 1;
  color: #94a3b8;
  background: #f1f5f9;
  border: 1px solid #e2e8f0;
  border-radius: 4px;
  padding: 0 0.25rem;
  vertical-align: baseline;
  cursor: help;
  user-select: none;
}

@media (min-width: 521px) {
  /* Wider where there is room: the same origin text costs fewer lines,
     which is the cheapest way to keep an uncapped panel short. */
  #sa-widget[data-mode="spelling-bee"] .sa-judge-panel {
    width: 340px;
  }
}

@media (max-width: 520px) {
  #sa-widget[data-mode="spelling-bee"] .sa-judge-btn {
    top: 10px;
  }
  #sa-widget[data-mode="spelling-bee"] .sa-judge-panel {
    top: 44px;
    width: 262px;
  }
  /* The tooltip stays on below 521px, unlike the settings one. Touch
     screens have no hover at all, so this is the only chance the label
     gets — and there is room for it beside a 26px button. */
  #sa-widget[data-mode="spelling-bee"] .sa-judge-tooltip {
    font-size: 0.71875rem;
    padding: 0.3125rem 0.5rem;
  }
}