/* WorksheetHub — base layer: reset, layout primitives, app shell. */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5 {
  font-family: var(--font-head); color: var(--text);
  line-height: 1.25; margin: 0 0 var(--s3);
  letter-spacing: -.011em;      /* tight enough to feel set, loose enough to read */
  text-wrap: balance;
}
h1 { font-size: var(--step-4); font-weight: 700; line-height: 1.15; }
h2 { font-size: var(--step-3); font-weight: 700; line-height: 1.2; }
h3 { font-size: var(--step-2); font-weight: 600; }
h4 { font-size: var(--step-1); font-weight: 600; }
p  { text-wrap: pretty; }
p  { margin: 0 0 var(--s4); color: var(--text-2); }

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
img, svg { max-width: 100%; }

/* Icons sit on the text baseline and inherit its colour, so they can be used
   inline without every call site adding alignment rules. */
.ico-svg { display: inline-block; vertical-align: -0.15em; flex: none; }
.ico { display: inline-flex; align-items: center; justify-content: center; flex: none; }
ul, ol { margin: 0 0 var(--s4); padding-left: var(--s5); color: var(--text-2); }

:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-sm); }

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--s5); }
.wrap-wide { max-width: 1440px; }
.section { padding-block: var(--s8); }
.section-tight { padding-block: var(--s7); }
.stack > * + * { margin-top: var(--s4); }
.row { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.row-nowrap { flex-wrap: nowrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; }
.grow { flex: 1; }
.center { text-align: center; }
.muted { color: var(--text-2); }
.small { font-size: var(--step--1); }
.mono { font-variant-numeric: tabular-nums; }
.hidden { display: none !important; }
/* The `hidden` attribute is only as strong as the UA rule behind it, so any
   class that sets `display` silently defeats it — which is how the exercise
   player stayed on screen underneath a "worksheet not found" message. */
[hidden] { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: var(--s4); top: -100px; z-index: 200;
  background: var(--band-from); color: #fff; padding: var(--s3) var(--s4); border-radius: var(--r-sm);
}
.skip-link:focus { top: var(--s4); }

.grid { display: grid; gap: var(--s4); }
/* minmax(0, …) throughout: without it a grid track refuses to shrink below the
   min-content width of what is inside it, which is how a long word or a wide
   table pushes a whole page into horizontal scroll. */
.grid > * { min-width: 0; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* Two-column sections that become one column on small screens. */
.grid-split      { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
.grid-split-wide { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); align-items: start; }

/* ------------------------------- header ------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
/* The header bar is full-bleed, so its contents do not have to line up with
   the 1200px article column — and at 1200 they genuinely do not fit: brand,
   six nav links and five controls need about 1250. */
.site-header .wrap {
  display: flex; align-items: center; gap: var(--s5);
  height: var(--header-h); flex-wrap: nowrap; max-width: 1400px;
}

.brand { display: inline-flex; align-items: center; gap: var(--s3); font-family: var(--font-head); font-weight: 700; font-size: var(--step-1); color: var(--text); }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  background: linear-gradient(140deg, var(--band-from), var(--band-to));
  display: grid; place-items: center;
  box-shadow: 0 2px 6px rgba(30, 27, 120, .32);
}
.brand-mark-lg { width: 54px; height: 54px; border-radius: 15px; margin-inline: auto; }
.brand-word { letter-spacing: -.015em; }
.brand-word-accent { color: var(--link); }
[data-mode="teacher"] .brand-word-accent { color: var(--text-2); }
[data-mode="teacher"] .brand-mark { background: linear-gradient(140deg, #1E293B, #0B1120); box-shadow: var(--shadow-1); }

.lang-picker { position: relative; display: inline-flex; align-items: center; }
/* One of the two is always hidden — see buildHeader. */
.lang-in-nav { display: none; }
.lang-globe { position: absolute; left: 9px; display: inline-flex; color: var(--text-3); pointer-events: none; }
.lang-select {
  appearance: none; height: 38px; padding: 0 var(--s3) 0 30px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text-2);
  font: inherit; font-size: var(--step--1); font-weight: 600; cursor: pointer;
}
.lang-select:hover { color: var(--text); border-color: var(--border-strong); }
.lang-select:focus-visible { outline: none; box-shadow: var(--ring); }

/* `flex: 1`, not `margin-inline: auto`. An auto margin on a flex item absorbs
   ALL the free space into the margins and then lets the item itself shrink
   below its content — so the nav sat centred in a box narrower than its own
   links and quietly painted them over the buttons beside it. Taking the free
   space as width and centring the content inside gets the same look and keeps
   the items in their box. */
.main-nav {
  display: flex; align-items: center; justify-content: center;
  gap: var(--s1); flex: 1 1 auto; min-width: 0;
}
.main-nav a {
  padding: var(--s2) var(--s3); border-radius: var(--r-sm);
  color: var(--text-2); font-weight: 500; font-size: var(--step-0);
  /* Translated labels are longer than the English ones. A wrapped nav item
     beside single-line ones reads as breakage, so the row keeps its items
     whole and gives up its own spare width instead. */
  white-space: nowrap;
}
.main-nav a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.main-nav a[aria-current="page"] { color: var(--brand-ink); background: var(--primary-tint); font-weight: 600; }

.header-actions { display: flex; align-items: center; gap: var(--s2); }
.icon-btn {
  width: 38px; height: 38px; display: grid; place-items: center; flex: none;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text-2); cursor: pointer; font-size: 16px;
}
.icon-btn:hover { color: var(--text); border-color: var(--border-strong); }
.nav-toggle { display: none; }

.avatar {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  background: var(--primary-light); color: var(--brand-ink);
  display: grid; place-items: center; font-weight: 700; font-size: var(--step--1);
  font-family: var(--font-head);
}
.user-chip { display: flex; align-items: center; gap: var(--s2); padding: var(--s1) var(--s2); border-radius: var(--r-pill); border: 1px solid var(--border); background: var(--surface); cursor: pointer; }
.user-chip:hover { border-color: var(--border-strong); text-decoration: none; }
.user-chip .name { font-size: var(--step--1); font-weight: 600; color: var(--text); }

/* --------------------------- app sidebar layout --------------------------- */
.app-layout { display: grid; grid-template-columns: 248px minmax(0, 1fr); gap: var(--s5); align-items: start; padding-block: var(--s5); }
.side-nav { position: sticky; top: calc(var(--header-h) + var(--s5)); display: flex; flex-direction: column; gap: var(--s1); }
.side-nav .side-label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); padding: var(--s4) var(--s3) var(--s2); }
.side-nav a {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3); border-radius: var(--r-md); color: var(--text-2); font-weight: 500;
}
.side-nav a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.side-nav a[aria-current="page"] { background: var(--primary-tint); color: var(--brand-ink); font-weight: 600; }
.side-nav .ico { width: 20px; text-align: center; flex: none; }
.side-nav .pill-count { margin-left: auto; }

/* ------------------------------- footer ------------------------------- */
.site-footer { border-top: 1px solid var(--border); background: var(--surface); margin-top: var(--s8); padding-block: var(--s7) var(--s5); }
.footer-grid { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: var(--s6); }
.footer-grid h5 { font-size: var(--step--1); text-transform: uppercase; letter-spacing: .07em; color: var(--text-3); margin-bottom: var(--s3); }
.footer-links { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s2); }
.footer-links a { color: var(--text-2); font-size: var(--step-0); }
.footer-links a:hover { color: var(--link); }
.footer-bottom { margin-top: var(--s6); padding-top: var(--s4); border-top: 1px solid var(--border); display: flex; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; font-size: var(--step--1); color: var(--text-3); }

/* ---------------------------- mobile bottom nav ---------------------------- */
.bottom-nav { display: none; }

/* Above the mobile breakpoint the header sheds controls before it sheds
   space for the nav, in order of how easily each is reached elsewhere. */
@media (min-width: 901px) and (max-width: 1320px) {
  /* Search has its own page, its own box on that page, and a bottom-bar entry
     on small screens. It is the first thing the header can spare. */
  .header-actions > .icon-btn:first-child { display: none; }
}
@media (min-width: 901px) and (max-width: 1240px) {
  .site-header .wrap { gap: var(--s3); }
  .main-nav { gap: 0; }
  .main-nav a { padding-inline: var(--s2); }
  .lang-select { padding-right: var(--s2); }
  /* Sign in lives one click inside Get started, so the secondary button goes
     before the primary one does. */
  .header-actions > .btn-ghost { display: none; }
  .theme-btn { display: none; }
}

/* When even that is not enough the nav becomes the menu, at whatever width
   that turns out to be. A media query cannot make this decision: the nav is
   nine words in English and eleven longer ones in German, so the width where
   it stops fitting is a property of the content, not of the device. shell.js
   measures and sets `.nav-as-menu`; the rules below are shared with the
   ≤900px block, which stays as the floor in case the script never runs. */
.site-header.nav-as-menu .main-nav {
  position: fixed; inset: var(--header-h) 0 auto 0; z-index: 55;
  flex-direction: column; align-items: stretch; gap: 0; margin: 0;
  background: var(--surface); border-bottom: 1px solid var(--border);
  padding: var(--s3); box-shadow: var(--shadow-2);
}
.site-header.nav-as-menu .main-nav[hidden] { display: none; }
.site-header.nav-as-menu .main-nav a { padding: var(--s3) var(--s4); border-radius: var(--r-md); }
.site-header.nav-as-menu .nav-toggle { display: grid; }
.site-header.nav-as-menu .lang-in-header { display: none; }
.site-header.nav-as-menu .lang-in-nav {
  display: flex; margin-top: var(--s2); padding-top: var(--s3);
  border-top: 1px solid var(--border);
}
.site-header.nav-as-menu .lang-in-nav .lang-select { width: 100%; height: 42px; }

@media (max-width: 900px) {
  .app-layout { grid-template-columns: minmax(0, 1fr); }
  .grid-split, .grid-split-wide { grid-template-columns: minmax(0, 1fr); }
  .side-nav { display: none; }
  .main-nav {
    position: fixed; inset: var(--header-h) 0 auto 0; z-index: 55;
    flex-direction: column; align-items: stretch; gap: 0; margin: 0;
    background: var(--surface); border-bottom: 1px solid var(--border);
    padding: var(--s3); box-shadow: var(--shadow-2);
  }
  .main-nav[hidden] { display: none; }
  .main-nav a { padding: var(--s3) var(--s4); border-radius: var(--r-md); }
  /* At 390px the header fits the brand, one call to action and the menu
     button. The language control moves into the panel that button opens. */
  .lang-in-header { display: none; }
  .lang-in-nav {
    display: flex; margin-top: var(--s2); padding-top: var(--s3);
    border-top: 1px solid var(--border);
  }
  .lang-in-nav .lang-select { width: 100%; height: 42px; }
  .nav-toggle { display: grid; }
  .site-header .wrap { gap: var(--s3); }
  /* Search lives in the library and the bottom bar on small screens, so the
     header keeps only what cannot be reached another way. */
  .header-actions > .icon-btn:first-child { display: none; }
  .user-chip .name { display: none; }
  .footer-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s5); }

  .bottom-nav {
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 70;
    background: var(--surface); border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .bottom-nav a {
    display: grid; gap: 2px; justify-items: center; padding: var(--s2) 0 var(--s3);
    color: var(--text-3); font-size: 11px; font-weight: 600;
  }
  .bottom-nav a:hover { text-decoration: none; }
  .bottom-nav a[aria-current="page"] { color: var(--link); }
  .bottom-nav .ico { font-size: 18px; line-height: 1.2; }
  .bottom-nav a > span:last-child { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Five equal columns only work if each is allowed to be narrower than its
     label. Without min-width:0 a grid track never shrinks below its content,
     so the bar ran 18px off a 320px screen. */
  .bottom-nav a { min-width: 0; }
  body { padding-bottom: 62px; }
}
/* The narrowest phones still in use. Labels shrink rather than the bar
   overflowing, and long single words are allowed to break. */
@media (max-width: 380px) {
  .bottom-nav a { font-size: 10px; }
  .bottom-nav a > span:last-child { letter-spacing: -.01em; }
}

@media (max-width: 560px) {
  .wrap { padding-inline: var(--s4); }
  .brand { font-size: var(--step-0); }
  /* One call to action in the header is enough when space is this tight. */
  .header-actions .btn-ghost { display: none; }
  /* Below this width the header cannot hold brand, theme toggle, call to
     action and menu button at once — it overflowed by 24px. The theme toggle
     is the one that also lives in Settings, so it is the one that goes. */
  .header-actions > .theme-btn { display: none; }
  .site-header .wrap { gap: var(--s4); }
  .section { padding-block: var(--s6); }
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
}
