/* mylearnbase custom styles — project overrides layered on top of the Serene theme.
   Loaded via templates/_head_extend.html (after the theme's compiled CSS). */

/* ── Homepage hero ──────────────────────────────────────────────
   #name has no rule in the theme, so it inherits body size and reads
   as plain text. Give the site identity real weight. */
#info #name {
  font-size: 1.55em;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

/* The avatar is the logo mark, not a photo — the theme crops it to a
   circle (border-radius:50%), which would clip the tall spark + base.
   Show it whole instead. */
#info img {
  border-radius: 0;
  object-fit: contain;
}

/* ── "What you'll find here" forms guide ────────────────────────
   A described map of the post forms — turns the bare nav words into an
   explained orientation, and surfaces `concepts` even while it's empty. */
#guide {
  margin-top: 2.5em;
}

.guide-title {
  font-size: 0.9em;
  font-weight: 400;
  color: var(--text-pale-color);
  margin: 0 15px 0.75em;
}

/* The "Latest" heading lives inside .layout-list (the guide heading does not),
   so this separates the recent-posts block from the forms guide above it. */
.layout-list .guide-title {
  margin-top: 2.5em;
}

#guide .guide-list {
  padding: 0 15px;
  display: flex;
  flex-direction: column;
  gap: 0.85em;
}

#guide .guide-item {
  display: grid;
  grid-template-columns: 8em 1fr;
  gap: 1em;
  align-items: baseline;
  text-decoration: none;
  color: var(--text-color);
  border-bottom: 1.5px solid transparent;
  padding-bottom: 0.15em;
}

#guide .guide-item:hover {
  border-bottom-color: var(--primary-color);
}

#guide .guide-name {
  color: var(--primary-color);
}

#guide .guide-desc {
  color: var(--text-pale-color);
}

@media (max-width: 425px) {
  #guide .guide-item {
    grid-template-columns: 1fr;
    gap: 0.15em;
  }
}

/* OpenDyslexic — self-hosted, loaded ON DEMAND. A browser only fetches these
   when an element actually renders in the family, so the ~235KB costs 0 bytes
   for readers who never pick "Dyslexic". font-display: swap shows fallback text
   immediately. (SIL OFL 1.1 — opendyslexic.org) */
@font-face {
  font-family: "OpenDyslexic";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/opendyslexic-400.woff2") format("woff2");
}
@font-face {
  font-family: "OpenDyslexic";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/opendyslexic-700.woff2") format("woff2");
}

/* ── Reader controls: typography application ─────────────────────
   Scoped to the article body (the reading surface) so nav/footer
   layout is never affected. Size is a CSS var set by JS; the family
   is keyed off a data-attribute on <html> so the font stacks live
   only here (no duplicate map in JS). Both fall back to the theme
   default when unset, so a no-JS / no-prefs visitor is unchanged. */
article.prose {
  font-size: var(--reader-font-size, var(--font-size));
}
html[data-reader-font="serif"] article.prose {
  font-family: Georgia, "Iowan Old Style", "Palatino Linotype", "Times New Roman", serif;
}
html[data-reader-font="mono"] article.prose {
  font-family: var(--code-font);
}
html[data-reader-font="dyslexic"] article.prose {
  font-family: "OpenDyslexic", sans-serif;
}
/* sans = theme default (--main-font); no rule needed */

/* ── Reader controls: floating "Aa" panel ───────────────────────
   Always-reachable reading-options control. Progressive enhancement:
   markup ships with [hidden]; js/reader-controls.js reveals it. All
   colors are theme variables, so light/dark adapt by construction. */
#reader-controls {
  position: fixed;
  left: 1.25rem;   /* bottom-LEFT: the theme's #back-to-top owns bottom-right */
  bottom: 1.25rem;
  z-index: 50;
  font-family: var(--main-font);
}

#reader-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1.5px solid var(--primary-color);
  background: var(--bg-color);
  color: var(--primary-color);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
}
#reader-toggle:hover {
  background: var(--primary-pale-color);
}

#reader-panel {
  position: absolute;
  left: 0;
  bottom: 3.4rem;
  width: 15rem;
  padding: 0.9rem 1rem 1rem;
  background: var(--bg-color);
  border: 1.5px solid var(--primary-color);
  border-radius: 6px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.18);
}
#reader-panel[hidden] {
  display: none;
}

.reader-row {
  margin-bottom: 0.9rem;
}
.reader-row:last-of-type {
  margin-bottom: 0.6rem;
}
.reader-label {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-pale-color);
  margin-bottom: 0.45rem;
}

.reader-size {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.reader-size button {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border: 1.5px solid var(--text-decoration-color);
  background: var(--bg-color);
  color: var(--text-color);
  border-radius: 4px;
  cursor: pointer;
}
.reader-size button:hover:not(:disabled) {
  border-color: var(--primary-color);
  color: var(--primary-color);
}
.reader-size button:disabled {
  opacity: 0.4;
  cursor: default;
}
#reader-size-val {
  flex: 1 1 auto;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-color);
}

.reader-fonts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
}
.reader-fonts button {
  padding: 0.4rem 0;
  border: 1.5px solid var(--text-decoration-color);
  background: var(--bg-color);
  color: var(--text-color);
  border-radius: 4px;
  font-size: 0.8rem;
  cursor: pointer;
}
.reader-fonts button[aria-pressed="true"] {
  border-color: var(--primary-color);
  color: var(--primary-color);
  background: var(--primary-pale-color);
}
.reader-fonts button[data-font="serif"] {
  font-family: Georgia, "Times New Roman", serif;
}
.reader-fonts button[data-font="mono"] {
  font-family: var(--code-font);
}
.reader-fonts button[data-font="dyslexic"] {
  font-family: "OpenDyslexic", sans-serif;
}

#reader-reset {
  background: none;
  border: none;
  padding: 0;
  color: var(--text-pale-color);
  font-size: 0.75rem;
  text-decoration: underline;
  cursor: pointer;
}
#reader-reset:hover {
  color: var(--primary-color);
}

/* ── Site header ─────────────────────────────────────────────────
   Persistent slim bar (templates/_base.html) on every page. Sticky at
   the top; static/js/header.js tucks it on scroll-down and reveals it on
   scroll-up via the .is-hidden modifier. All colors are theme variables,
   so light/dark adapt by construction. Several rules explicitly reset
   margin/padding because the theme's generic `header`/`header a` rules
   (main.scss) otherwise inflate the bar's links. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 0;                 /* override theme `header { padding: 0 15px }` */
  font-size: 1em;             /* reset theme `header { font-size: 0.8em }` so the inner
                                 em below measures against the body, not 0.8× it (the nav
                                 was compounding to ~0.68em) */
  background: var(--bg-color);
  border-bottom: 1px solid var(--primary-pale-color);
  transition: transform 0.25s ease;
}
.site-header.is-hidden {
  transform: translateY(-100%);
}

.site-header__inner {
  max-width: var(--main-max-width);   /* line up with the content column */
  margin: 0 auto;
  padding: 0 15px;
  height: 3rem;
  display: flex;
  align-items: center;
  gap: 1.1em;
  font-family: var(--main-font);
  font-size: 0.95em;          /* ~0.95× body; no longer compounds with the theme header */
}

.site-header__brand {
  margin: 0;                  /* override theme `header a` */
  padding: 0;
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-color);
  text-decoration: none;
}
.site-header__brand:hover {
  color: var(--primary-color);
}

.site-header__nav {
  display: flex;
  align-items: center;
  gap: 1.1em;
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-header__nav a {
  margin: 0;                  /* override theme `header a` */
  padding: 0;
  color: var(--text-pale-color);
  text-decoration: none;
}
.site-header__nav a:hover {
  color: var(--primary-color);
}

.site-header__actions {
  margin-left: auto;          /* push the icon cluster to the right edge */
  display: flex;
  align-items: center;
  gap: 0.4em;
}
.site-header__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.3rem;
  border: none;
  background: none;
  color: var(--text-pale-color);
  cursor: pointer;
  line-height: 0;
}
.site-header__icon:hover {
  color: var(--primary-color);
}
.site-header__icon svg {
  display: block;
  width: 1.15rem;
  height: 1.15rem;
}

/* Sticky header offsets in-page anchor jumps (TOC, heading links) so a
   target heading isn't hidden behind the bar. */
html {
  scroll-padding-top: 3.75rem;
}

/* Reduced-motion: no slide — the bar simply stays put. */
@media (prefers-reduced-motion: reduce) {
  .site-header {
    transition: none;
  }
  .site-header.is-hidden {
    transform: none;
  }
}

@media (max-width: 425px) {
  .site-header__inner {
    height: 2.75rem;
    gap: 0.8em;
    font-size: 0.85em;
  }
  .site-header__nav {
    gap: 0.8em;
  }
}

/* ── Homepage profile: social icons ──────────────────────────────
   GitHub/LinkedIn icons moved out of the retired #links row into the
   profile block (templates/home.html), under the bio. */
#info #profile-links {
  display: flex;
  gap: 0.7em;
  line-height: 0;
}
#info #profile-links a {
  color: var(--text-pale-color);
}
#info #profile-links a:hover {
  color: var(--primary-color);
}
#info #profile-links a svg {
  display: block;
  width: 1.2rem;
  height: 1.2rem;
}

/* ── Search overlay (Pagefind) ───────────────────────────────────
   The header trigger opens this; static/js/search.js lazy-loads the
   Pagefind UI into #search-ui. Pagefind's own tokens are mapped to the
   site's theme variables, so the results UI adapts to light/dark for
   free (the theme vars already flip under body.dark). */
.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;               /* above the sticky header (z-index 100) */
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 4rem 1rem 2rem;
  background: rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.search-overlay[hidden] {
  display: none;
}
.search-overlay__dialog {
  width: 100%;
  max-width: 34rem;
  max-height: 80vh;
  overflow: auto;
  padding: 1rem;
  background: var(--bg-color);
  border: 1.5px solid var(--primary-color);
  border-radius: 8px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
}

/* Lock background scroll while the overlay is open. */
body.search-open {
  overflow: hidden;
}

/* Map Pagefind UI tokens onto the site theme. */
#search-ui {
  --pagefind-ui-primary: var(--primary-color);
  --pagefind-ui-text: var(--text-color);
  --pagefind-ui-background: var(--bg-color);
  --pagefind-ui-border: var(--text-decoration-color);
  --pagefind-ui-tag: var(--primary-pale-color);
  --pagefind-ui-border-width: 1.5px;
  --pagefind-ui-border-radius: 6px;
  --pagefind-ui-font: var(--main-font);
}

/* ── Post chrome: reading-time + adjacent-post nav ───────────────
   Two small reader-orientation additions to the post template
   (templates/post.html). Theme-variable colored, so light/dark adapt
   by construction. (Breadcrumbs are emitted as BreadcrumbList JSON-LD
   only — see templates/_head_extend.html — with no visible trail.) */

/* Reading-time — a pale sibling of the publish date in #post-info,
   set off from the date with a middot. */
#reading-time {
  color: var(--text-pale-color);
  margin: 0 1em 1em 0;
}
#reading-time::before {
  content: "\00B7";           /* · */
  margin-right: 0.6em;
}

/* Adjacent-post navigation after the article: previous (older) on the
   left, next (newer) on the right. A spacer keeps "next" right-aligned
   when there is no previous. */
.post-nav {
  display: flex;
  justify-content: space-between;
  gap: 1em;
  margin: 3em 0 1em;
  padding-top: 1.5em;
  border-top: 1px solid var(--primary-pale-color);
}
.post-nav__link {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
  max-width: 45%;
  text-decoration: none;
  color: var(--text-color);
}
.post-nav__next {
  margin-left: auto;
  text-align: right;
}
.post-nav__dir {
  font-size: 0.8em;
  color: var(--text-pale-color);
}
.post-nav__title {
  font-weight: 600;
}
.post-nav__link:hover .post-nav__title {
  color: var(--primary-color);
}
@media (max-width: 425px) {
  .post-nav__link {
    max-width: 48%;
  }
}

/* ── Wide demos: break an interactive out of the reading column ──────
   The {{ demo(wide=true) }} shortcode adds .demo--wide. The article is
   centered in the viewport, so shifting the figure's left edge to the
   column centre and pulling back half its own width re-centres it on the
   viewport — letting the demo be wider than the prose measure without JS.
   Degrades to ~full width (96vw) on small screens. */
.demo--wide {
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: min(96vw, 1080px);
}
.demo--wide figcaption,
.demo--wide .demo-standalone-link {
  max-width: 60ch;
  margin-left: auto;
  margin-right: auto;
}
/* Above 1024px the post page shows a sticky table-of-contents that fills the
   entire right gutter (theme: body.post aside). A breakout centred on the
   viewport runs its right edge into that TOC. So when the TOC is present,
   re-centre the demo on the *non-TOC* region (empty left gutter + content
   column) and cap its width so the right edge stops short of the TOC.
   `100%` here is the article's width; `100vw` the viewport. */
@media (min-width: 1025px) {
  .demo--wide {
    width: min(1080px, calc((100% + 100vw) / 2 - 1.5rem));
    left: calc((300% - 100vw) / 4);
  }
}
/* A comparative demo stacks its two lanes on mobile, so it needs more vertical
   room than the desktop height. Give the iframe a taller mobile height: the demo
   fills it via flex and the page scrolls past it (no nested scrollbar). */
@media (max-width: 640px) {
  .demo--wide iframe { height: 1040px; }
}
