/* ============================================================
   YBB internal shell · design/internal/shell.css

   The one source for how the internal apps look: the header, the type scale on Poppins, buttons,
   focus rings, and a handful of tokens the public site does not need. It is read together with
   tokens.css, which scripts/sync-internal-css.mjs generates from public/css/site.css (:root), so
   every colour, weight and size here is the public site's own.

   Edit this file only. Then run

       node scripts/sync-internal-css.mjs

   which copies it (and tokens.css and the Poppins files) into team/public/static/ and
   board/public/static/, and writes the "header" section alone to public/css/team.css for the two
   internal pages of the main site. `npm test` in team/ and in board/ fails while a copy is stale.

   Sections are marked "---- section: name ----". The header section must stand on its own on the
   main site, where only site.css is loaded beside it: it uses site.css tokens only (never the ones
   in the "tokens" section here), and its targets are a plain 44px. Its class names start with th-
   (it was the team header first) so nothing collides with site.css.

   Language and consent rules apply to every word rendered on these pages: person-first language,
   sentence case, no em dashes, no exclamation points. See CLAUDE.md, "Internal apps".
   ============================================================ */

/* ---- section: fonts ---- */
/* Poppins, self-hosted (SIL Open Font License; design/internal/fonts/). Nothing on a gated page
   loads from a CDN. Both apps serve these files under /static/fonts/. */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/poppins-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/poppins-latin-500-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/poppins-latin-600-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/fonts/poppins-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- section: tokens ---- */
/* Tokens the internal apps add on top of site.css. Everything else comes from tokens.css. */
:root {
  /* The smallest target. The reading size below raises it. */
  --tap: 44px;
  --radius: 12px;

  /* The shell on team.* and board.*: the sidebar and the page side by side on wide screens (the
     header's inner width follows it). The page column itself comes out near the old 56rem. */
  --shell-max: 72rem;
  /* Signed-in pages are laid out like an app: the header and the sidebar stay pinned to the left edge
     on every page, and only the page's own column changes width (wider on a page of tables), so
     nothing jumps when you move between pages. */
  --main-max: 56rem;
  --main-max-wide: 84rem;
  --shell-pad: 16px;

  /* The spacing scale (4px base). Tight inside a group, generous between groups: rows in a list sit
     a step apart, sections three or four steps. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* The type scale for app pages: fixed sizes, about 1.2 apart, so a heading in a narrow column reads
     the same as one on a wide screen. site.css's fluid sizes stay for the public site. */
  --fs-h1: 2rem;
  --fs-h2: 1.3125rem;
  --fs-h3: 1.0625rem;
  --fs-meta: 0.875rem;
  --fs-lede: 1.0625rem;

  /* Surfaces: the warm sand page, white panels on it with a hairline edge. Nothing nests a bordered
     box inside another. */
  --panel-edge: 1px solid var(--border-hairline);
  --side-w: 232px;
  --side-w-collapsed: 56px;

  /* Links are deep teal on the internal pages: they come in lists and rows here, where the public
     site's gold link colour would read as a wall of accent. Everything else keeps site.css's value. */
  --text-link: var(--ybb-deep-teal);
  --text-link-hover: var(--teal-900);

  /* Status colours (AA on their backgrounds). Not in the public site's tokens. */
  --ok: #1D6A44;
  --ok-bg: #E7F4EC;
  --warn: #7A4A00;
  --warn-bg: #FFF4DD;
  --bad: #A3261B;
  --bad-bg: #FCECEA;
  --info-bg: var(--teal-50);
}

/* ---- section: base ---- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--surface-page-warm);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--text-body-md);
  font-weight: var(--weight-regular);
  line-height: var(--leading-body);
}
img { max-width: 100%; height: auto; }
h1, h2, h3 {
  font-family: var(--font-display);
  color: var(--text-heading);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-heading);
  overflow-wrap: break-word;
  text-wrap: balance;
}
/* App pages use the fixed scale in the tokens section: a clear step from the page title to a section
   to a row's title, with more space above a heading than below it. */
h1 { font-size: var(--fs-h1); line-height: 1.2; letter-spacing: -0.015em; margin: var(--space-2) 0 var(--space-3); }
h2 { font-size: var(--fs-h2); line-height: 1.3; letter-spacing: -0.01em; margin: 0 0 var(--space-3); }
h3 { font-size: var(--fs-h3); line-height: 1.35; margin: 0 0 var(--space-1); }
p { margin: 0 0 0.9rem; text-wrap: pretty; }
::selection { background: var(--gold-300); color: var(--teal-900); }
input, textarea { caret-color: var(--ybb-deep-teal); }
/* On a phone the two largest steps come down a little; everything that uses the tokens follows. */
@media (max-width: 639px) {
  :root { --fs-h1: 1.75rem; --fs-h2: 1.25rem; }
}
/* Links keep an underline (so they never rely on colour alone), drawn thin and soft so a page of
   links does not shout; it firms up on hover. */
a { color: var(--text-link); text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); }
a:hover { color: var(--text-link-hover); text-decoration-thickness: 2px; text-decoration-color: currentColor; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; background: var(--teal-50); padding: 0.1em 0.35em; border-radius: 4px; overflow-wrap: anywhere; }
:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 3px; border-radius: 4px; }

/* The reading size: for pages people read slowly and carefully (the board). Put the class on
   <body>. Body text steps up from body-md to body-lg, headings and targets grow by the same ratio. */
body.reading {
  --tap: 52px;
  --reading-step: 1.125;
  /* The type tokens themselves step up, so every rule that uses them (headings, a page's own titles,
     the quiet lines) grows together and nothing is multiplied twice. */
  --fs-h1: 2.25rem;
  --fs-h2: 1.4766rem;
  --fs-h3: 1.1953rem;
  --fs-meta: 1rem;
  --fs-lede: 1.1875rem;
  font-size: var(--text-body-lg);
  line-height: var(--leading-body-loose);
}
@media (max-width: 639px) {
  body.reading { --fs-h1: 1.875rem; --fs-h2: 1.375rem; }
}

.wrap { max-width: var(--shell-max); margin: 0 auto; padding: 0 var(--shell-pad); }
/* A page of tables takes a wider column (body.is-wide), so rows of data do not wrap. */
body.is-wide { --main-max: var(--main-max-wide); }
.muted { color: var(--text-muted); }
.block { display: block; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: 16px; top: -80px; z-index: 200;
  background: var(--action-primary); color: var(--action-primary-text); padding: 12px 20px;
  font-weight: var(--weight-semibold); border-radius: var(--radius);
}
.skip:focus { top: 12px; }

.demo-banner { margin: 0; padding: 6px 16px; text-align: center; background: var(--gold-200); color: var(--teal-900); font-size: var(--fs-meta); line-height: 1.4; }

main { padding-top: var(--space-5); padding-bottom: var(--space-8); }
main:focus { outline: none; }
.lede { font-size: var(--fs-lede); color: var(--ink-700); max-width: 38rem; margin-bottom: var(--space-6); }
.crumb { margin: 0 0 var(--space-1); }
.crumb a { display: inline-flex; align-items: center; gap: 6px; min-height: var(--tap); font-weight: var(--weight-medium); font-size: 0.9375rem; text-decoration: none; }
.crumb a:hover { text-decoration: underline; }
.foot { color: var(--text-muted); font-size: var(--fs-meta); padding: var(--space-5) 0 var(--space-6); }
.foot p { margin: 0; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; transition: none !important; animation: none !important; }
}

/* ---- section: header ---- */
/* The internal header: a menu button (phones), the lotus mark at 44px tall (the public site's
   header size, width from its own proportions), a wordmark, the "Internal" tag, then Search, the
   person and Sign out on the right. The rows of the Hub are in the sidebar (section "side"), or, on
   the main site, in the list the menu button opens. Every target is 44px. On the main site this
   section is loaded as public/css/team.css beside site.css, which already defines the tokens and
   Poppins, so it uses site.css tokens only. */
.team-header {
  background: var(--ybb-deep-teal);
  color: var(--ybb-white);
  border-bottom: 1px solid var(--border-inverse);
  font-family: var(--font-sans);
}
/* The focus ring on the header: the site's gold-600 ring fades into deep teal, so the header
   uses the brand gold. */
.team-header :focus-visible { outline: 3px solid var(--ybb-warm-gold); outline-offset: 3px; border-radius: 4px; }
.th-top {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
  max-width: var(--shell-max, var(--content-max)); margin: 0 auto; padding: 8px var(--shell-pad, var(--content-pad));
}
.th-logo {
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  color: var(--ybb-white); text-decoration: none; font-weight: var(--weight-semibold); font-size: 1.15rem;
}
.th-logo img { height: 44px; width: auto; }
.th-logo:hover { color: var(--gold-400); }
.th-tag {
  display: inline-flex; align-items: center; min-height: 28px; padding: 0 12px; border-radius: 100px;
  background: var(--ybb-warm-gold); color: var(--teal-900);
  font-size: 0.8rem; font-weight: var(--weight-semibold); letter-spacing: 0.04em;
}
.th-person { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.th-person form { margin: 0; }
.th-chip {
  display: inline-flex; align-items: center; min-height: 32px; padding: 0 4px;
  color: var(--teal-100); font-size: 0.9rem;
}
.th-signout, .th-signin {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px; background: transparent;
  color: var(--ybb-white); border: 1px solid rgba(255, 255, 255, 0.6); border-radius: 100px;
  font: inherit; font-size: 0.9rem; text-decoration: none; cursor: pointer;
}
.th-signin { margin-left: auto; }
.th-signout:hover, .th-signin:hover { border-color: var(--gold-400); color: var(--gold-400); }

/* Line icons from the sprite (design/internal/icons.svg): 20px, the text's colour. */
.ic { width: 20px; height: 20px; flex: 0 0 auto; }

/* The menu button. On team.* and board.* it opens the sidebar as a sheet on a phone (class
   th-menu-sheet; shell.js un-hides it, and wide screens have the sidebar itself). On the main site
   it opens the Hub list below. */
.th-menu {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-width: 44px; min-height: 44px; padding: 0 10px;
  background: transparent; color: var(--ybb-white); border: 1px solid rgba(255, 255, 255, 0.6); border-radius: 100px;
  font: inherit; font-size: 0.9rem; cursor: pointer;
}
.th-menu:hover, .th-menu[aria-expanded="true"] { border-color: var(--gold-400); color: var(--gold-400); }
.th-menu[hidden] { display: none; }

/* Search: a link to the search page, with the shortcut shown the way a keyboard draws it. */
.th-search {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 14px; margin-left: auto;
  color: var(--ybb-white); text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.4); border-radius: 100px;
  font-size: 0.9rem;
}
.th-search:hover { border-color: var(--gold-400); color: var(--gold-400); }
.th-search kbd {
  font-family: inherit; font-size: 0.75rem; line-height: 1; padding: 4px 6px; border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.35); color: var(--teal-100);
}
.th-search ~ .th-person { margin-left: 0; }
/* Help: one place to report a problem or send feedback (team site /help), beside Search. */
.th-help {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 14px;
  color: var(--ybb-white); text-decoration: none; border: 1px solid rgba(255, 255, 255, 0.4); border-radius: 100px;
  font-size: 0.9rem;
}
.th-help:hover { border-color: var(--gold-400); color: var(--gold-400); }

/* The Hub list the main site's menu button opens (public/js/team-header.js draws it): the same
   rows as the sidebar, in sections, under the button. */
.th-hubwrap { position: relative; }
.th-hub {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 120;
  width: min(22rem, calc(100vw - 32px)); max-height: min(70vh, 32rem); overflow-y: auto;
  background: var(--ybb-white); color: var(--text-body); border: 1px solid var(--border-default); border-radius: 12px;
  box-shadow: 0 12px 32px rgba(22, 35, 44, 0.18); padding: 8px;
}
.th-hub[hidden] { display: none; }
.th-hub :focus-visible { outline-color: var(--focus-ring); }
.th-hub-h {
  margin: 10px 12px 4px; font-size: var(--text-label); font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-muted);
}
.th-hub ul { list-style: none; margin: 0; padding: 0; }
.th-hub li { margin: 0; }
.th-hub a {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; border-radius: 8px;
  color: var(--ybb-deep-teal); text-decoration: none; font-size: 0.95rem;
}
.th-hub a:hover { background: var(--teal-50); }
.th-hub a[aria-current="page"] { background: var(--teal-50); box-shadow: inset 3px 0 0 var(--ybb-warm-gold); font-weight: var(--weight-semibold); }
.th-hub .ic { color: var(--teal-600); }
.th-soon {
  display: inline-block; margin-left: auto; padding: 1px 8px; border-radius: 100px;
  background: var(--sand-200); color: var(--ink-700);
  font-size: 0.7rem; font-weight: var(--weight-semibold); letter-spacing: 0.04em; text-transform: uppercase;
}

/* A page's own extra link (the main site's internal pages keep one for people without a team
   session, who have no Hub list). */
.th-extra { max-width: var(--shell-max, var(--content-max)); margin: 0 auto; padding: 0 var(--shell-pad, var(--content-pad)) 6px; }
.th-extra a { display: inline-flex; align-items: center; min-height: 44px; color: var(--gold-300); font-size: 0.95rem; }
.th-extra a:hover { color: var(--ybb-white); }
.th-extra[hidden] { display: none; }

.th-visually-hidden {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 639px) {
  /* On a phone the Search link is its icon alone; the word stays for screen readers. */
  .th-search-label {
    position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .th-search kbd { display: none; }
  .th-search { padding: 0 11px; }
  .th-help-label {
    position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .th-help { padding: 0 11px; }
}
@media (min-width: 640px) {
  .th-top { flex-wrap: nowrap; }
}
/* On a phone inside the apps the header is one row: menu, mark, tag, search. The person and Sign out
   move into the menu sheet (nav.js draws them there), the way a phone app keeps the account behind
   its menu. The main site's two internal pages have no sheet, so they keep both. */
@media (max-width: 899px) {
  body.has-side .th-top { flex-wrap: nowrap; gap: 4px 8px; }
  body.has-side .th-person { display: none; }
  /* Help moves into the sheet beside Sign out, so the row fits beside the menu button. A volunteer
     teacher's header has no menu button (they open the sheet from the bottom bar's More), so theirs
     keeps Help in reach. */
  body.has-side:not(.teach-only) .th-help { display: none; }
  body.has-side .th-tag { min-height: 24px; padding: 0 10px; font-size: 0.75rem; }
}
@media (min-width: 900px) {
  .th-menu-sheet { display: none; }
}

/* The Cmd+K search dialog (public/static/palette.js builds it). Uses site.css tokens only, like the
   header, because the main site's internal pages load it from public/css/team.css. */
.pal { position: fixed; inset: 0; z-index: 1000; }
.pal[hidden] { display: none; }
.pal-backdrop { position: absolute; inset: 0; background: rgba(22, 35, 44, 0.55); }
.pal-dialog {
  position: absolute; left: 50%; top: min(10vh, 88px); transform: translateX(-50%);
  width: min(680px, calc(100% - 24px)); max-height: calc(100vh - min(10vh, 88px) - 24px);
  display: flex; flex-direction: column; background: var(--ybb-white); border-radius: 16px;
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.5); overflow: hidden;
}
@media (max-width: 560px) { .pal-dialog { top: 12px; max-height: calc(100dvh - 24px); } }
.pal-top { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--teal-200); }
.pal-input { flex: 1; min-width: 0; min-height: 44px; font: 500 17px/1.4 var(--font-sans); color: var(--teal-900); border: 0; background: transparent; padding: 6px 2px; }
.pal-input:focus { outline: none; }
.pal-input::placeholder { color: var(--ink-600); }
.pal-close { min-height: 32px; font: 600 12px/1 var(--font-sans); color: var(--ink-600); background: var(--sand-100); border: 1px solid var(--teal-200); border-radius: 6px; padding: 6px 8px; cursor: pointer; }
.pal-count { font-size: 12px; color: var(--ink-600); padding: 8px 16px 0; margin: 0; min-height: 26px; }
.pal-list { position: relative; list-style: none; overflow-y: auto; padding: 4px 8px 8px; margin: 0; flex: 1 1 auto; overscroll-behavior: contain; }
.pal-item { margin: 0; }
.pal-link { display: flex; gap: 10px; align-items: flex-start; padding: 9px 12px; border-radius: 10px; border-left: 3px solid transparent; color: var(--ink-700); text-decoration: none; }
.pal-item[aria-selected="true"] .pal-link { background: var(--teal-50); border-left-color: var(--gold-500); }
.pal-kind { flex: 0 0 auto; margin-top: 2px; font-weight: 600; font-size: 11.5px; color: var(--teal-700); background: var(--gold-100); border-radius: 4px; padding: 1px 6px; white-space: nowrap; }
.pal-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pal-title { font-weight: 600; color: var(--teal-900); overflow-wrap: anywhere; }
.pal-crumb { font-size: 11.5px; color: var(--ink-600); }
.pal-text { font-size: 14px; line-height: 1.45; overflow-wrap: anywhere; }
.pal-text mark, .search-text mark { background: var(--gold-200); color: var(--teal-900); border-radius: 3px; padding: 0 1px; box-shadow: inset 0 -2px 0 var(--gold-500); }
.pal-ask .pal-kind { background: var(--teal-700); color: var(--ybb-white); }
.pal-foot { font-size: 12px; color: var(--ink-600); padding: 10px 16px; margin: 0; border-top: 1px solid var(--teal-200); background: var(--sand-100); }
@media (hover: none) and (max-width: 560px) { .pal-foot { display: none; } }
body.pal-open { overflow: hidden; }

/* ---- section: buttons ---- */
/* .button is the quiet one (deep teal outline), .button-primary the site's gold with teal text,
   .button-secondary the site's solid deep teal. One primary button per screen. */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--tap); padding: 8px 22px;
  background: var(--ybb-white); color: var(--teal-900);
  border: 2px solid var(--ybb-deep-teal); border-radius: var(--radius);
  font: inherit; font-weight: var(--weight-semibold); line-height: 1.25; text-align: center; text-decoration: none;
  cursor: pointer; transition: var(--transition-control);
}
.button:hover { background: var(--action-quiet-hover); color: var(--teal-900); }
.button-primary { background: var(--action-primary); border-color: var(--action-primary); color: var(--action-primary-text); }
.button-primary:hover { background: var(--action-primary-hover); border-color: var(--action-primary-hover); color: var(--action-primary-text); }
.button-primary:active { background: var(--action-primary-active); border-color: var(--action-primary-active); color: var(--action-primary-text); }
.button-secondary { background: var(--action-secondary); border-color: var(--action-secondary); color: var(--action-secondary-text); }
.button-secondary:hover { background: var(--action-secondary-hover); border-color: var(--action-secondary-hover); color: var(--action-secondary-text); }
.button-danger { background: var(--bad); border-color: var(--bad); color: var(--ybb-white); }
.button-danger:hover { background: #8A1F16; border-color: #8A1F16; color: var(--ybb-white); }
.button-small { padding: 4px 16px; font-size: 0.95em; }
/* A button that cannot be used yet looks it, whichever kind it is, and says why nearby. */
.button:disabled, .button[aria-disabled="true"],
.button-primary:disabled, .button-secondary:disabled, .button-danger:disabled {
  background: var(--sand-200); border-color: var(--sand-300); color: var(--ink-600); cursor: not-allowed;
}
.button-block { display: flex; width: 100%; }
.button-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* ---- section: tips ---- */
/* A tip: a small "?" after a word someone may not know, and the plain sentence that says what it
   is. tip(text, about) in each app's src/lib/html.js draws it:
     <span class="tip"><button type="button" class="tip-btn"><span class="tip-mark" aria-hidden="true">?</span>
       <span class="visually-hidden">More about clearances</span></button><span class="tip-text">...</span></span>
   The sentence is always in the page: without JavaScript a screen reader reads it after the button,
   and shell.js makes it the button's description instead. On screen it opens as a bubble on hover,
   on keyboard focus and on a tap or click, which keeps it open (.is-open); Escape, a second tap or
   a tap elsewhere shuts it (shell.js adds .is-shut, which holds it shut until the pointer or focus
   moves away).
   The button is a full --tap target; its negative margins keep it from opening up the line. Never
   put a tip inside a link, a button or a <label>, nor inside a heading or a <legend> (its button would
   join their name). Beside a heading or a label, wrap the two in .with-tip:
     <div class="with-tip"><h2 id="clr-h">My clearances</h2> ${tip(...)}</div>
   Under a <legend>, put it at the end of the hint that follows. */
.tip { position: relative; display: inline-block; vertical-align: middle; line-height: 1; }
.with-tip { display: flex; flex-wrap: wrap; align-items: center; gap: 0 4px; margin: 0 0 0.5rem; }
.with-tip > :not(.tip) { margin-bottom: 0; }
.tip-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--tap); min-height: var(--tap);
  margin: calc((1.25rem - var(--tap)) / 2) calc((1.25rem - var(--tap)) / 2 + 4px);
  padding: 0; border: 0; background: none; color: var(--ybb-deep-teal);
  font: inherit; font-family: var(--font-body); cursor: pointer;
}
.tip-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.25rem; height: 1.25rem; border: 1.5px solid currentColor; border-radius: 50%;
  font-size: 0.8rem; font-weight: var(--weight-semibold); line-height: 1; letter-spacing: 0;
  transition: var(--transition-control);
}
.tip-btn:hover .tip-mark, .tip.is-open .tip-mark { background: var(--ybb-deep-teal); color: var(--ybb-white); }
.tip-btn:focus-visible { outline: none; }
.tip-btn:focus-visible .tip-mark { outline: 3px solid var(--focus-ring); outline-offset: 3px; }
/* Closed: out of sight, still read. */
.tip-text {
  position: absolute; z-index: 60; top: calc(100% + 10px); left: 50%;
  width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* Open: a bubble under the mark (above it, .tip-up, when the screen runs out below). --tip-shift
   is set by shell.js to keep the bubble on screen; the arrow stays over the mark. */
.tip.is-open:not(.is-shut) .tip-text,
.tip:not(.is-shut):has(.tip-btn:focus-visible) .tip-text {
  width: max-content; max-width: min(20rem, calc(100vw - 32px));
  height: auto; margin: 0; padding: 10px 14px; overflow: visible; clip: auto; white-space: normal;
  transform: translateX(calc(-50% + var(--tip-shift, 0px)));
  background: var(--teal-900); color: var(--ybb-white); border-radius: 10px;
  box-shadow: 0 6px 20px rgba(22, 35, 44, 0.22);
  font-family: var(--font-body); font-size: var(--text-body-sm); font-weight: var(--weight-regular);
  line-height: 1.5; letter-spacing: normal; text-align: left; text-transform: none;
}
@media (hover: hover) {
  .tip:not(.is-shut):hover .tip-text {
    width: max-content; max-width: min(20rem, calc(100vw - 32px));
    height: auto; margin: 0; padding: 10px 14px; overflow: visible; clip: auto; white-space: normal;
    transform: translateX(calc(-50% + var(--tip-shift, 0px)));
    background: var(--teal-900); color: var(--ybb-white); border-radius: 10px;
    box-shadow: 0 6px 20px rgba(22, 35, 44, 0.22);
    font-family: var(--font-body); font-size: var(--text-body-sm); font-weight: var(--weight-regular);
    line-height: 1.5; letter-spacing: normal; text-align: left; text-transform: none;
  }
}
body.reading .tip-text { font-size: var(--text-body-md); }
/* The arrow, and a bridge over the gap so the pointer can move onto the bubble without losing it. */
.tip-text::before {
  content: ""; position: absolute; left: calc(50% - var(--tip-shift, 0px) - 7px); top: -7px;
  border: 7px solid transparent; border-top: 0; border-bottom-color: var(--teal-900);
}
.tip-text::after { content: ""; position: absolute; left: 0; right: 0; top: -12px; height: 12px; }
.tip.tip-up .tip-text { top: auto; bottom: calc(100% + 10px); }
.tip.tip-up .tip-text::before { top: auto; bottom: -7px; border: 7px solid transparent; border-bottom: 0; border-top-color: var(--teal-900); }
.tip.tip-up .tip-text::after { top: auto; bottom: -12px; }

/* ---- section: disclosure ---- */
/* Every <details> summary shows that it opens: a chevron at the end of the row that turns when it is
   open, a full --tap target, the text in deep teal. A page may style the row further (a quiet
   button, a hairline above it); the chevron stays. */
summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: var(--space-2); min-height: var(--tap); font-weight: var(--weight-semibold); color: var(--ybb-deep-teal); }
summary::-webkit-details-marker { display: none; }
summary::after {
  content: ""; flex: 0 0 auto; width: 8px; height: 8px; margin: 0 4px 3px auto;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform var(--duration-fast) var(--ease-standard);
}
details[open] > summary::after { transform: rotate(-135deg); margin-bottom: -3px; }
summary:hover { color: var(--teal-900); }

/* ---- section: signals ---- */
/* The attention scale: one look per level for every status that asks for notice, in both apps (the
   ux-principles skill, references/attention-scale.md). Most of a page is level 0. The level grows with
   how soon this person must act, never in one jump from nothing to red, and the words always say the
   same as the colour. Draw them with sig() in each app's src/lib/attention.js.
     sig-0  calm      a fact: a neutral tag, or no tag at all
     sig-1  notice    worth knowing, nothing to do yet: a cool tint
     sig-2  act soon  this person should act within days: a warm tint, semibold
     sig-3  act now   due, past due, or blocking others: red, semibold. Rare by design. */
.sig {
  display: inline-flex; align-items: center; gap: 4px; padding: 1px 10px; border-radius: 100px;
  font-size: var(--fs-meta); font-weight: var(--weight-medium); line-height: 1.5; white-space: nowrap; vertical-align: baseline;
}
.sig-0 { background: var(--sand-200); color: var(--ink-700); }
.sig-1 { background: var(--teal-100); color: var(--teal-900); }
.sig-2 { background: var(--gold-200); color: #5C3F08; font-weight: var(--weight-semibold); }
.sig-3 { background: var(--bad-bg); color: var(--bad); font-weight: var(--weight-semibold); }
/* On a phone a long tag ("Make it final, 7 days overdue") wraps inside the panel instead of running past it. */
@media (max-width: 639px) { .sig { white-space: normal; max-width: 100%; } }

/* ---- section: side ---- */
/* The shell: on wide screens the sidebar on the left (sticky, with its own scroll) and the page on
   the right; on a phone the sidebar folds into a sheet that the header's menu button and the bottom
   bar's More open (public/static/shell.js), or that the More link's #side target opens when there
   is no JavaScript. body.side-collapsed narrows it to icons (shell.js remembers the choice in the
   browser). Section headings look like the donor story's sidebar; the current row has a gold edge. */
.shell { max-width: var(--shell-max); margin: 0 auto; }
.side { display: none; }
.side-nav .side-h {
  margin: 18px 8px 6px; font-size: var(--text-label); font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-muted); line-height: 1.4;
}
.side-nav .side-h:first-child { margin-top: 4px; }
.side-nav ul { list-style: none; margin: 0; padding: 0; }
.side-nav li { margin: 0; }
.side-nav a {
  display: flex; align-items: center; gap: 10px; min-height: var(--tap); padding: 0 10px 0 9px;
  border-left: 3px solid transparent; border-radius: 0 8px 8px 0;
  color: var(--teal-900); text-decoration: none; font-size: 0.95rem; line-height: 1.3;
}
.side-nav a:hover { background: rgba(255, 255, 255, 0.7); color: var(--ybb-deep-teal); }
.side-nav a[aria-current="page"] {
  background: var(--teal-50); border-left-color: var(--ybb-warm-gold); color: var(--ybb-deep-teal); font-weight: var(--weight-semibold);
}
.side-nav .ic { color: var(--teal-600); }
.side-nav a[aria-current="page"] .ic, .side-row.is-here > a .ic { color: var(--ybb-deep-teal); }
.side-row.is-here > a { color: var(--ybb-deep-teal); }
.side-sub { margin: 2px 0 6px 19px; border-left: 1px solid var(--border-default); }
.side-sub a { min-height: 40px; padding-left: 12px; font-size: 0.9rem; }
.side-soon {
  display: inline-block; margin-left: auto; padding: 1px 8px; border-radius: 100px;
  background: var(--sand-200); color: var(--ink-700);
  font-size: 0.7rem; font-weight: var(--weight-semibold); letter-spacing: 0.04em; text-transform: uppercase;
}
h2 .side-soon { vertical-align: middle; }
.side-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin: 0 0 var(--space-2); }
/* Who is signed in, and Sign out: in the sheet on a phone (the header keeps them on wide screens). */
.side-person { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin: var(--space-2) 0 var(--space-4); padding: var(--space-3) var(--space-4); background: var(--ybb-white); border: var(--panel-edge); border-radius: var(--radius); }
.side-person p { margin: 0; color: var(--ink-700); font-size: 0.9375rem; }
.side-person strong { color: var(--teal-900); }
.side-person form { margin: 0; }
.side-person-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.side-close {
  display: inline-flex; align-items: center; gap: 8px; min-height: var(--tap); padding: 0 10px;
  font-weight: var(--weight-semibold); text-decoration: none;
}
.side-collapse { display: none; }

@media (max-width: 899px) {
  /* The sheet: the whole screen, its Close link first. */
  body.side-open .side, .side:target {
    display: block; position: fixed; inset: 0; z-index: 150; overflow-y: auto;
    background: var(--surface-page-warm); padding: 8px 16px calc(24px + env(safe-area-inset-bottom));
  }
  body.side-open { overflow: hidden; }
}

@media (min-width: 900px) {
  .shell { display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); gap: 0 32px; padding: 0 var(--shell-pad); align-items: start; }
  body:not(.has-side) .shell { display: block; padding: 0; }
  body.has-side .shell { max-width: none; }
  body.has-side .shell > .wrap { max-width: var(--main-max); margin: 0; padding: 0; min-width: 0; }
  body.has-side .th-top, body.has-side .foot .wrap { max-width: none; }
  .side {
    display: block; position: sticky; top: 0; max-height: 100vh; overflow-y: auto; scrollbar-width: thin;
    padding: 12px 0 16px;
    /* A soft shadow at the top or bottom edge while more rows are hidden there: the two sand covers
       scroll with the list and hide the shadows once its end is reached. */
    background:
      linear-gradient(var(--surface-page-warm) 30%, rgba(250, 248, 245, 0)) center top / 100% 40px no-repeat local,
      linear-gradient(rgba(250, 248, 245, 0), var(--surface-page-warm) 70%) center bottom / 100% 40px no-repeat local,
      radial-gradient(farthest-side at 50% 0, rgba(22, 35, 44, 0.16), transparent) center top / 100% 12px no-repeat scroll,
      radial-gradient(farthest-side at 50% 100%, rgba(22, 35, 44, 0.16), transparent) center bottom / 100% 12px no-repeat scroll;
  }
  .side-head, .side-person { display: none; }
  .side-collapse:not([hidden]) {
    display: inline-flex; align-items: center; gap: 8px; min-height: var(--tap); margin: 12px 0 0; padding: 0 10px 0 12px;
    background: transparent; border: 0; border-radius: 8px; color: var(--text-muted);
    font: inherit; font-size: 0.85rem; cursor: pointer;
  }
  .side-collapse:hover { background: rgba(255, 255, 255, 0.7); color: var(--ybb-deep-teal); }
  .side-collapse .ic { transform: rotate(180deg); }

  /* Icons only. Labels stay for screen readers; sighted people get the row's title. */
  body.side-collapsed .shell { grid-template-columns: var(--side-w-collapsed) minmax(0, 1fr); }
  body.side-collapsed .side-h, body.side-collapsed .side-label, body.side-collapsed .side-collapse-label {
    position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  body.side-collapsed .side-soon, body.side-collapsed .side-sub { display: none; }
  body.side-collapsed .side-nav ul { margin-top: 8px; }
  body.side-collapsed .side-nav a { justify-content: center; padding: 0 0 0 0; border-radius: 8px; }
  body.side-collapsed .side-collapse:not([hidden]) { justify-content: center; width: 100%; padding: 0; }
  body.side-collapsed .side-collapse .ic { transform: none; }
}

/* ---- section: bottom ---- */
/* The bar fixed to the bottom of a phone: up to five 44px targets with room for the home
   indicator. The page gets padding at the bottom so nothing hides under it. Wide screens have the
   sidebar instead. */
.side-bottom { display: none; }
@media (max-width: 899px) {
  body.has-side { padding-bottom: calc(60px + env(safe-area-inset-bottom)); }
  .side-bottom {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 140;
    background: var(--ybb-white); border-top: 1px solid var(--border-default);
    padding: 0 4px env(safe-area-inset-bottom);
  }
  .side-bottom ul { display: flex; list-style: none; margin: 0; padding: 0; }
  .side-bottom li { flex: 1 1 0; min-width: 0; margin: 0; }
  .side-bottom a {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 56px; padding: 6px 2px; color: var(--teal-700); text-decoration: none;
    font-size: 0.7rem; line-height: 1.2; white-space: nowrap;
  }
  .side-bottom .ic { width: 22px; height: 22px; }
  .side-bottom a[aria-current="page"] { color: var(--ybb-deep-teal); font-weight: var(--weight-semibold); box-shadow: inset 0 3px 0 var(--ybb-warm-gold); }
}

/* ---- section: print ---- */
/* On paper: the page alone. */
@media print {
  .team-header, .side, .side-bottom, .foot, .skip, .demo-banner, .tip { display: none !important; }
  .shell { display: block !important; max-width: none; padding: 0; }
  body { background: #fff; padding: 0; }
}
