/* ============================================================
   Sway site chrome — banner, sidebar, content shell.

   The .gs-* rules are carried over verbatim from the Google Sites
   replica embedded in the legacy pages (extracted from the live
   Google Sites via getComputedStyle — see docs/ARCHITECTURE.md).
   Three deliberate departures from the legacy replica:
     1. The chrome is always visible (this IS the site now), so the
        body.standalone gating is gone.
     2. Below the 1280px breakpoint the sidebar becomes a slide-in
        drawer opened from a hamburger button in the banner, instead
        of disappearing entirely (the old replica left no navigation
        at all on narrow screens).
     3. The active-page underline (a.gs-active) has no fixed height.
        The replica's height:26px assumed Google Sites' tight line
        box; under this site's 1.6 line-height it left a 19px content
        box (border-box minus the 7px border) and the inherited
        overflow:hidden clipped descenders under the bar.
   ============================================================ */

/* ---- Tokens ----
   Chrome tokens (--gs-*) are theme-independent: the banner and sidebar are
   always dark, exactly like the legacy pages. Content tokens flip with the
   html.light-mode / html.dark-mode classes (same localStorage 'theme' key
   the legacy pages use, so the choice carries across the whole site).
   Light is the default — :root carries the light values for no-JS visitors. */
:root {
  --gs-banner-bg: rgb(35, 0, 77);
  --gs-sidebar-bg: rgb(25, 24, 26);
  --gs-text: rgb(249, 249, 249);
  --gs-active: rgb(80, 80, 208);
  --banner-h: 64px;
  --sidebar-w: 250px;

  color-scheme: light;

  /* ---- Elevation ladder ----
     The base is a warm off-white rather than pure white — 2.1 L* down, chroma
     1.55, which reads as paper without reading as cream. Raised and overlay
     surfaces share that value, so their lift is carried entirely by
     --border-subtle plus a shadow, and the tonal rungs run downward.

       sunken-2 L* 91.5   pressed/active states, nested wells
       sunken   L* 94.2   wells, table headers, inputs — cut into the page
       page     L* 97.9   the base
       raised   L* 97.9   cards — + border + --shadow-sm
       overlay  L* 97.9   + --shadow-lg

     Every rung sits the same distance below the page as it did when the page
     was white, so wells and hairlines separate exactly as before. Chroma stays
     between 1.5 and 3.4: enough that nothing reads blue, little enough that
     the greys never look tinted against the page.

     --surface-raised is kept as its own token even though it equals --page-bg
     today; setting it back to #ffffff is the one-line change that gives cards
     2.1 L* of lift again. */
  --surface-sunken-2: #e8e7e2;
  --surface-sunken: #f0eeea;
  --page-bg: #faf9f6;
  --surface-raised: #ffffff;
  --surface-overlay: #ffffff;

  --text: #212529;
  --text-strong: #111118;
  --text-soft: #3f3f46;
  --link-color: #5a5ad1;
  --link-hover: #3a3ab1;

  /* Hairlines. Opaque at the two ends of the ramp so they hold their hue on
     any surface; --rule stays alpha because it is drawn over both. With the
     page and the cards on one value the border is load-bearing — it is what
     makes a card a card. */
  --border-subtle: #dedcd7;
  --border-strong: #c6c3bd;
  --rule: rgba(60, 50, 40, 0.16);

  /* Shadows carry the elevation the page colour no longer can, so they are a
     touch deeper than they would be on a tinted ground. Warm-tinted rather
     than neutral black, and two layers each — a tight contact shadow plus a
     wide diffuse one. */
  --shadow-sm: 0 1px 2px rgba(60, 50, 40, 0.07);
  --shadow-md: 0 1px 2px rgba(60, 50, 40, 0.07), 0 3px 8px -4px rgba(60, 50, 40, 0.12);
  --shadow-lg: 0 2px 4px rgba(60, 50, 40, 0.08), 0 12px 28px -14px rgba(60, 50, 40, 0.24);

  --footer-text: #6f6d68;
  --fab-color: #333333;
}
html.dark-mode {
  color-scheme: dark;

  /* ---- Dark elevation ladder ----
     The base stays true black (OLED pixels-off), so the ladder runs upward
     and "sunken" lifts like everything else — the standard true-black
     inversion. Every rung sits on one hue: OKLCh h≈285, the violet-ink the
     evidence deck and the purple chrome already live on, with chroma held
     between 1.2 and 2.1 so the tint reads as ink, never as a navy theme.
     Rungs are evenly spaced in OKLCh lightness:

       page      okL  0     true black
       sunken-2  okL 13     pressed/active states, nested wells
       sunken    okL 16.5   wells, table headers, inputs
       raised    okL 20     cards — + border + --shadow-sm
       overlay   okL 24.5   popovers, drawer, the FAB

     Cards carry real tonal lift over the floor (the dark analogue of the
     light pass that put cards back on #ffffff); the border and the shadow's
     top hairline do the rest. */
  --surface-sunken-2: #07070c;
  --surface-sunken: #0e0e15;
  --page-bg: #000000;
  --surface-raised: #15151e;
  --surface-overlay: #1f1f2a;

  /* Text runs a real four-step ramp (strong 96 / body 89.5 / soft 77 /
     footer 64 in okL). Body sits at ~13-15:1 on the surfaces it reads on —
     comfortable at night — rather than the old near-white #f3f3f3, which
     glared at 19:1 and left headings nowhere to go. */
  --text: #dcdce1;
  --text-strong: #f1f1f5;
  --text-soft: #b3b3bc;
  --link-color: #8a8aff;
  --link-hover: #b3b3ff;

  /* Opaque, like the light borders, so they hold their hue on any rung;
     both sit ~8-9 okL above the card face, mirroring the light deltas.
     --rule stays alpha because it draws over page and card alike — 14%
     violet-white, calmed from the old 25% pure white. */
  --border-subtle: #2b2b36;
  --border-strong: #3e3e4b;
  --rule: rgba(226, 226, 248, 0.14);

  /* Drop shadows can't darken a true-black page, so raised surfaces also
     get a 1px top inner hairline — light falling on the card's upper edge —
     which is what actually reads as elevation on ink. */
  --shadow-sm: inset 0 1px 0 rgba(226, 226, 255, 0.05), 0 1px 2px rgba(0, 0, 0, 0.55);
  --shadow-md: inset 0 1px 0 rgba(226, 226, 255, 0.05), 0 1px 2px rgba(0, 0, 0, 0.55), 0 3px 8px -4px rgba(0, 0, 0, 0.7);
  --shadow-lg: inset 0 1px 0 rgba(226, 226, 255, 0.06), 0 2px 4px rgba(0, 0, 0, 0.55), 0 12px 28px -14px rgba(0, 0, 0, 0.9);

  --footer-text: #8b8b92;
  --fab-color: #dcdce1;
}

/* ---- Base ---- */
*, *::before, *::after { box-sizing: border-box; }
html {
  background: var(--page-bg);
  /* Fluid root size: content type scales with the window so large displays
     read comfortably by default (≈20.5px at 1728px wide, 16px floor on
     small screens, 21.5px cap). Everything sized in rem scales with it;
     the banner/sidebar chrome is deliberately fixed in px. */
  font-size: clamp(16px, 11px + 0.55vw, 21.5px);
}
/* Smooth scrolling only where it has not been asked to stop. This sheet loads
   on every templated page, so an unconditional `scroll-behavior: smooth` here
   overrode deck-wireframe.css's own `no-preference` guard: measured under
   `prefers-reduced-motion: reduce`, the landing deck and the walkthrough rigs
   still scrolled smoothly — the two page types the preference most exists
   for. The guard belongs wherever the property is set, not only where the
   animation is. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
body {
  margin: 0;
  padding: var(--banner-h) 0 0 0;
  background: var(--page-bg);
  color: var(--text);
  font-family: "IBM Plex Sans", sans-serif;
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* Line-break quality (progressive enhancements; no-ops where text-wrap is
   unsupported): headings balance their lines instead of stranding a word,
   prose avoids a single short word as its last line. The legacy pages get
   the same rules from lib/legacy-chrome/fragments/fluid-*.css. */
h1, h2, h3, h4, h5 { text-wrap: balance; }
p, li, blockquote, figcaption { text-wrap: pretty; }
@media (min-width: 1280px) {
  body { margin-left: var(--sidebar-w); }
}

/* ---- Banner (Google Sites announcement bar) ---- */
.gs-banner{display:flex;position:fixed;top:0;left:0;right:0;z-index:1300;height:64px;background-color:rgb(35,0,77);padding:0 12px;justify-content:center;align-items:center}
.gs-banner p{font-family:Roboto,sans-serif;font-weight:300;font-size:16px;color:rgb(255,255,255);margin:16px 0}
.gs-banner .gs-btn-outer{display:flex;padding-left:23px}
.gs-banner .gs-btn-box{border:1px solid rgb(255,255,255);border-radius:4px;overflow:hidden;cursor:pointer;position:relative}
.gs-banner .gs-btn-box a{display:block;font-family:Roboto,sans-serif;font-weight:300;font-size:16px;color:rgb(255,255,255);line-height:34px;letter-spacing:0.25px;text-align:center;text-decoration:none;padding:0 23px}
.gs-banner .gs-btn-box:hover{background:rgba(255,255,255,0.08)}

/* Hamburger — only below the sidebar breakpoint */
.gs-menu-btn{display:none;position:absolute;left:8px;top:50%;transform:translateY(-50%);background:none;border:0;color:#fff;padding:8px;cursor:pointer;border-radius:4px}
.gs-menu-btn:hover{background:rgba(255,255,255,0.08)}
@media (max-width: 1279px) {
  .gs-menu-btn{display:flex;align-items:center;justify-content:center}
}

/* ---- Sidebar (Google Sites navigation replica) ---- */
.gs-sidebar{display:block;position:fixed;top:64px;left:0;bottom:0;z-index:1250;width:250px;background-color:rgb(25,24,26);overflow-y:auto;padding-bottom:64px;font-family:Roboto,sans-serif;font-size:17.6px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.gs-sidebar::-webkit-scrollbar{width:4px}
.gs-sidebar::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.1);border-radius:2px}
.gs-sidebar .gs-logo{display:block;margin:48px 32px 0 48px;text-decoration:none}
.gs-sidebar .gs-logo img{width:36px;height:36px;max-width:100%}
.gs-sidebar .gs-brand{display:block;position:relative;z-index:20;margin:48px 32px 62px 48px;font-family:Roboto,sans-serif;font-size:26.6667px;font-weight:400;color:rgb(249,249,249);text-decoration:none;overflow:hidden;text-overflow:ellipsis;cursor:pointer}
.gs-sidebar ul{list-style:none;padding:0;margin:0}
.gs-sidebar li{list-style:none;padding:0;margin:0}
.gs-l1{position:relative;margin-top:12px;padding:0 12px 0 36px;font-family:Roboto,sans-serif;color:rgb(249,249,249);text-overflow:ellipsis}
.gs-l1-in{position:relative}
.gs-l1-in>a{display:block;position:relative;padding-left:4px;font-family:Roboto,sans-serif;font-size:17.6px;font-weight:400;color:rgb(249,249,249);text-decoration:none;overflow:hidden;text-overflow:ellipsis;vertical-align:middle}
.gs-l1-in>a:hover{background:rgba(255,255,255,0.06)}
.gs-l2{position:relative;margin-top:12px;padding:0 12px 0 56px;font-family:Roboto,sans-serif;color:rgb(249,249,249);text-overflow:ellipsis}
.gs-l2-in{position:relative}
.gs-l2-in>a{display:block;position:relative;padding-left:4px;font-family:Roboto,sans-serif;font-size:17.6px;font-weight:400;color:rgb(249,249,249);text-decoration:none;overflow:hidden;text-overflow:ellipsis;vertical-align:middle}
.gs-l2-in>a:hover{background:rgba(255,255,255,0.06)}
.gs-l2-in>a.gs-active{display:inline-block;margin-right:12px;margin-left:4px;padding-left:0;border-bottom:7px solid rgb(80,80,208)}
.gs-l1-in>a.gs-section{cursor:default}
/* Keyboard-accessible sidebar group toggles: the <button>s (group labels on
   hrefless groups, chevrons on linked groups) restyled to match the anchors
   they replaced. line-height is set explicitly because form controls do not
   inherit it (the UA sets line-height:normal), which made the group rows
   shorter than the plain anchor rows and bunched them up vertically. */
.gs-l1-in>button.gs-section{display:block;width:100%;text-align:left;background:none;border:0;margin:0;position:relative;padding:0 0 0 4px;font-family:Roboto,sans-serif;font-size:17.6px;line-height:1.6;font-weight:400;color:rgb(249,249,249);cursor:pointer;overflow:hidden;text-overflow:ellipsis}
.gs-l1-in>button.gs-section:hover{background:rgba(255,255,255,0.06)}
button.gs-chev{background:none;border:0;margin:0;padding:0 0 0 12px;cursor:pointer;color:rgb(249,249,249)}
.gs-chev{position:absolute;top:-14.5px;left:-32px;width:36px;height:24px;padding-left:12px;cursor:pointer;transform:translateY(12px);vertical-align:middle;color:rgb(249,249,249)}
.gs-chev svg{width:24px;height:24px;transition:transform 0.2s}
.gs-open .gs-chev svg{transform:rotate(180deg)}
.gs-subnav{display:none;position:relative}
.gs-open>.gs-subnav{display:block}
.gs-l1-in>a.gs-active{display:inline-block;margin-right:12px;margin-left:4px;padding-left:0;border-bottom:7px solid rgb(80,80,208)}

/* Drawer mode below the breakpoint */
@media (max-width: 1279px) {
  /* Shadow only while open — on the closed drawer it bled past the parked
     sidebar's edge and drew a grey fade down the left side of the page. */
  .gs-sidebar{transform:translateX(-100%);transition:transform 0.25s ease}
  body.nav-open .gs-sidebar{transform:translateX(0);box-shadow:2px 0 18px rgba(0,0,0,0.6)}
  .gs-scrim{position:fixed;top:var(--banner-h);left:0;right:0;bottom:0;z-index:1240;background:rgba(0,0,0,0.5);opacity:0;pointer-events:none;transition:opacity 0.25s ease}
  body.nav-open .gs-scrim{opacity:1;pointer-events:auto}
}
@media (min-width: 1280px) {
  .gs-scrim{display:none}
}

/* Narrow-screen banner (carried over from the replica) */
@media (max-width: 600px) {
  :root{--banner-h:48px}
  .gs-banner{height:var(--banner-h);padding:0 16px 0 48px;flex-wrap:wrap;gap:6px}
  body{padding-top:var(--banner-h)}
  .gs-sidebar{top:var(--banner-h)}
  .gs-banner p{font-size:14px;margin:4px 0}
  .gs-banner .gs-btn-outer{padding-left:0}
  .gs-banner .gs-btn-box a{font-size:14px;line-height:28px;padding:0 14px}
}
/* Below 416px the message and the button stop fitting on one line and the
   button wraps to a second — into a bar 48px tall that has no room for it, so
   it hung 18px below the banner, white on the page's own paper. The bar takes
   the height of what is in it. Measured at 416; 420 for the margin a font
   still loading can move it by. */
@media (max-width: 420px) {
  :root{--banner-h:76px}
}

/* ---- Content shell ---- */
.site-main { min-height: calc(100vh - var(--banner-h) - 80px); }
.page-container {
  max-width: 78rem;   /* scales with the fluid root, so text fills the window */
  margin: 0 auto;
  padding: 3rem 2.5rem 5rem;
}
@media (max-width: 600px) {
  .page-container { padding: 32px 20px 60px; }
}

/* Creators page: small headshot left, bio right (as on Google Sites) */
.creator-row {
  display: flex;
  gap: 40px;
  align-items: flex-start;
  margin: 3rem 0;
}
.creator-row img {
  flex: 0 0 178px;
  width: 178px;
  height: auto;
  margin: 0;
}
.creator-row p { margin: 0; }
@media (max-width: 700px) {
  .creator-row { flex-direction: column; }
}

/* Social icon row (about page) */
.social-links {
  display: flex;
  justify-content: flex-end;
  gap: 14px;
  margin: 8px 0 -24px;
}
.social-links a { display: inline-flex; border-radius: 50%; }
.social-links svg { display: block; }

/* Disclosures in the run of a page — the walkthroughs' notes and the
   showcases' asides. /faq had these too until it moved into the
   wireframe language, which draws its questions as rows in a box
   instead (css/wire-page.css) and turns these off for itself. */
.page-content details {
  border-bottom: 1px solid var(--rule);
  padding: 26px 0 26px;
}
.page-content details > summary {
  list-style: none;
  cursor: pointer;
  font-family: "Roboto Mono", monospace;
  font-weight: 500;
  font-size: clamp(1.15rem, 2vw, 1.667rem);
  line-height: 1.5;
  color: var(--text);
}
.page-content details > summary::-webkit-details-marker { display: none; }
.page-content details > summary:hover { color: var(--text-strong); }
.page-content details[open] { padding-bottom: 8px; }

/* ---- Floating page index ("on this page") ----
   Enabled per page with `toc: true` front matter; js/toc.js builds the
   links. Wide screens: sticky column right of the article. Narrow screens:
   a compact box above the content. */
.page-with-toc {
  display: grid;
  grid-template-areas: "content toc";
  grid-template-columns: minmax(0, 1fr) 14.5rem;
  gap: 0 3.5rem;
  align-items: start;
}
.page-with-toc > .page-content { grid-area: content; }
.page-toc {
  grid-area: toc;
  position: sticky;
  top: calc(var(--banner-h) + 32px);
  max-height: calc(100vh - var(--banner-h) - 64px);
  overflow-y: auto;
  padding: 4px 0 4px 20px;
  border-left: 1px solid var(--rule);
}
.page-toc-title {
  font-family: "Roboto Mono", monospace;
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--text-soft);
  margin: 0 0 10px;
}
.page-toc ul { list-style: none; margin: 0; padding: 0; }
.page-toc li { margin: 0; }
.page-toc li.toc-sub a { padding-left: 14px; }
.page-toc a {
  display: block;
  padding: 4px 0 4px 2px;
  font-family: Roboto, sans-serif;
  font-weight: 300;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--text-soft);
  text-decoration: none;
  border-left: 2px solid transparent;
  margin-left: -21px;
  padding-left: 19px;
}
.page-toc li.toc-sub a { padding-left: 33px; }
.page-toc a:hover { color: var(--link-color); }
.page-toc a.toc-active {
  color: var(--link-color);
  border-left-color: var(--gs-active);
  font-weight: 400;
}
@media (max-width: 1100px) {
  /* The index stacks above the <h1> here, because the heading lives inside
     {{ content }} and there is nothing to order it against. Ordering the whole
     index after the content instead was tried and is worse: it puts a jump
     list three thousand pixels below the only place it is useful. The real fix
     is to hoist the page title out of the markdown body in layouts/page.njk so
     the order can be title / index / content — a template change across the
     ten pages that set `toc: true`, not a CSS one. */
  .page-with-toc { display: block; }
  .page-toc {
    position: static;
    max-height: none;
    border-left: 0;
    /* Inline on narrow screens the index becomes a well rather than a card:
       it is navigation about the page, not content raised above it. */
    background: var(--surface-sunken);
    border: 0;
    border-radius: 8px;
    padding: 16px 20px;
    margin: 24px 0 8px;
  }
  .page-toc a, .page-toc li.toc-sub a { margin-left: 0; border-left: 0; padding-left: 0; }
  .page-toc li.toc-sub a { padding-left: 14px; }
}

/* ---- Theme toggle FAB (same placement/behavior as the legacy pages) ---- */
.theme-toggle {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  z-index: 1200;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: 1px solid var(--border-subtle);
  background: var(--surface-overlay);
  color: var(--fab-color);
  cursor: pointer;
  box-shadow: var(--shadow-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.15s ease;
}
.theme-toggle:hover { transform: scale(1.08); }
/* Bottom right is where a thumb rests, which is the trouble: on a phone the
   button sat over the last line of whatever the reader had scrolled to. Below
   the banner in the top right instead, and smaller, so it overlaps a heading's
   margin rather than a paragraph's text. */
@media (max-width: 1279px) {
  .theme-toggle {
    top: calc(var(--banner-h, 48px) + 0.55rem);
    right: 0.8rem;
    bottom: auto;
    width: 42px;
    height: 42px;
  }
  .theme-toggle svg { width: 19px; height: 19px; }
}
.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }
html.dark-mode .theme-toggle .icon-sun { display: block; }
html.dark-mode .theme-toggle .icon-moon { display: none; }

/* ---- Content typography ----
   Sizes measured from the live Google Sites pages via getComputedStyle:
   h1 Roboto Mono 700 40px; h2 Roboto Mono 500 26.67px;
   body Roboto 300 16px, line-height ~2. Colors come from the theme tokens. */
.page-content h1 {
  font-family: "Roboto Mono", monospace;
  font-weight: 700;
  font-size: clamp(1.7rem, 3.2vw, 2.5rem);
  line-height: 1.38;
  color: var(--text-strong);
  margin: 0.9em 0 0.6em;
}
.page-content h2 {
  font-family: "Roboto Mono", monospace;
  font-weight: 500;
  font-size: clamp(1.25rem, 2.2vw, 1.667rem);
  line-height: 1.5;
  color: var(--text);
  margin: 2.6em 0 0.9em;
}
.page-content h3 {
  font-family: "Roboto Mono", monospace;
  font-weight: 500;
  font-size: 1.2rem;
  color: var(--text);
  margin: 1.8em 0 0.6em;
}
.page-content h4 {
  font-family: "Roboto Mono", monospace;
  font-weight: 500;
  font-size: 1.02rem;
  color: var(--text-soft);
  margin: 1.7em 0 0.5em;
}
.page-content h2, .page-content h3 { scroll-margin-top: calc(var(--banner-h) + 20px); }
.page-content p, .page-content li {
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.8;
  color: var(--text);
}
.page-content a { color: var(--link-color); text-decoration: none; }
.page-content a:hover { color: var(--link-hover); text-decoration: underline; }
/* A bare URL has no break opportunity in it, so on a phone it sets the page's
   width instead of taking the column's. /students/ prints
   https://chat.swaybeta.ai/student/reset_password in full and was 397px wide
   in a 390px window — the only page of the site that scrolled sideways. */
.page-content a, .page-content code { overflow-wrap: anywhere; }
/* Content images: constrained and centered by default (source files are
   large exports). Use class="img-wide" for anything that should span the
   full column. */
.page-content img {
  max-width: min(100%, 39rem);
  height: auto;
  display: block;
  margin: 2em auto;
  border-radius: 6px;
}
.page-content img.img-wide { max-width: 100%; }
.page-content figure {
  margin: 2.5em auto;
  max-width: 40rem;
}
.page-content figure img { margin: 0 auto 0.6em; }
.page-content figcaption {
  font-size: 0.88rem;
  color: var(--text-soft);
  text-align: center;
}
.page-content blockquote {
  margin: 1.5em 0;
  padding: 0.2em 0 0.2em 1.2em;
  border-left: 4px solid var(--gs-active);
  font-style: italic;
}
.page-content hr { border: 0; border-top: 1px solid var(--rule); margin: 2.5em 0; }
/* Tables ride the elevation ladder: the table itself is a raised surface, the
   header row is cut into it, and the hairlines are the subtle border. */
.page-content table {
  border-collapse: collapse;
  width: 100%;
  margin: 1.5em 0;
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.page-content th, .page-content td { padding: 9px 14px; text-align: left; }
.page-content th { background: var(--surface-sunken); font-weight: 600; }
.page-content tbody tr + tr td, .page-content thead + tbody td { border-top: 1px solid var(--border-subtle); }

/* ---- Rotating student pull-quote (landing + design studies) ----
   Typographic treatment — serif italic, no quotation mark — rather than a
   card, and fully theme-aware. Rendered by js/landing.js.

   There is no mark on purpose. A Charter open-quote used to hang in the
   margin here at 4.4rem in the accent, and it was the only thing on the
   page speaking neither of the site's two languages: not the drawn ink,
   not the speech bubble. On the most-read block on the site it read as
   ornament rather than as part of the page. It also indented the text
   2.3rem, so the quote began at a place the heading and the paragraph
   above it did not. The italic and the attribution under it already say
   this is someone speaking, which is the whole job the mark was doing —
   so removing it costs nothing and returns the quote to the column edge.

   Nothing here is positioned any more, so .pull-quote no longer needs
   `position: relative`; figcaption's rule is a flex item, not an
   absolutely placed one. */
.quotes-container {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 170px;
}
.pull-quote {
  margin: 0;
  opacity: 1;
  transition: opacity 1s ease-in-out;
}
.pull-quote.fade-out { opacity: 0; }
.pull-quote blockquote {
  margin: 0;
  padding: 0;
  border: 0;
  font-family: Charter, "Bitstream Charter", Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.15rem, 1.8vw, 1.45rem);
  line-height: 1.65;
  color: var(--text);
}
.pull-quote figcaption {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.9rem;
  font-family: "Roboto Mono", monospace;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.pull-quote figcaption::before {
  content: "";
  width: 26px;
  height: 1px;
  background: var(--gs-active);
}

/* Responsive video embeds */
.video-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  margin: 1.5em 0;
}
.video-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Buttons in content (outlined, Google Sites style) */
.gs-button {
  display: inline-block;
  border: 1px solid var(--text-strong);
  border-radius: 4px;
  padding: 8px 24px;
  color: var(--text-strong);
  font-family: Roboto, sans-serif;
  font-weight: 300;
  text-decoration: none;
}
.gs-button:hover { background: var(--surface-sunken); }

/* ---- Footer (black strip, small grey centered text — as on Google Sites) ---- */
.site-footer {
  padding: 28px 16px 36px;
  text-align: center;
}
.site-footer p {
  margin: 0;
  font-family: Roboto, Arial, sans-serif;
  font-weight: 300;
  font-size: 12px;
  line-height: 1.5;
  color: var(--footer-text);
}
/* The org credits link out but read as plain text — no underline, no colour
   shift, in any state. The :hover selectors are spelled out because the
   credit line on /about/ sits inside .page-content, whose a:hover rule would
   otherwise underline it. The focus ring stays so the links are still
   reachable by keyboard. */
.site-footer a,
.site-footer a:hover,
.site-footer a:focus,
.credit-line a,
.credit-line a:hover,
.credit-line a:focus {
  color: inherit;
  text-decoration: none;
}
.site-footer a:focus-visible,
.credit-line a:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}
