/* ==========================================================================
   SPEAKDOS DESIGN SYSTEM — the learner layer
   How the Speakdos Master Theme (/sd-tokens.css) is worn by learner pages.

   The atmosphere is the Speakdos business card: warm peach in the upper left,
   through pink and lavender, to light sky blue on the right. Every learner-
   facing page links /sd-tokens.css and then this file after its own styles,
   so the tokens re-skin the whole product through the custom properties the
   pages already use (--bg, --card, --border, --fg, --muted, --primary). A page
   written against those tokens inherits Speakdos with no extra work; changing
   a colour means changing sd-tokens.css, which Speakdos Admin shares too.

   Sections
     1–2. Tokens (sd-tokens.css)  6. Hard-coded tints remapped
                                  7. The living Speakdos tree
     3. Atmosphere + tone         8. Tree marks and lesson motifs
     4. Header and chrome         9. Moments (recognition, XP, completion)
     5. Surfaces and accents     10. Reduced motion
                                 11. The Announcement Space

   Rules this file keeps:
   - Learning comes first. Lesson screens get a calmer, veiled version of the
     gradient, and all lesson text stays on high-contrast surfaces.
   - Decoration is CSS only: gradients, transforms and opacity. Nothing here
     downloads anything except the transparent tree artwork where it is shown.
   - Decoration is never interactive and never measured: every decorative
     element has pointer-events:none, and nothing here is tied to analytics.
   - prefers-reduced-motion stops every decorative movement (section 10).
   ========================================================================== */

/* ---------- 1–2. Tokens --------------------------------------------------
   The palette, gradients, surfaces and motion values — light and dark — live
   in /sd-tokens.css, the Speakdos Master Theme shared with Speakdos Admin and
   any future Speakdos app. Every page links it immediately before this file,
   so everything below reads the same values it always has. */

/* ---------- 3. Atmosphere + tone ----------------------------------------
   body::before paints the gradient; body::after lays a white (or, in dark
   mode, deep) veil over it plus a whisper of paper grain. The veil is what
   changes per screen, and it cross-fades, so moving from the homepage into
   a lesson calms the colour instead of switching pages.

   Tone is chosen from html[data-screen], which go() keeps current.
     vivid — homepage, fast start, pricing, identity, the moment after a lesson
     calm  — lessons, tests, games in progress, reading-heavy screens
     hub   — everything else, and the default for any screen added later */
html{background:var(--sd-base)}
body::before,body::after{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none}
body::before{
  background-image:var(--sd-atmos);
  background-color:var(--sd-base);
}
body::after{
  opacity:1;
  background-color:var(--sd-veil-hub);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.06'/%3E%3C/svg%3E");
  transition:background-color .6s ease;
}
html.dark body::after{opacity:1}
html[data-screen="home"] body::after,
html[data-screen="onboard"] body::after,
html[data-screen="pricing"] body::after,
html[data-screen="identity"] body::after,
html[data-screen="momentum"] body::after{background-color:var(--sd-veil-vivid)}
html[data-screen="lesson"] body::after,
html[data-screen="legal"] body::after,
html[data-screen="community"] body::after,
html[data-screen="bank"] body::after,
html[data-screen="exam"] body::after,
html[data-screen="patterns"] body::after,
html[data-screen="wblib"] body::after,
html[data-screen="xray"] body::after,
html[data-screen="bridge"] body::after,
html[data-screen="daily"] body::after,
html[data-screen="practical"] body::after,
html[data-screen="prcmd"] body::after,
html[data-screen="prref"] body::after,
html[data-screen="prwalk"] body::after,
html[data-screen="prsafe"] body::after,
html[data-screen="sdwalk"] body::after,
html[data-screen="sdprac"] body::after,
html[data-screen="game"] body::after,
html[data-screen="wstage"] body::after,
html[data-screen="tool"] body::after,
html[data-screen="search"] body::after,
html[data-sd-tone="calm"] body::after{background-color:var(--sd-veil-calm)}
/* A standalone page (Ambassador, Privacy) can pick a tone the same way. */
html[data-sd-tone="vivid"] body::after{background-color:var(--sd-veil-vivid)}

/* ---------- 4. Header and chrome ---------------------------------------- */
header,html.dark header{
  background:var(--sd-header);
  -webkit-backdrop-filter:blur(14px) saturate(1.15);
  backdrop-filter:blur(14px) saturate(1.15);
  border-bottom:1px solid var(--sd-header-line);
}
/* The header mark is the transparent tree, so it sits in the gradient
   instead of in a black tile. */
.logo img{object-fit:contain;object-position:center;border-radius:0}
/* On the homepage the central living tree is the brand; the small header
   lockup would say the same thing twice. It is hidden, not removed, so the
   header buttons keep exactly the place they had. */
html[data-screen="home"] header .logo{visibility:hidden}
/* When an announcement is live, it takes the logo's place in the upper left
   (section 11). With none, the corner simply stays clean. */
html.sd-ann-on[data-screen="home"] header .logo{display:none}
footer{border-top-color:var(--sd-header-line)}

/* ---------- 5. Surfaces and accents -------------------------------------
   Cards stay clean and light (slightly translucent in flow, solid when they
   float) with a soft tinted shadow and the same rounded language. */
.card,.tpanel,.lgcard,.dbp,.li,.tcard,.sg,.sdbox,.qz,.vc,.mp,.stack,.pc,.jlv,.jsec,
.qw,.prall,.fxm-card,.gstat,.wsum,.hd,.ff,.clk,.csw,.pic,.rlist li{
  box-shadow:var(--sd-shadow-sm);
}
.pc.f{box-shadow:0 0 0 4px var(--sd-ring),var(--sd-shadow-md)}
.sdt-bub,.sdt-arrow,.sdtoast{background:var(--sd-surface-solid)}
/* Answer choices and small buttons are read closely: solid, not glass. */
.qopt,.sb,html.dark .qopt,html.dark .sb{background:var(--sd-surface-solid);color:var(--fg)}
.qopt:hover{border-color:var(--primary);background:var(--sd-tint)}
.tab,html.dark .tab{background:var(--sd-surface-solid)}
.tab.on,html.dark .tab.on{background:var(--primary);color:var(--pf);border-color:var(--primary)}
.btn.bo{background:rgba(255,255,255,.45)}
html.dark .btn.bo{background:rgba(255,255,255,.04)}
.langsw{background:var(--sd-surface-solid);box-shadow:var(--sd-shadow-sm)}
.langsw button.on{color:var(--pf)}

/* The Bilingual Somos gradient, used where it means something: progress,
   XP and completion. Everything else stays in plain, readable colour. */
.pbar>div,.fxbar>i,.ambp .ambbar>i{background:var(--sd-grad)}
.fxm-n{color:var(--primary)}
@supports (-webkit-background-clip:text) or (background-clip:text){
  .fxm-n,.sd-ink{background:var(--sd-grad-ink);-webkit-background-clip:text;background-clip:text;color:transparent}
}
.ruplift,.cotd{background:var(--sd-grad-soft)}

/* ---------- 6. Hard-coded tints remapped --------------------------------
   Older rules name pale blue (#eff6ff / #dbeafe) and, in dark mode, navy
   (#152238) directly. They are pointed at the shared tint here so every
   selected, highlighted and table-header state belongs to the same world. */
.dbtn:hover,.dbtn.sel,.sb.slow,th,.lnum,.bn,.dbp-step.cur .dbp-b,td.cell:hover,.mt.sel,.pic .pi,.jbanner,
html.dark th,html.dark .bn,html.dark .lnum,html.dark .mt.sel,html.dark .dbtn:hover,html.dark .dbtn.sel,
html.dark td.cell:hover,html.dark .sb.slow,html.dark .dbp-step.cur .dbp-b,html.dark .pic .pi,html.dark .jbanner,
html.dark .prpt,html.dark .prln,
html.dark .wbnote,html.dark .wbfl select,html.dark .wbwrow,html.dark .wbex,html.dark .wbcmprow,html.dark .wblab,
html.dark .wbpwside,html.dark .wbpwch,html.dark .wbpwalt,html.dark .wbfilters,
html.dark .wbcard>h4 .af,html.dark .wbdl>div,html.dark .wbit,html.dark .wbform,html.dark .wbpr,html.dark .wbimp>div,
html.dark .wbfam .mem>div,html.dark .wbroot,html.dark .wbslot,html.dark .wbfb,html.dark .wbstrength,html.dark .wbmast>div{
  background:var(--sd-tint);
}
.refnote,html.dark .refnote,html.dark .qrurl code,html.dark .qrfail{background:var(--sd-tint-2)}
.lnum,.lrec,.dbp-step.cur .dbp-s,html.dark .lrec,html.dark .dbp-step.cur .dbp-s{color:var(--sd-ink-accent)}
.badge{background:#e9e4fe;color:var(--sd-ink-accent)}
html.dark .badge{background:#2e2762;color:#d9d6ff}
.nlang.sel,html.dark .nlang.sel,.mt.sel{box-shadow:0 0 0 4px var(--sd-ring)}
.li.rec,html.dark .li.rec{box-shadow:0 0 0 3px var(--sd-ring)}
html.dark .pc.f{box-shadow:0 0 0 4px var(--sd-ring),var(--sd-shadow-md)}
html.dark .clk .cf{fill:var(--sd-tint-2)}
.fs-map path.fs-in{fill:rgba(124,58,237,.28)}

/* ---------- 7. The living Speakdos tree ---------------------------------
   Markup (homepage hero):
     <span class="hlogo sd-tree" role="img" aria-label="…">
       <span class="sd-tree-glow"></span>
       <span class="sd-tree-sway"><img class="sd-tree-canopy" …></span>
       <img class="sd-tree-base" …>
       <span class="sd-leaf l1"></span> … <span class="sd-spark s1"></span> …
     </span>
   The artwork is split in two: the canopy and upper trunk sway on their own
   layer, pivoting where the trunk meets the book; the book and the wordmark
   are a still layer drawn on top. So the tree breathes while the logo, the
   headline and every button stay exactly where they are. The box keeps the
   210 × 224 footprint the old image had, so nothing below it moves.

   Everything animated is transform or opacity on a small element, which the
   browser composites without repainting the page. */
.sd-tree{position:relative;display:block;isolation:isolate;pointer-events:none;-webkit-user-select:none;user-select:none}
.hero .hlogo.sd-tree{width:210px;height:224px;margin:0 auto 1.5rem}
.sd-tree img,.hero .sd-tree img,html.dark .hero .sd-tree img{
  position:absolute;inset:0;width:100%;height:100%;margin:0;
  object-fit:contain;border-radius:0;box-shadow:none;
}
.sd-tree-sway{position:absolute;inset:0;transform-origin:50% 54%;z-index:1}
.sd-tree-canopy{transform-origin:50% 54%;animation:sd-sway var(--sd-sway-dur) var(--sd-ease) infinite;will-change:transform}
.sd-tree-base{z-index:2}
.sd-tree-glow{
  position:absolute;left:-18%;right:-18%;top:-14%;height:92%;z-index:0;
  background:var(--sd-glow);border-radius:50%;
  animation:sd-breathe var(--sd-glow-dur) ease-in-out infinite;
}
/* The "Bilingual Somos" line keeps its brand gradient, now drawn straight
   onto the gradient background instead of onto a black patch. The original
   navy lettering underneath gives it a crisp edge. */
.hlogo .bsm,html.dark .hlogo .bsm{background:transparent!important;z-index:3}

/* The business-card wordmark is navy and gold, drawn for a light card. On the
   dark theme a fine light keyline and a soft halo keep "Speak" readable
   without recolouring it. The arrow sits over the still layer; its one-time
   draw (sdArrow() in index.html) only runs while .is-playing is set, so with
   no script, or with reduced motion, it is simply the still arrow. */
html.dark .sd-tree-base{filter:drop-shadow(0 0 .5px rgba(255,255,255,.95)) drop-shadow(0 0 .5px rgba(255,255,255,.8)) drop-shadow(0 0 6px rgba(255,244,250,.42))}
.sd-arrow{position:absolute;inset:0;width:100%;height:100%;z-index:2;overflow:visible;pointer-events:none}
.sd-arrow-draw{display:none}
.sd-arrow.is-playing .sd-arrow-draw{display:inline}

/* Drifting leaves: three, long cycles, far apart. Occasional, never a
   shower. A fourth only flies when the tree is stirred (section 9). */
.sd-leaf{
  position:absolute;z-index:3;width:9px;height:9px;opacity:0;
  background:var(--sd-leaf);border-radius:0 80% 0 80%;
  animation:sd-drift 15s ease-in-out infinite;
}
.sd-leaf.l1{left:26%;top:18%;animation-delay:2.5s}
.sd-leaf.l2{left:72%;top:26%;width:8px;height:8px;animation-duration:19s;animation-delay:9s;animation-name:sd-drift-r}
.sd-leaf.l3{left:18%;top:36%;width:7px;height:7px;animation-duration:23s;animation-delay:15s}
.sd-leaf.l4{left:60%;top:14%;animation:none}

/* Soft sparkles, like light between leaves. */
.sd-spark{
  position:absolute;z-index:3;width:4px;height:4px;border-radius:50%;opacity:0;
  background:var(--sd-spark);box-shadow:0 0 6px 2px rgba(255,236,200,.7);
  animation:sd-twinkle 6s ease-in-out infinite;
}
.sd-spark.s1{left:14%;top:12%;animation-delay:1s}
.sd-spark.s2{left:84%;top:10%;animation-delay:3.2s;animation-duration:7s}
.sd-spark.s3{left:90%;top:40%;animation-delay:5s}
.sd-spark.s4{left:8%;top:44%;animation-delay:2.2s;animation-duration:8s}
html.dark .sd-spark{box-shadow:0 0 7px 2px rgba(253,230,138,.45)}

/* The expanded tree's extra life, all inside the same 210 x 224 box.
   A band of warm light passes over the canopy now and then (masked to the
   artwork, so it only ever lights leaves and flags); golden motes rise out
   of the open book into the branches; one petal drifts down on a long cycle. */
.sd-tree-shine{
  position:absolute;inset:0;overflow:hidden;pointer-events:none;
  -webkit-mask:url("/brand/speakdos-tree.webp?v=2") center/contain no-repeat;
  mask:url("/brand/speakdos-tree.webp?v=2") center/contain no-repeat;
  transform-origin:50% 54%;animation:sd-sway var(--sd-sway-dur) var(--sd-ease) infinite;
}
.sd-tree-shine::before{
  content:"";position:absolute;top:-10%;bottom:-10%;left:0;width:45%;
  background:linear-gradient(100deg,transparent,rgba(255,244,214,.55) 45%,rgba(255,255,255,.7) 50%,rgba(255,244,214,.55) 55%,transparent);
  transform:translateX(-120%) skewX(-12deg);animation:sd-shine 11s ease-in-out 3s infinite;
}
html.dark .sd-tree-shine::before{opacity:.6}
.sd-mote{
  position:absolute;z-index:3;width:3px;height:3px;border-radius:50%;opacity:0;
  background:#ffe29a;box-shadow:0 0 5px 2px rgba(255,210,120,.65);
  animation:sd-rise 9s ease-out infinite;
}
.sd-mote.m1{left:46%;top:54%;animation-delay:1.5s}
.sd-mote.m2{left:55%;top:55%;animation-delay:4.5s;animation-duration:10s;animation-name:sd-rise-r}
.sd-mote.m3{left:50%;top:53%;animation-delay:7.5s;animation-duration:11s}
.sd-leaf.l5{
  left:40%;top:10%;width:8px;height:7px;animation-duration:21s;animation-delay:6s;
  background:linear-gradient(135deg,#ffd1e3,#f28bb4);border-radius:80% 0 80% 0;
}

@keyframes sd-sway{
  0%,100%{transform:rotate(-.8deg) scale(1)}
  30%{transform:rotate(.5deg) skewX(.3deg) scale(1.006)}
  55%{transform:rotate(1deg) scale(1.01)}
  80%{transform:rotate(-.15deg) skewX(-.3deg) scale(1.004)}
}
@keyframes sd-shine{
  0%,62%{transform:translateX(-120%) skewX(-12deg)}
  85%,100%{transform:translateX(260%) skewX(-12deg)}
}
@keyframes sd-rise{
  0%{opacity:0;transform:translate(0,0) scale(.6)}
  12%{opacity:.95}
  70%{opacity:.7}
  100%{opacity:0;transform:translate(-22px,-96px) scale(1)}
}
@keyframes sd-rise-r{
  0%{opacity:0;transform:translate(0,0) scale(.6)}
  12%{opacity:.95}
  70%{opacity:.7}
  100%{opacity:0;transform:translate(26px,-88px) scale(1)}
}
@keyframes sd-breathe{0%,100%{opacity:.6;transform:scale(.97)}50%{opacity:.95;transform:scale(1.03)}}
@keyframes sd-drift{
  0%{opacity:0;transform:translate(0,0) rotate(0)}
  6%{opacity:.9}
  45%{transform:translate(-16px,38px) rotate(120deg)}
  62%{opacity:.75}
  74%,100%{opacity:0;transform:translate(-6px,62px) rotate(220deg)}
}
@keyframes sd-drift-r{
  0%{opacity:0;transform:translate(0,0) rotate(0)}
  6%{opacity:.9}
  45%{transform:translate(14px,34px) rotate(-110deg)}
  62%{opacity:.75}
  74%,100%{opacity:0;transform:translate(4px,58px) rotate(-200deg)}
}
@keyframes sd-twinkle{0%,100%{opacity:0;transform:scale(.4)}45%{opacity:.95;transform:scale(1)}60%{opacity:0;transform:scale(.6)}}

/* ---------- 8. Tree marks and lesson motifs -----------------------------
   The full tree is special: the homepage has it, and the moment after a
   lesson brings it forward again. Hubs carry a small tree mark; lessons and
   reading screens carry only a leaf and a thin gradient line, so learning
   is never decorated over.

     .sd-hub     small tree mark before a hub heading (Start Here, Journey,
                 Identity, Tools, Topics)
     .sd-cheer   larger mark that celebrates when its screen appears
     .sd-motif   leaf + gradient hairline for lesson and content headings
   Being pseudo-elements, they survive the headings' text being rewritten
   in either language, and they can never be tapped. */
.sd-hub::before,.sd-cheer::before{
  content:"";display:inline-block;vertical-align:-.28em;
  width:1.55em;height:1.55em;margin-right:.4rem;
  background:url("/brand/speakdos-mark.webp?v=2") center/contain no-repeat;
  transform-origin:50% 90%;pointer-events:none;
}
.sd-cheer::before{
  width:2.4em;height:2.4em;vertical-align:-.7em;margin-right:.5rem;
  filter:drop-shadow(0 0 10px rgba(236,72,153,.35)) drop-shadow(0 0 16px rgba(139,92,246,.25));
  animation:sd-cheer 1.5s var(--sd-ease) .15s both;
}
.sd-motif::before{
  content:"";display:inline-block;width:.62em;height:.62em;margin-right:.5rem;vertical-align:.08em;
  background:var(--sd-leaf);border-radius:0 80% 0 80%;opacity:.9;pointer-events:none;
}
.sd-motif::after{
  content:"";display:block;width:56px;height:3px;margin-top:.45rem;border-radius:999px;
  background:var(--sd-grad);opacity:.85;pointer-events:none;
}

@keyframes sd-cheer{
  0%{transform:scale(.85) rotate(0);opacity:.4}
  35%{transform:scale(1.1) rotate(-4deg);opacity:1}
  60%{transform:scale(.98) rotate(3deg)}
  80%{transform:scale(1.03) rotate(-1deg)}
  100%{transform:scale(1) rotate(0)}
}
@keyframes sd-nudge{0%,100%{transform:rotate(0)}25%{transform:rotate(-5deg)}55%{transform:rotate(4deg)}80%{transform:rotate(-1.5deg)}}

/* ---------- 9. Moments --------------------------------------------------
   sdTree(kind) in the page adds .is-breeze / .is-stir / .is-celebrate to
   the tree elements on screen for about two seconds. Meaningful moments
   only: choosing a language, starting to learn, finishing a lesson. These
   classes carry no measurement and change nothing but decoration. */
.sd-tree.is-breeze .sd-tree-sway,.sd-tree.is-stir .sd-tree-sway{animation:sd-breeze 1.8s var(--sd-ease)}
.sd-tree.is-stir .sd-tree-sway{animation-duration:2.1s}
.sd-tree.is-breeze .sd-leaf.l4,.sd-tree.is-stir .sd-leaf.l4{animation:sd-gust 2s ease-out}
.sd-tree.is-celebrate .sd-tree-glow{animation:sd-bloom 1.8s ease-out}
.sd-tree.is-celebrate .sd-spark{animation:sd-pop 1.4s ease-out}
.sd-tree.is-breeze .sd-leaf.l5,.sd-tree.is-stir .sd-leaf.l5{animation:sd-gust 2.2s ease-out .15s}
.sd-tree.is-stir .sd-tree-shine::before,.sd-tree.is-celebrate .sd-tree-shine::before{animation:sd-shine 2.2s ease-out}
.sd-tree.is-celebrate .sd-mote{animation-duration:2.2s;animation-delay:0s}
.sd-hub.is-stir::before,.sd-hub.is-breeze::before{animation:sd-nudge 1.4s var(--sd-ease)}
.sd-hub.is-celebrate::before,.sd-cheer.is-celebrate::before{animation:sd-cheer 1.5s var(--sd-ease)}

@keyframes sd-breeze{
  0%,100%{transform:rotate(0)}
  20%{transform:rotate(2deg) skewX(.6deg)}
  45%{transform:rotate(-1.3deg)}
  70%{transform:rotate(.7deg)}
}
@keyframes sd-gust{
  0%{opacity:0;transform:translate(0,0) rotate(0)}
  15%{opacity:.95}
  100%{opacity:0;transform:translate(46px,40px) rotate(260deg)}
}
@keyframes sd-bloom{0%{opacity:.7;transform:scale(1)}35%{opacity:1;transform:scale(1.14)}100%{opacity:.8;transform:scale(1)}}
@keyframes sd-pop{0%{opacity:0;transform:scale(.3)}30%{opacity:1;transform:scale(1.5)}100%{opacity:0;transform:scale(.6)}}

/* Country recognition: the chosen flag arrives with a soft Speakdos halo. */
.fs-seen .fs-flag{position:relative;isolation:isolate;animation:sd-recognize .9s var(--sd-ease) both}
.fs-seen .fs-flag::before{
  content:"";position:absolute;left:50%;top:50%;width:6.5rem;height:6.5rem;margin:-3.25rem 0 0 -3.25rem;z-index:-1;
  border-radius:50%;background:var(--sd-glow);pointer-events:none;
}
@keyframes sd-recognize{0%{transform:scale(.8);opacity:0}55%{transform:scale(1.08);opacity:1}100%{transform:scale(1)}}

/* XP earned in a game: the toast's spark twinkles once. */
.sdtoast .tk{display:inline-block;animation:sd-pop-in .7s var(--sd-ease) both}
@keyframes sd-pop-in{0%{transform:scale(.4) rotate(-30deg);opacity:0}60%{transform:scale(1.25) rotate(10deg);opacity:1}100%{transform:scale(1) rotate(0)}}

/* ---------- 11. The Announcement Space ---------------------------------
   Markup: <aside class="sd-ann" id="sd-ann" hidden> in the header, filled by
   /sd-announce.js. The voice of Speakdos — a single compact pill with a thin
   gradient edge, quieter than the tree, the language choice and Start Free.
   It lives inside the fixed-height header, so it appearing or rotating can
   never move anything else on the page.

     homepage      in the upper left, where the header lockup is hidden
     other screens beside the header mark, sitewide announcements only,
                   and only where there is room (hidden on phones)
     lesson-type   .sd-ann becomes quiet: smaller, flat, no CTA chip */
.sd-ann{flex:0 1 auto;min-width:0;max-width:30rem;display:flex;align-items:center;margin:0 .75rem 0 0}
.sd-ann[hidden]{display:none!important}
.logo+.sd-ann{margin-left:1rem}
html[data-screen="home"] .logo+.sd-ann{margin-left:0}
.sd-hctl{margin-left:auto;flex:0 0 auto}
.sd-ann-item{
  position:relative;display:flex;min-width:0;max-width:100%;
  transition:opacity .7s ease,transform .7s var(--sd-ease);
}
/* The pill: a button that opens the full announcement below it. */
.sd-ann-btn{
  display:inline-flex;align-items:center;gap:.45rem;min-width:0;max-width:100%;
  margin:0;padding:.32rem .5rem .32rem .8rem;border:1px solid transparent;border-radius:999px;
  background:linear-gradient(var(--sd-surface-solid),var(--sd-surface-solid)) padding-box,var(--sd-grad) border-box;
  box-shadow:var(--sd-shadow-sm);
  color:var(--fg);font:inherit;font-size:.82rem;font-weight:600;line-height:1.25;text-align:left;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.sd-ann-t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sd-ann-txt{display:flex;flex-direction:column;align-items:flex-start;min-width:0;gap:.08rem}
.sd-ann-txt .sd-ann-t{max-width:100%}
.sd-ann-lbl{
  font-size:.62rem;font-weight:800;line-height:1.1;letter-spacing:.08em;text-transform:uppercase;
  color:var(--sd-ink-accent);white-space:nowrap;
}
.sd-ann-arrow{
  flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:1.35rem;height:1.35rem;border-radius:999px;
  background:var(--sd-tint);color:var(--sd-ink-accent);
  transition:background-color .2s ease,color .2s ease;
}
.sd-ann-arrow::before{
  content:"";width:.38rem;height:.38rem;margin-top:-.16rem;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(45deg);transition:transform .2s var(--sd-ease),margin .2s var(--sd-ease);
}
.sd-ann-item.is-open .sd-ann-arrow::before{transform:rotate(-135deg);margin-top:.16rem}
.sd-ann-btn:hover .sd-ann-arrow,.sd-ann-btn:focus-visible .sd-ann-arrow,
.sd-ann-item.is-open .sd-ann-arrow{background:var(--primary);color:var(--pf)}
.sd-ann-btn:focus-visible{outline:2px solid var(--primary);outline-offset:2px}

/* The full announcement: a card under the pill, above the page (the header
   is sticky, so it floats over the hero without moving it). */
.sd-ann-panel{
  position:absolute;top:calc(100% + .45rem);left:0;z-index:60;
  width:max-content;min-width:14rem;max-width:min(24rem,calc(100vw - 2rem));box-sizing:border-box;
  padding:.85rem 1rem .9rem;border:1px solid transparent;border-radius:14px;
  background:linear-gradient(var(--sd-surface-solid),var(--sd-surface-solid)) padding-box,var(--sd-grad) border-box;
  box-shadow:var(--sd-shadow-md);color:var(--fg);text-align:left;
  white-space:normal;overflow-wrap:break-word;word-break:normal;
}
.sd-ann-panel[hidden]{display:none!important}
.sd-ann-title{margin:0;font-size:.92rem;font-weight:700;line-height:1.4}
.sd-ann-body{margin:.4rem 0 0;font-size:.86rem;font-weight:500;line-height:1.45;color:var(--muted)}
.sd-ann-link{
  display:inline-flex;align-items:center;margin-top:.75rem;padding:.38rem .85rem;border-radius:999px;
  background:var(--sd-tint);color:var(--sd-ink-accent);font-size:.82rem;font-weight:700;text-decoration:none;
  transition:background-color .2s ease,color .2s ease;
}
.sd-ann-link::after{content:"\00a0\203A"}
.sd-ann-link:hover,.sd-ann-link:focus-visible{background:var(--primary);color:var(--pf)}
.sd-ann-link:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
.sd-ann-item.is-out,.sd-ann-item.is-in{opacity:0;transform:translateY(-3px)}
.sd-ann-item.is-in{transform:translateY(3px)}

/* Lesson-type screens: learning has priority, so the space whispers. */
html[data-screen="lesson"] .sd-ann-btn,html[data-screen="exam"] .sd-ann-btn,
html[data-screen="game"] .sd-ann-btn,html[data-screen="bank"] .sd-ann-btn,
html[data-screen="wstage"] .sd-ann-btn,html[data-screen="daily"] .sd-ann-btn,
html[data-screen="prwalk"] .sd-ann-btn,html[data-screen="sdwalk"] .sd-ann-btn,
html[data-screen="sdprac"] .sd-ann-btn,html[data-screen="tool"] .sd-ann-btn{
  background:transparent;border-color:var(--border);box-shadow:none;
  font-size:.74rem;font-weight:500;color:var(--muted);padding:.22rem .7rem;
}
html[data-screen="lesson"] .sd-ann-arrow,html[data-screen="exam"] .sd-ann-arrow,
html[data-screen="game"] .sd-ann-arrow,html[data-screen="bank"] .sd-ann-arrow,
html[data-screen="wstage"] .sd-ann-arrow,html[data-screen="daily"] .sd-ann-arrow,
html[data-screen="prwalk"] .sd-ann-arrow,html[data-screen="sdwalk"] .sd-ann-arrow,
html[data-screen="sdprac"] .sd-ann-arrow,html[data-screen="tool"] .sd-ann-arrow{background:transparent;color:var(--muted);width:1rem;height:1rem}

/* Away from the homepage, only where the header has room for it. */
@media (max-width:899px){
  html:not([data-screen="home"]) .sd-ann{display:none!important}
}
/* Phones, homepage: the pill shrinks into the corner — up to two short
   lines and the arrow — and never pushes the language toggle, dark mode or
   Start Free off the header. The open panel spans the screen width, less a
   margin, so the full text wraps instead of clipping. */
@media (max-width:600px){
  .sd-ann{margin-right:.5rem}
  .sd-ann-btn{border-radius:14px;padding:.3rem .4rem .3rem .62rem;gap:.3rem;font-size:.72rem}
  .sd-ann-t{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow-wrap:anywhere}
  .sd-ann-arrow{width:1.15rem;height:1.15rem}
  .sd-ann-lbl{font-size:.58rem;letter-spacing:.06em}
  .sd-ann-btn{padding-top:.26rem;padding-bottom:.26rem}
  .sd-ann-panel{position:fixed;top:calc(64px - .25rem);left:1rem;right:1rem;width:auto;min-width:0;max-width:none;max-height:calc(100vh - 80px);overflow-y:auto}
}
@media (max-width:360px){
  .sd-ann-btn{font-size:.66rem;padding:.26rem .4rem .26rem .5rem}
  .sd-ann-panel{left:.6rem;right:.6rem}
}

/* The October 2026 transition notice (/sd-notice.js). In the dropdown it is
   several paragraphs, so its panel is wider and scrolls within the screen.
   On the page it is a plain card in the reading column: full text above the
   lesson list, a summary with "Read the full update" in lessons. Body text
   stays at reading size on phones and wraps rather than clipping. */
.sd-ann-panel.sd-ann-notice{max-width:min(30rem,calc(100vw - 2rem));max-height:calc(100vh - 96px);overflow-y:auto;overscroll-behavior:contain}
.sd-ann-notice .sd-ann-p{color:var(--fg)}
.sd-notice{
  margin:1.25rem 0;padding:1rem 1.15rem 1.05rem;border:1px solid transparent;border-radius:16px;
  background:linear-gradient(var(--sd-surface-solid),var(--sd-surface-solid)) padding-box,var(--sd-grad) border-box;
  box-shadow:var(--sd-shadow-sm);color:var(--fg);
  overflow-wrap:break-word;word-break:normal;
}
.sd-notice[hidden]{display:none!important}
.sd-notice-t{margin:0 0 .5rem;font-size:1.05rem;font-weight:800;line-height:1.35}
.sd-notice-p,.sd-notice-sum{margin:0 0 .6rem;font-size:.95rem;line-height:1.55}
.sd-notice-body[hidden],.sd-notice-sum[hidden]{display:none!important}
.sd-notice-body>.sd-notice-p:last-child{margin-bottom:0}
.sd-notice-s{margin:.85rem 0 .25rem;padding:.8rem 1rem .85rem;box-shadow:none}
.sd-notice-s .sd-notice-t{font-size:.95rem;margin-bottom:.35rem}
.sd-notice-s .sd-notice-p,.sd-notice-s .sd-notice-sum{font-size:.9rem;color:var(--muted)}
.sd-notice-more{
  display:inline-flex;align-items:center;min-height:44px;margin-top:.35rem;padding:.4rem .95rem;
  border:0;border-radius:999px;background:var(--sd-tint);color:var(--sd-ink-accent);
  font:inherit;font-size:.86rem;font-weight:700;cursor:pointer;
  transition:background-color .2s ease,color .2s ease;
}
.sd-notice-more:hover,.sd-notice-more:focus-visible{background:var(--primary);color:var(--pf)}
.sd-notice-more:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
@media (max-width:600px){
  .sd-notice{margin:1rem 0;padding:.9rem .95rem .95rem;border-radius:14px}
  .sd-notice-t{font-size:1rem}
  .sd-notice-p,.sd-notice-sum{font-size:.95rem}
  .sd-notice-s .sd-notice-p,.sd-notice-s .sd-notice-sum{font-size:.92rem}
  .sd-notice-more{width:100%;justify-content:center}
}

/* ---------- 10. Reduced motion ------------------------------------------
   The still design stays; every decorative movement stops. Drifting leaves
   and sparkles are removed outright rather than frozen mid-air. */
@media (prefers-reduced-motion:reduce){
  .sd-tree-canopy,.sd-tree-sway,.sd-tree-glow,.sd-hub::before,.sd-cheer::before,
  .fs-seen .fs-flag,.sdtoast .tk,.bsx,.hlogo .bsm::after{animation:none!important}
  .sd-tree-glow{opacity:.8}
  .sd-leaf,.sd-spark,.sd-mote,.sd-tree-shine{display:none!important}
  .sd-arrow .sd-arrow-draw{display:none!important}
  .sd-arrow .sd-arrow-rest{opacity:1!important}
  .sd-ann-item,.sd-ann-arrow,.sd-ann-arrow::before,.sd-ann-link,.sd-notice-more{transition:none}
  .sd-ann-item.is-in,.sd-ann-item.is-out{transform:none}
  body::after{transition:none}
}
