/*
 * Minimal styles for rails-docs. Intended to evolve into the design system
 * once that work begins; for now, content-first typographic defaults.
 */

/*
 * Color palette + type scale mirror guides.rubyonrails.org. Brand red
 * #C81418, gray scale, dark-mode tokens, fonts (InterVariable for body,
 * Calibre for display headings, IBM Plex Mono for code), and the
 * heading sizes all come from rails/guides/assets/stylesrc/style.scss
 * + _main.scss so the API site and the guides site read as one product.
 *
 * Font binaries copied from rails-website/assets/fonts (the canonical
 * source rubyonrails.org serves) into app/assets/fonts/. Propshaft
 * fingerprints them at build time; @font-face URLs use plain filenames
 * and propshaft rewrites to the digested asset path.
 */

/* --------------------------------------------------------------------------
 * Fonts
 * -------------------------------------------------------------------------- */

@font-face {
  font-family: InterVariable;
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/InterVariable-286b035b.woff2") format("woff2");
}
@font-face {
  font-family: InterVariable;
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/InterVariable-Italic-2289a606.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/IBMPlexMono-Text-5c5db1c6.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/IBMPlexMono-TextItalic-9cb547c9.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/IBMPlexMono-Medium-959804ef.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/IBMPlexMono-MediumItalic-547e013c.woff2") format("woff2");
}

@font-face {
  font-family: Calibre;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/calibre-regular-46236793.woff2") format("woff2");
}
@font-face {
  font-family: Calibre;
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/calibre-regular-italic-386c3d0f.woff2") format("woff2");
}
@font-face {
  font-family: Calibre;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/calibre-semibold-bc983797.woff2") format("woff2");
}
@font-face {
  font-family: Calibre;
  font-style: italic;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/calibre-semibold-italic-6bc3d1b7.woff2") format("woff2");
}
@font-face {
  font-family: Calibre;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/calibre-bold-cd002e0e.woff2") format("woff2");
}

:root {
  --rf-brand: #C81418;
  --rf-brand-light: #d8181c;
  --rf-brand-lighter: #e83d40;
  --rf-brand-lightest: #f17072;
  --rf-brand-dark: #831114;
  --rf-brand-darker: #6a0e10;

  --gray-100: #FAF9F8;
  --gray-200: #F5F3F1;
  --gray-300: #EBEBEA;
  --gray-400: #DCDCD8;
  --gray-500: #A9A9A8;
  --gray-600: #666666;
  --gray-700: #3A3939;
  --gray-800: #343434;
  --gray-850: #2E2E2E;
  --gray-900: #292929;
  --gray-1000: #181818;

  --color-text: var(--gray-900);
  --color-muted: var(--gray-600);
  --color-link: var(--rf-brand);
  --color-link-hover: var(--rf-brand-dark);
  --color-border: var(--gray-300);
  --color-bg: #fff;
  --color-bg-soft: var(--gray-100);
  --color-code-bg: var(--gray-200);

  /* Type stack — InterVariable for prose, Calibre for display headings,
   * IBM Plex Mono for code, all matching rails/guides. System-font
   * fallbacks cover the brief window before the webfonts swap in. */
  --font-body: InterVariable, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: Calibre, InterVariable, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --max-width: 64rem;
  --radius: 8px;
  --header-h: 4rem;        /* sticky-header height; module-nav clears it */

  /* Component colors that differ per theme live here (not in scattered
   * [data-theme="dark"] component rules) so system-dark — where no
   * data-theme attribute is set — picks them up via the media query
   * below. A component override outside this variable layer WILL be
   * invisible to prefers-color-scheme users; don't add one. */
  --badge-since-text: var(--gray-900);
  --badge-removed-text: var(--gray-900);
  --badge-deprecated-text: var(--rf-brand-dark);
  --badge-private-bg: var(--gray-200);
  --badge-private-text: var(--gray-700);
  --badge-private-border: var(--gray-400);
  --nav-zebra: rgba(0, 0, 0, 0.03);
  --nav-active-bg: var(--rf-brand);
  --nav-active-border: var(--rf-brand-darker);

  /* Tell the UA which scheme it's rendering so native form controls
   * (selects, inputs, scrollbars) match the theme — without this they
   * keep light-scheme chrome and black text on our dark backgrounds. */
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --color-text: #E5E5E5;
    --color-muted: var(--gray-500);
    --color-link: var(--rf-brand-lightest);
    --color-link-hover: var(--rf-brand-lighter);
    --color-border: var(--gray-850);
    --color-bg: var(--gray-1000);
    --color-bg-soft: var(--gray-900);
    --color-code-bg: var(--gray-900);
    --badge-since-text: #cffaff;
    --badge-removed-text: #fff5b3;
    --badge-deprecated-text: var(--rf-brand-lightest);
    --badge-private-bg: var(--gray-850);
    --badge-private-text: var(--gray-400);
    --badge-private-border: var(--gray-700);
    --nav-zebra: rgba(255, 255, 255, 0.03);
    --nav-active-bg: var(--rf-brand-light);
    --nav-active-border: var(--rf-brand);
  }
}

[data-theme="light"] {
  color-scheme: light;
  --color-text: var(--gray-900);
  --color-muted: var(--gray-600);
  --color-link: var(--rf-brand);
  --color-link-hover: var(--rf-brand-dark);
  --color-border: var(--gray-300);
  --color-bg: #fff;
  --color-bg-soft: var(--gray-100);
  --color-code-bg: var(--gray-200);
  --badge-since-text: var(--gray-900);
  --badge-removed-text: var(--gray-900);
  --badge-deprecated-text: var(--rf-brand-dark);
  --badge-private-bg: var(--gray-200);
  --badge-private-text: var(--gray-700);
  --badge-private-border: var(--gray-400);
  --nav-zebra: rgba(0, 0, 0, 0.03);
  --nav-active-bg: var(--rf-brand);
  --nav-active-border: var(--rf-brand-darker);
}

[data-theme="dark"] {
  color-scheme: dark;
  --color-text: #E5E5E5;
  --color-muted: var(--gray-500);
  --color-link: var(--rf-brand-lightest);
  --color-link-hover: var(--rf-brand-lighter);
  --color-border: var(--gray-850);
  --color-bg: var(--gray-1000);
  --color-bg-soft: var(--gray-900);
  --color-code-bg: var(--gray-900);
  --badge-since-text: #cffaff;
  --badge-removed-text: #fff5b3;
  --badge-deprecated-text: var(--rf-brand-lightest);
  --badge-private-bg: var(--gray-850);
  --badge-private-text: var(--gray-400);
  --badge-private-border: var(--gray-700);
  --nav-zebra: rgba(255, 255, 255, 0.03);
  --nav-active-bg: var(--rf-brand-light);
  --nav-active-border: var(--rf-brand);
}

/* Diff page */
.diff__header {
  margin-bottom: 1.5rem;
}

.diff__subtitle {
  color: var(--color-muted);
  font-size: 0.95rem;
}

.diff__status {
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  background: var(--color-bg-soft);
  border: 1px solid var(--color-border);
}

.diff__status--added { border-color: #1f7a3a; }
.diff__status--removed { border-color: var(--rf-brand); }

.diff__section { margin: 2rem 0; }

.diff__section--source summary {
  cursor: pointer;
  font-weight: 500;
  margin-bottom: 0.5rem;
}

/* Inline base/compare version pickers in the diff header */
.diff__switch {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  align-items: center;
  margin-top: 0.5rem;
  font-size: 0.9rem;
}

.diff__switch-group {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
}

.diff__switch-label {
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.75rem;
}

.diff__switch-arrow { color: var(--color-muted); }

.diff__switch-plain {
  margin-left: auto;
  font-size: 0.85rem;
}

.diff-lines {
  background: var(--color-code-bg);
  padding: 0.75rem;
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.5;
  white-space: pre;
  overflow-x: auto;
}

.diff-line {
  display: block;
}

.diff-line--unchanged {
  color: var(--color-text);
}

.diff-line--added {
  background: rgba(31, 122, 58, 0.15);
  color: var(--color-text);
}

.diff-line--removed {
  background: rgba(200, 20, 24, 0.12);
  color: var(--color-text);
}

/* "Available in: …" strip on entity pages. The container stacks its two
 * rows (version chips, compare picker); each row is its own wrapping
 * flexbox so chips keep a vertical gap when the strip wraps onto
 * multiple lines. */
.availability {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 0.5rem 0 1rem;
  font-size: 0.85rem;
}

.availability__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 0.5rem;
  align-items: center;
  margin: 0;
}

.availability__label {
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.75rem;
}

.availability__chip {
  font-family: var(--font-mono);
  background: var(--color-bg-soft);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.15em 0.5em;
  color: var(--color-link);
}

.availability__chip--current {
  background: var(--color-link);
  color: var(--color-bg);
  border-color: var(--color-link);
}

/* Since / removed / deprecated badges on entity pages */
.badge {
  display: inline-block;
  font-size: 0.8rem;
  padding: 0.15em 0.6em;
  border-radius: 999px;
  margin-right: 0.5em;
  margin-top: 0.25em;
  font-weight: 500;
  border: 1px solid transparent;
}

.badge a { color: inherit; text-decoration: underline; }

.badge--since {
  background: rgba(0, 240, 255, 0.12);
  color: var(--badge-since-text);
  border-color: rgba(0, 240, 255, 0.45);
}

.badge--removed {
  background: rgba(255, 214, 0, 0.18);
  color: var(--badge-removed-text);
  border-color: rgba(255, 214, 0, 0.55);
}

.badge--deprecated {
  background: rgba(200, 20, 24, 0.12);
  color: var(--badge-deprecated-text);
  border-color: rgba(200, 20, 24, 0.4);
}

.badge--private {
  background: var(--badge-private-bg);
  color: var(--badge-private-text);
  border-color: var(--badge-private-border);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 500;
}

.badge-note {
  margin: 0.25em 0 0;
  font-size: 0.9rem;
  color: var(--color-muted);
}

/* ⌘K command palette */
.palette {
  border: none;
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
  width: min(40rem, 90vw);
  max-height: 70vh;
  padding: 0;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
}

.palette::backdrop { background: rgba(0, 0, 0, 0.4); }

.palette__inner { padding: 0.75rem; }

.palette__input {
  width: 100%;
  font-family: inherit;
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-bg);
  color: var(--color-text);
}

.palette__input:focus {
  outline: none;
  border-color: var(--color-link);
  box-shadow: 0 0 0 2px var(--color-link);
}

.palette__results {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  max-height: 50vh;
  overflow-y: auto;
}

.palette__item {
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  cursor: pointer;
  display: grid;
  /* Kind badge leads (fixed 5.5rem gutter) so it never gets pushed out
   * of view by a long FQN; the name column wraps instead. */
  grid-template-columns: 5.5rem minmax(0, 1fr);
  gap: 0 0.5rem;
}

.palette__item--active,
.palette__item:hover { background: var(--color-bg-soft); }

.palette__fqn {
  background: transparent;
  padding: 0;
  min-width: 0;
  overflow-wrap: anywhere;   /* long FQNs wrap instead of clipping */
}

/* Containing path (e.g. "ActiveModel::SecurePassword::ClassMethods#") is
 * de-emphasized so the eye lands on the method/class name itself. */
.palette__fqn-path {
  font-weight: 400;
  color: var(--color-muted);
}
.palette__fqn-name { font-weight: 600; }

.palette__kind {
  font-size: 0.7rem;
  text-transform: uppercase;
  color: var(--color-muted);
  align-self: start;
  padding-top: 0.25em;
}

.palette__summary {
  grid-column: 2;
  margin: 0.25rem 0 0;
  font-size: 0.85rem;
  color: var(--color-muted);
}

/* "See all N results" footer link into the full search page. */
.palette__all {
  display: block;
  margin: 0.25rem 0.75rem 0;
  padding-top: 0.5rem;
  border-top: 1px solid var(--color-border);
  font-size: 0.85rem;
}

.palette__empty,
.palette__hint {
  margin: 0.5rem 0.75rem;
  font-size: 0.85rem;
}

.palette__hint kbd {
  font-family: var(--font-mono);
  font-size: 0.8em;
  background: var(--color-bg-soft);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0 0.4em;
}

/* Keyboard-shortcuts help overlay ("?"). Shares the .palette dialog
 * chrome (sizing, backdrop, shadow) but is a fixed-size list rather
 * than a search box, so it gets its own inner layout. */
.shortcuts-help {
  width: min(24rem, 90vw);
  max-height: none;
}

.shortcuts-help__inner {
  padding: 1rem 1.25rem;
}

.shortcuts-help__title {
  margin: 0 0 0.75rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-text);
}

.shortcuts-help__list {
  margin: 0;
}

.shortcuts-help__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0;
  border-top: 1px solid var(--color-border);
}
.shortcuts-help__row:first-child { border-top: none; }

.shortcuts-help__row dt kbd {
  font-family: var(--font-mono);
  font-size: 0.8em;
  background: var(--color-bg-soft);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0 0.4em;
}

.shortcuts-help__row dd {
  margin: 0;
  color: var(--color-muted);
  font-size: 0.9rem;
}

/* Shortcut opt-out (WCAG 2.1.4) + explicit close button. */
.shortcuts-help__setting {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 1rem;
  font-size: 0.85rem;
  color: var(--color-muted);
  cursor: pointer;
  user-select: none;
}

.shortcuts-help__setting input {
  margin: 0;
  accent-color: var(--rf-brand);
}

.shortcuts-help__setting kbd {
  font-family: var(--font-mono);
  font-size: 0.8em;
  background: var(--color-bg-soft);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0 0.4em;
}

.shortcuts-help__close {
  margin-top: 1rem;
  padding: 0.35rem 1rem;
  font-family: inherit;
  font-size: 0.85rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg-soft);
  color: var(--color-text);
  cursor: pointer;
}

.shortcuts-help__close:hover {
  border-color: var(--color-link);
  color: var(--color-link);
}

.theme-toggle {
  background: transparent;
  border: 1px solid var(--color-border);
  color: var(--color-text);
  font-size: 1rem;
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  border-radius: var(--radius);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.theme-toggle:hover {
  background: var(--color-bg-soft);
}

* { box-sizing: border-box; }

/* Body type scale matches guides.rubyonrails.org: 16px Inter at
 * line-height 1.4, with common ligatures and oldstyle figures for
 * prose, and the variable font when the browser supports it. */
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.4;
  color: var(--color-text);
  background: var(--color-bg);
  font-feature-settings: "liga" 1;
}

@supports (font-variant-ligatures: common-ligatures) {
  body {
    font-feature-settings: normal;
    font-variant-ligatures: common-ligatures;
  }
}

@supports (font-variant-numeric: oldstyle-nums) {
  body {
    font-variant-numeric: oldstyle-nums;
  }
}

/* Heading type scale (guides _main.scss). h1/h2 use Calibre; h3-h5
 * stay on the body face but step down in size and weight. Headings
 * always use lining figures + kerning so numerals don't sit lower
 * than caps in the visual rhythm. */
h1, h2, h3, h4, h5, h6 {
  font-feature-settings: "kern" 1, "lnum" 1;
  margin-top: 1.5em;
  margin-bottom: 0.5em;
}

@supports (font-variant-numeric: lining-nums) {
  h1, h2, h3, h4, h5, h6, ol, ol > li {
    font-feature-settings: normal;
    font-variant-numeric: lining-nums;
  }
}

h1 {
  color: var(--rf-brand);
  font-family: var(--font-display);
  font-size: 3rem;       /* 48px */
  font-weight: 700;
  line-height: 1;
  margin-top: 0;
}

h2 {
  font-family: var(--font-display);
  font-size: 2.25rem;    /* Calibre runs smaller than Inter at the same px */
  font-weight: 700;
  line-height: 1.1;
}

h2 a, h2 a:link, h2 a:visited { color: var(--color-link); }

h2 code {
  font-size: 2rem;
  font-weight: 400;
}

h3 {
  font-size: 1.5rem;     /* 24px */
  font-weight: 600;
}

h3 code {
  font-size: 1.5rem;
  font-weight: 400;
}

h4 {
  font-size: 1.125rem;
  font-weight: 600;
}

h4 code {
  font-size: 1.125rem;
  font-weight: 400;
}

h5 {
  font-size: 0.9375rem;
  font-weight: 600;
}

h5 code {
  font-size: 0.9375rem;
  font-weight: 400;
}

h1 a, h1 a:link, h2 a, h2 a:link, h3 a, h3 a:link,
h4 a, h4 a:link, h5 a, h5 a:link {
  text-decoration: none;
}

h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover {
  text-decoration: underline;
}

a {
  color: var(--color-link);
  text-decoration: none;
}

/* Links inside running text must be distinguishable by more than hue
 * (WCAG 1.4.1 / axe link-in-text-block) — underline them. Standalone
 * link lists, nav trees, chips and headings aren't in running text and
 * stay clean. */
p a,
.sidebar-block a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Availability chips sit inside a <p> but are distinguished by their
 * border + background, not color alone — keep them unadorned. */
.availability__row a { text-decoration: none; }

a:hover {
  color: var(--color-link-hover);
  text-decoration: underline;
}

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--color-code-bg);
  padding: 0.1em 0.3em;
  border-radius: 4px;
}

pre code {
  background: none;
  padding: 0;
}

.muted { color: var(--color-muted); }

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;                          /* above .module-nav (10) */
  border-bottom: 1px solid var(--color-border);
  background: var(--color-bg);          /* opaque so scrolled content doesn't bleed through */
}

.site-header__inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 1rem 1.5rem;
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

/* Narrow viewports: brand + search button + version switcher + theme
 * toggle can't all fit on one row without the flex items being squeezed
 * past usable size. Wrap onto two rows; the search button shrinks to
 * its content (its ⌘K hint hides — see .header-search-button). */
@media (max-width: 40rem) {
  .site-header__inner {
    flex-wrap: wrap;
    row-gap: 0.75rem;
  }

  .site-header__brand { flex: 1 1 auto; }

  .version-switcher { margin-left: 0; }
}

/* Logo + "API Guides" wordmark, mirroring the rails/guides header
 * lockup. Logo sits left, wordmark in Calibre to match guides type. */
.site-header__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--color-text);
  text-decoration: none;
}

.site-header__brand:hover { text-decoration: none; color: var(--rf-brand); }

.site-header__logo {
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
}

.site-header__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.35rem;
  line-height: 1;
  letter-spacing: -0.01em;
}

/* App shell — left module-nav rail + main column. Sidebar is fixed
 * to the viewport so it doesn't scroll with content; main content
 * gets a left margin to clear it. Toggling `body.module-nav--collapsed`
 * hides the rail and removes the offset. */
.site-shell {
  display: block;
}

.site-main {
  max-width: var(--max-width);
  margin: 0 auto 0 18rem;   /* left offset clears the fixed module-nav */
  padding: 2rem 1.5rem 4rem;
}

@media (max-width: 60rem) {
  .site-main { margin-left: auto; }
}

/* Large monitors: let the content column and right rail use the room
 * instead of leaving a third of the screen blank past 64rem. Prose
 * stays readable because entity pages are mostly code + short
 * paragraphs, and the outline rail absorbs 16rem of the extra width. */
@media (min-width: 90rem) {
  .site-main,
  .site-header__inner { max-width: 84rem; }
  .entity__layout { grid-template-columns: minmax(0, 1fr) 16rem; gap: 3rem; }
}

/* Ultra-wide (2560px-class): grow the shell further, bump the reading
 * size a notch, and cap prose at a book-ish measure — code blocks,
 * method grids and namespace lists still use the full column. This is
 * the Stripe/Tailwind-docs pattern: panels spread, prose doesn't. */
@media (min-width: 110rem) {
  .site-main,
  .site-header__inner { max-width: 100rem; }
  .entity__layout { grid-template-columns: minmax(0, 1fr) 18rem; gap: 4rem; }
  .entity__doc {
    font-size: 1.0625rem;
    max-width: 85ch;
  }
}

body.module-nav--collapsed .site-main {
  margin-left: auto;
}

/* Module-nav (left rail). Starts beneath the sticky header (--header-h)
 * so the logo and search are unobstructed; spans down to the bottom
 * of the viewport with its own internal scroll. */
.module-nav {
  position: fixed;
  top: var(--header-h, 4rem);
  left: 0;
  bottom: 0;
  width: 16.5rem;
  border-right: 1px solid var(--color-border);
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  z-index: 10;
}

body.module-nav--collapsed .module-nav { display: none; }

@media (max-width: 60rem) {
  .module-nav { display: none; }
  body.module-nav--collapsed .module-nav { display: flex; }
  body.module-nav--collapsed .site-main { margin-left: 0; }
  /* On mobile the toggle inverts: nav is hidden by default, shows on toggle */
}

.module-nav__header {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
}

.module-nav__title {
  margin: 0 0 0.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text);
}

.module-nav__filter {
  width: 100%;
  padding: 0.4rem 0.6rem;
  font-size: 0.85rem;
  font-family: inherit;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-bg-soft);
  color: var(--color-text);
}

.module-nav__filter:focus {
  outline: none;
  border-color: var(--color-link);
  box-shadow: 0 0 0 2px var(--color-link);
}

/* "Show ecosystem gems" toggle beneath the filter (rails nav only). */
.module-nav__ecosystem {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.5rem;
  font-size: 0.8rem;
  color: var(--color-muted);
  cursor: pointer;
  user-select: none;
}

.module-nav__ecosystem input {
  margin: 0;
  accent-color: var(--rf-brand);
}

.module-nav__body {
  flex: 1;
  overflow-y: auto;
  padding: 0.25rem 0;
}

/* Method/constant/attribute hits for the sidebar filter — the tree only
 * holds classes and modules, so as-you-type method results come from
 * the suggest endpoint and render in their own group beneath it. */
.module-nav__methods {
  border-top: 1px solid var(--color-border);
  padding: 0.5rem 0;
}

.module-nav__methods-title {
  margin: 0 0.75rem 0.25rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
}

.module-nav__methods ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.module-nav__methods a {
  display: block;
  padding: 0.15rem 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--color-text);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.module-nav__methods a:hover { color: var(--color-link); }

/* Each framework is an expandable group. Closed by default unless
 * the controller marks it active; the framework matching the current
 * page opens automatically. */
.module-nav__group {
  border-bottom: 1px solid var(--color-border);
}

.module-nav__group:last-child { border-bottom: none; }

.module-nav__group-summary {
  list-style: none;
  cursor: pointer;
  padding: 0.5rem 1rem;
  font-size: 0.85rem;
  font-weight: 500;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
}

/* Style the disclosure marker — flip on open. */
.module-nav__group-summary::-webkit-details-marker { display: none; }
.module-nav__group-summary::before {
  content: "▸";
  display: inline-block;
  margin-right: 0.5rem;
  font-size: 0.7rem;
  transition: transform 100ms ease;
  color: var(--color-muted);
}

.module-nav__group[open] > .module-nav__group-summary::before {
  transform: rotate(90deg);
}

.module-nav__group-summary:hover {
  background: var(--color-bg-soft);
  color: var(--color-link);
}

.module-nav__group-name { flex: 1; }
.module-nav__group-count { font-size: 0.75rem; }

/* Collapsible namespace tree. Each node is one row (toggle + label);
 * children nest in a hidden <ul> revealed by the toggle. Depth drives
 * a CSS-var indent so deep FQNs read as a tree, leaf segment only. */
.module-nav__tree,
.module-nav__children {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
}

.module-nav__tree { padding-bottom: 0.5rem; }

.module-nav__node { margin: 0; }

.module-nav__row {
  display: flex;
  align-items: center;
  /* base gutter + one toggle-width (1rem) per nesting level, so a child's
   * left edge aligns under its parent's label — the classic tree look,
   * clearly indented rather than a too-subtle sub-toggle nudge. */
  padding-left: calc(0.5rem + (var(--depth, 0) * 1rem));
  padding-right: 0.5rem;
  border-left: 2px solid transparent;
}

/* Depth → --depth, driven by a data attribute rather than an inline
 * style="--depth:N" (which CSP's style-src would flag per row). Covers
 * the deepest Rails namespaces (~10 levels); anything deeper falls back
 * to the var() default of 0. */
.module-nav__row[data-depth="1"]  { --depth: 1; }
.module-nav__row[data-depth="2"]  { --depth: 2; }
.module-nav__row[data-depth="3"]  { --depth: 3; }
.module-nav__row[data-depth="4"]  { --depth: 4; }
.module-nav__row[data-depth="5"]  { --depth: 5; }
.module-nav__row[data-depth="6"]  { --depth: 6; }
.module-nav__row[data-depth="7"]  { --depth: 7; }
.module-nav__row[data-depth="8"]  { --depth: 8; }
.module-nav__row[data-depth="9"]  { --depth: 9; }
.module-nav__row[data-depth="10"] { --depth: 10; }
.module-nav__row[data-depth="11"] { --depth: 11; }
.module-nav__row[data-depth="12"] { --depth: 12; }

/* Faint zebra striping across rows. :where() zeroes the selector's
 * specificity so hover / active / upstream backgrounds still win. */
:where(.module-nav__node:nth-of-type(even)) > .module-nav__row {
  background: var(--nav-zebra);
}

.module-nav__row:hover {
  background: var(--color-bg-soft);
  border-left-color: var(--color-link);
}

.module-nav__toggle,
.module-nav__toggle-spacer {
  flex: 0 0 1rem;
  width: 1rem;
  height: 1.2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.module-nav__toggle {
  border: 0;
  background: none;
  cursor: pointer;
  position: relative;
  color: var(--color-muted);
  font-size: 0.7rem;
  line-height: 1;
  padding: 0;
}

.module-nav__toggle::before { content: "\25B8"; } /* ▸ */
.module-nav__toggle[aria-expanded="true"]::before { content: "\25BE"; } /* ▾ */

/* The visual glyph is 16×19px — well under the 24px touch-target
 * floor. Grow the hit area with an invisible overlay instead of the
 * element itself so the tree's indent math and row density stay put. */
.module-nav__toggle::after {
  content: "";
  position: absolute;
  inset: -4px -6px;
}

.module-nav__link {
  display: block;
  flex: 1;
  min-width: 0;
  padding: 0.15rem 0;
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.module-nav__link:hover {
  color: var(--color-link);
  text-decoration: none;
}

.module-nav__link--namespace { color: var(--color-muted); cursor: default; }
.module-nav__link--overview { font-style: italic; }

/* Active trail: the current entity's row reverses to brand red with
 * white text; every namespace ancestor on the way down gets a soft
 * 10% red wash so the user can see the path at a glance. */
.module-nav__node--active > .module-nav__row {
  background: var(--nav-active-bg);
  border-left-color: var(--nav-active-border);
}

.module-nav__node--active > .module-nav__row .module-nav__link {
  color: #fff;
  font-weight: 500;
}

.module-nav__node--active > .module-nav__row .module-nav__toggle { color: #fff; }

.module-nav__node--active > .module-nav__row:hover { background: var(--rf-brand-dark); }

.module-nav__node--upstream > .module-nav__row {
  background: rgba(200, 20, 24, 0.1);
  border-left-color: rgba(200, 20, 24, 0.4);
}

[data-theme="dark"] .module-nav__node--upstream > .module-nav__row {
  background: rgba(232, 61, 64, 0.18);
  border-left-color: rgba(232, 61, 64, 0.5);
}

.module-nav__empty {
  padding: 1rem;
  font-size: 0.85rem;
  text-align: center;
}

/* Toggle button — fixed bottom-left so it's always reachable. */
.module-nav-toggle {
  position: fixed;
  bottom: 1rem;
  left: 1rem;
  z-index: 11;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 1rem;
  /* line-height 1 + zero padding so the ☰ glyph actually centers in
   * the circle — the inherited body line-height floats it high. */
  line-height: 1;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.module-nav-toggle:hover {
  background: var(--color-bg-soft);
  border-color: var(--color-link);
  color: var(--color-link);
}

.site-footer {
  border-top: 1px solid var(--color-border);
  padding: 1.5rem;
  text-align: center;
  color: var(--color-muted);
  font-size: 0.9rem;
}

.home h1 { margin-top: 0; }
.home__lede { font-size: 1.15rem; color: var(--color-muted); }

/* Inline search form under the hero — same look as the header search
 * input, plus a visible submit button since there's room for one here. */
.home__search {
  display: flex;
  gap: 0.5rem;
  max-width: 28rem;
  margin: 0 0 1.5rem;
}

.home__search input[type="text"] {
  flex: 1;
  min-width: 0;
  font-family: inherit;
  font-size: 0.95rem;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}

.home__search input[type="text"]:focus {
  outline: none;
  border-color: var(--color-link);
  box-shadow: 0 0 0 2px var(--color-link);
}

.home__search input[type="submit"] {
  padding: 0.4rem 1rem;
  font-family: inherit;
  font-size: 0.95rem;
  border: 1px solid var(--color-border);
  background: var(--color-bg-soft);
  color: var(--color-text);
  border-radius: var(--radius);
  cursor: pointer;
}

.home__search input[type="submit"]:hover {
  border-color: var(--color-link);
  color: var(--color-link);
}

/* Responsive multi-column grid — 3-ish columns on desktop, collapsing
 * to fewer (then 1) as the viewport narrows. */
.framework-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 1rem 0;
}

.framework-card {
  padding: 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.framework-card h2,
.framework-card h3 {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
}

.framework-card .muted { margin: 0; font-size: 0.85rem; }

.version-list__link { font-weight: 500; margin-right: 0.5rem; }
.version-list__meta { color: var(--color-muted); font-size: 0.9rem; }

/* Version list grouped by major series — a label column plus a wrapping
 * row of compact inline links, so the whole history fits in roughly a
 * screenful instead of one row per patch release. */
.version-groups {
  margin: 1rem 0;
}

.version-groups__row {
  display: flex;
  gap: 1rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--color-border);
}

.version-groups__series {
  flex: 0 0 4rem;
  font-weight: 600;
  color: var(--color-muted);
}

.version-groups__list {
  margin: 0;
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  column-gap: 0.9rem;
  row-gap: 0.25rem;
}

@media (max-width: 30rem) {
  .version-groups__row { flex-direction: column; gap: 0.25rem; }
}

.entity__breadcrumb {
  font-family: var(--font-mono);
  color: var(--color-muted);
  font-size: 0.9rem;
  margin: 0 0 0.25rem;
}

/* GitHub-style anchor copy link on headings */
.anchor-link {
  display: inline-block;
  margin-left: 0.35em;
  font-weight: normal;
  text-decoration: none;
  color: var(--color-muted);
  opacity: 0;
  transition: opacity 0.15s, color 0.15s;
}

h1:hover > .anchor-link,
h2:hover > .anchor-link,
h3:hover > .anchor-link,
h4:hover > .anchor-link,
.anchor-link:focus {
  opacity: 1;
}

.anchor-link:hover {
  color: var(--color-link);
  text-decoration: none;
}

.anchor-link--copied {
  opacity: 1;
  color: var(--color-link);
}

.anchor-link--copied::after {
  content: " copied";
  font-size: 0.75rem;
}

.entity__name {
  margin: 0 0 0.5rem;
  font-size: 2rem;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
}

.entity__kind {
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.15em 0.5em;
}

.entity__version {
  color: var(--color-muted);
  font-size: 0.95rem;
  margin-top: 0;
}

.entity__doc { margin: 2rem 0; }

.entity__source {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--color-border);
  color: var(--color-muted);
  font-size: 0.9rem;
}

/* File paths have no spaces to wrap at — let them break mid-token
 * rather than widening the page on narrow viewports. */
.entity__source code { overflow-wrap: anywhere; }

.entity__body section h2 {
  margin-top: 2rem;
  font-size: 1.25rem;
  border-bottom: 1px solid var(--color-border);
  padding-bottom: 0.25rem;
}

.method-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0.25rem 1rem;
}

.method-list li {
  padding: 0.15rem 0;
}

.method-list__scope {
  color: var(--color-muted);
  font-family: var(--font-mono);
}

.method-group {
  margin-bottom: 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg-soft);
}

.method-group summary {
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  font-weight: 500;
}

.method-group summary code {
  background: transparent;
  padding: 0;
}

.method-group__count {
  color: var(--color-muted);
  font-weight: normal;
  font-size: 0.9em;
}

.method-group__hint {
  display: block;
  font-size: 0.85em;
  font-weight: normal;
  margin-top: 0.15rem;
}

.method-group .method-list {
  padding: 0 0.75rem 0.75rem;
}

.entity__private-methods { margin-top: 1.5rem; }

/* Ancestor name in an inherited-methods group summary — plain text (a
 * link inside a summary nests interactive controls), styled like the
 * entity links around it. */
.method-group__ancestor {
  background: transparent;
  padding: 0;
}

/* Breadcrumbs */
.breadcrumbs {
  font-family: var(--font-mono);
  font-size: 0.875rem;
  color: var(--color-muted);
  margin-bottom: 0.25rem;
}

.breadcrumbs ol {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.breadcrumbs li:not(:last-child)::after {
  content: "::";
  margin-left: 0.25rem;
  color: var(--color-muted);
}

.breadcrumbs a { color: var(--color-link); }
.breadcrumbs [aria-current="page"] { color: var(--color-text); }

/* Layout (body + outline aside) */
.entity__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 14rem;
  gap: 2rem;
  margin-top: 1.5rem;
}

@media (max-width: 60rem) {
  /* minmax(0, 1fr), not bare 1fr: a 1fr track's automatic minimum is
   * min-content, so a wide <pre> would push the single column past the
   * viewport instead of scrolling inside it — the same trap fixed on
   * the desktop two-column template above. */
  .entity__layout { grid-template-columns: minmax(0, 1fr); }
  /* Previously `order: -1` here forced the outline (On this page / Support
   * / License) to render above the doc body on narrow viewports, pushing
   * the actual content below the fold. .entity__body already comes first
   * in the DOM, so leaving order unset (the default, 0) makes the grid
   * follow DOM order: body first, outline second. Desktop layout (body
   * left, outline right) is unaffected since this rule only applies
   * inside the max-width: 60rem media query. */
}

.entity__body { min-width: 0; }

.entity__doc h1, .entity__doc h2, .entity__doc h3 {
  margin-top: 1.25rem;
  margin-bottom: 0.5rem;
}

.entity__doc h2 { font-size: 1.15rem; }
.entity__doc h3 { font-size: 1rem; }
.entity__doc pre {
  background: var(--color-code-bg);
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.5;
}
.entity__doc :not(pre) > code {
  white-space: nowrap;
}

/* On narrow viewports an unbreakable inline token (a long FQN in <code>)
 * can be wider than the whole screen — let it wrap mid-token there
 * rather than force horizontal scroll. Placed after the nowrap rule so
 * it wins the same-specificity source-order tiebreak. */
@media (max-width: 40rem) {
  .entity__doc :not(pre) > code {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* --------------------------------------------------------------------------
 * Syntax highlighting (Rouge). Dark code block in both light and dark mode,
 * token palette copied from rails/guides (assets/stylesrc/highlight.scss)
 * for visual parity. Rouge emits CSS-class spans (.k, .nf, …) — no inline
 * styles, so this is CSP-clean.
 * -------------------------------------------------------------------------- */
pre.highlight {
  background: #292929;
  color: #f8f8f2;
  padding: 0.85rem 1rem;
  border-radius: var(--radius);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.5;
  margin: 0 0 1rem;
}
pre.highlight code {
  background: none;
  padding: 0;
  color: inherit;
  white-space: pre;
}

/* Emphasis */
.highlight .c, .highlight .cd, .highlight .ch, .highlight .cm,
.highlight .cpf, .highlight .c1, .highlight .ge { font-style: italic; }
.highlight .cp, .highlight .cs, .highlight .fm, .highlight .gs,
.highlight .kc, .highlight .kd, .highlight .kn, .highlight .kp,
.highlight .kr, .highlight .kt, .highlight .nc, .highlight .nd,
.highlight .ne, .highlight .nf, .highlight .nl, .highlight .o,
.highlight .ow { font-weight: 500; }

/* Token colors */
.highlight .c   { color: #b4b4b3; }
.highlight .err { color: #ff0088; background-color: #1e0010; }
.highlight .k   { color: #9decfc; }
.highlight .l   { color: #cfb7fd; }
.highlight .n   { color: #f8f8f2; }
.highlight .o   { color: #ff699b; }
.highlight .p   { color: #f8f8f2; }
.highlight .pi  { color: #c74646; }
.highlight .cm  { color: #b4b4b3; }
.highlight .cp  { color: #b4b4b3; }
.highlight .c1  { color: #b4b4b3; }
.highlight .cs  { color: #b4b4b3; }
.highlight .kc  { color: #9decfc; }
.highlight .kd  { color: #9decfc; }
.highlight .kn  { color: #ff699b; }
.highlight .kp  { color: #9decfc; }
.highlight .kr  { color: #9decfc; }
.highlight .kt  { color: #9decfc; }
.highlight .ld  { color: #fff5ab; }
.highlight .m   { color: #cfb7fd; }
.highlight .s   { color: #fff5ab; }
.highlight .na  { color: #d0ff71; }
.highlight .nb  { color: #f8f8f2; }
.highlight .nc  { color: #d0ff71; }
.highlight .no  { color: #9decfc; }
.highlight .nd  { color: #d0ff71; }
.highlight .ni  { color: #f8f8f2; }
.highlight .ne  { color: #d0ff71; }
.highlight .nf  { color: #d0ff71; }
.highlight .nl  { color: #f8f8f2; }
.highlight .nn  { color: #f8f8f2; }
.highlight .nx  { color: #d0ff71; }
.highlight .py  { color: #f8f8f2; }
.highlight .nt  { color: #ff699b; }
.highlight .nv  { color: #f8f8f2; }
.highlight .ow  { color: #ff699b; }
.highlight .w   { color: #f8f8f2; }
.highlight .mf  { color: #cfb7fd; }
.highlight .mh  { color: #cfb7fd; }
.highlight .mi  { color: #cfb7fd; }
.highlight .mo  { color: #cfb7fd; }
.highlight .sb  { color: #fff5ab; }
.highlight .sc  { color: #fff5ab; }
.highlight .sd  { color: #fff5ab; }
.highlight .s2  { color: #fff5ab; }
.highlight .se  { color: #cfb7fd; }
.highlight .sh  { color: #fff5ab; }
.highlight .si  { color: #fff5ab; }
.highlight .sx  { color: #fff5ab; }
.highlight .sr  { color: #fff5ab; }
.highlight .s1  { color: #fff5ab; }
.highlight .ss  { color: #fff5ab; }
.highlight .bp  { color: #f8f8f2; }
.highlight .vc  { color: #f8f8f2; }
.highlight .vg  { color: #f8f8f2; }
.highlight .vi  { color: #f8f8f2; }
.highlight .il  { color: #cfb7fd; }
.highlight .gh  { color: #b4b4b3; }
.highlight .gu  { color: #9e9b8a; }
.highlight .gd  { color: #ff699b; }
.highlight .gi  { color: #d0ff71; }
.highlight .gr  { color: #ff699b; }
.highlight .go  { color: #b4b4b3; }
.highlight .gp  { color: #fff; }

/* Copy-to-clipboard button, injected by code_copy_controller.js into
 * every pre.highlight. Positioned over the block rather than in normal
 * flow so it doesn't add height or interfere with the pre's own
 * horizontal scrolling. Subtle by default on pointer devices (revealed
 * on hover/focus); always visible on touch, where there's no hover to
 * reveal it. Colors come from the shared variables (not the Rouge
 * token palette above, which is intentionally fixed-dark in both
 * themes) so the control itself still follows light/dark mode. */
pre.highlight {
  position: relative;
}
.code-copy {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  padding: 0.25em 0.6em;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  opacity: 0;
  cursor: pointer;
  transition: opacity 0.1s ease-in-out;
}
pre.highlight:hover .code-copy,
pre.highlight:focus-within .code-copy,
.code-copy:focus {
  opacity: 1;
}
.code-copy--copied {
  color: var(--color-bg);
  background: var(--color-text);
  border-color: var(--color-text);
}
@media (hover: none) {
  .code-copy {
    opacity: 1;
  }
}

/* Sticky right rail. The whole aside (outline + Support/License block)
 * sticks as one unit so the two children don't overlap on scroll. On
 * very tall pages where the rail is taller than the viewport,
 * max-height + overflow keep the rail scrollable on its own. Top offset
 * clears the sticky site header (z-index 20, opaque) — without it the
 * rail's first rows disappear behind the header once you scroll. */
.entity__outline {
  position: sticky;
  top: calc(var(--header-h, 4rem) + 1rem);
  align-self: start;
  max-height: calc(100vh - var(--header-h, 4rem) - 2rem);
  overflow-y: auto;
}

@media (max-width: 60rem) {
  .entity__outline {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

/* Outline */
.outline {
  font-size: 0.9rem;
  border-left: 1px solid var(--color-border);
  padding-left: 1rem;
}

.outline__title,
.sidebar-block__title {
  /* Shared rail-section caption — keep these in lockstep so the right
   * rail's typography reads as one continuous strip. */
  margin: 0 0 0.5rem;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
}

.outline__title { margin-top: 0; }

.outline ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.outline li { margin: 0.25rem 0; }

/* Sidebar block — used for the curated Support + License block beneath
 * the page outline. Matches the outline's typographic treatment so the
 * whole right rail reads as one continuous strip. */
.sidebar-block {
  margin-top: 2rem;
  padding-left: 1rem;
  border-left: 1px solid var(--color-border);
  font-size: 0.9rem;
  color: var(--color-muted);
}

.sidebar-block__title--license { margin-top: 1.25rem; }

.sidebar-block__list {
  list-style: none;
  padding: 0;
  margin: 0 0 0.5rem;
}

.sidebar-block__list li { margin: 0 0 0.5rem; line-height: 1.4; }

.sidebar-block__text { margin: 0; line-height: 1.4; }

/* Version switcher */
.version-switcher {
  margin-left: auto;
  font-size: 0.9rem;
  color: var(--color-muted);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.version-switcher select {
  font-family: inherit;
  font-size: inherit;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text);
}

/* Native dropdown popups follow color-scheme, but option text can still
 * render dim against the popup background in dark mode — pin both to
 * the theme palette. */
select option {
  color: var(--color-text);
  background: var(--color-bg);
}

.version-switcher--single {
  font-family: var(--font-mono);
  background: var(--color-code-bg);
  padding: 0.15em 0.5em;
  border-radius: 4px;
}

/* Module list (for Includes/Extends/Namespace). Long FQNs like
 * ActionCable::Channel::NonInferrableChannelError must stay fully
 * visible (user feedback: names are the information — never hide
 * them), so cells wrap onto extra lines instead of truncating.
 * overflow-wrap: anywhere lets an unbroken FQN break mid-token when
 * it's wider than the cell, so it can't bleed into the next column. */
.entity__module-list,
.entity__simple-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 0.25rem 1rem;
}

.entity__module-list > li,
.entity__simple-list > li {
  min-width: 0;          /* allow the cell to shrink below content width */
}

.entity__module-list > li > a,
.entity__simple-list > li > a,
.entity__module-list > li > code,
.entity__simple-list > li > code {
  display: block;
  overflow-wrap: anywhere;
}

/* Signature block on method pages */
.signature {
  background: var(--color-code-bg);
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 0.95rem;
  margin: 1rem 0;
  overflow-x: auto;
}

.signature--call-seq { white-space: pre; }

/* Params list on method pages */
.param-list dt {
  margin-top: 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.95rem;
}

.param-list__kind {
  display: inline-block;
  margin-left: 0.5rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0 0.4em;
  font-family: var(--font-body);
}

.param-list__default { color: var(--color-muted); }
.param-list dd { margin: 0.25rem 0 0 1rem; color: var(--color-muted); }

/* Source code block on method pages */
.entity__source-code summary {
  cursor: pointer;
  color: var(--color-muted);
  margin: 1rem 0 0.5rem;
}

.entity__source-code pre {
  background: var(--color-code-bg);
  padding: 1rem;
  border-radius: var(--radius);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  white-space: pre;
}

.entity__back {
  margin-top: 2rem;
  font-size: 0.95rem;
  color: var(--color-muted);
}

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

/* Skip-to-main keyboard affordance — invisible until focused. */
.skip-link {
  position: absolute;
  top: -100px;
  left: 0.5rem;
  padding: 0.5rem 0.75rem;
  background: var(--color-bg);
  color: var(--color-link);
  border: 2px solid var(--color-link);
  font-weight: 600;
  z-index: 100;
}

.skip-link:focus,
.skip-link:focus-visible {
  top: 0.5rem;
  outline: none;
}

/* Default visible Tab outline. Components that paint their own focus
 * indicator (palette__input, site-header__search input, anchor-link)
 * suppress this with `outline: none` paired with their custom paint. */
:focus-visible {
  outline: 2px solid var(--color-link);
  outline-offset: 2px;
}

/* Honor user motion preferences across all animations and transitions. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Header search affordance — a button styled like an input that opens
 * the ⌘K palette. One search UI instead of three: the palette (and the
 * sidebar filter) do the searching; this is just the front door. */
.header-search-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  max-width: 22rem;
  padding: 0.4rem 0.75rem;
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--color-muted);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  cursor: pointer;
  text-align: left;
}

.header-search-button:hover {
  border-color: var(--color-link);
  color: var(--color-link);
}

.header-search-button kbd {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.8em;
  background: var(--color-bg-soft);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0 0.4em;
}

@media (max-width: 40rem) {
  .header-search-button {
    flex: 0 0 auto;
    min-height: 2.75rem;   /* tap target */
  }
  .header-search-button kbd { display: none; }
}

/* Search results page */
.search-page__form {
  margin: 1rem 0 2rem;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
}

.search-page__input {
  flex: 1;
  min-width: 18rem;
  font-family: inherit;
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.search-page__submit {
  padding: 0.5rem 1rem;
  font-family: inherit;
  font-size: 1rem;
  border: 1px solid var(--color-border);
  background: var(--color-bg-soft);
  color: var(--color-text);
  border-radius: var(--radius);
  cursor: pointer;
}

.search-page__count {
  margin: 1rem 0;
  color: var(--color-muted);
  font-size: 0.9rem;
}

.search-layout {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 2rem;
  margin-top: 1.5rem;
}

@media (max-width: 768px) {
  .search-layout { grid-template-columns: minmax(0, 1fr); }
}

/* Results column is a grid item, but its own contents (long FQNs with no
 * natural break points) still need to be told they're allowed to shrink —
 * otherwise their min-content width pushes this column, the grid, and the
 * whole .site-shell wider than the viewport, causing horizontal scroll. */
.search-results-column { min-width: 0; }

.search-facets h2 {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  margin: 1.25rem 0 0.5rem;
  border: none;
  padding: 0;
}

.search-facets ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.search-facets li { padding: 0.15rem 0; font-size: 0.95rem; }

.search-facets a.active {
  font-weight: 600;
  color: var(--color-link);
}

.search-facets__chip {
  display: inline-block;
  font-size: 0.8rem;
  padding: 0.15em 0.6em;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  margin-right: 0.4em;
  color: var(--color-muted);
}

.search-facets__chip--remove { color: var(--color-link); cursor: pointer; }
.search-facets__chip--remove:hover { background: var(--color-bg-soft); text-decoration: none; }

.search-results {
  list-style: none;
  padding: 0;
  margin: 0;
}

.search-result {
  padding: 1rem 0;
  border-bottom: 1px solid var(--color-border);
  min-width: 0;
}

/* FQNs like ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
 * have no natural break points, so without overflow-wrap they read as one
 * unbreakable token and force this element (and every ancestor grid/flex
 * track up to .site-shell) to widen past the viewport. Let long ones wrap. */
.search-result__breadcrumb {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--color-muted);
  margin: 0;
  overflow-wrap: break-word;
}

.search-result__name {
  font-size: 1.1rem;
  margin: 0.25rem 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
  min-width: 0;
}

.search-result__name a {
  overflow-wrap: break-word;
  min-width: 0;
}

.search-result__kind {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.1em 0.4em;
}

.search-result__summary {
  margin: 0.25rem 0;
  color: var(--color-text);
}

.search-result__meta {
  font-size: 0.85rem;
  margin: 0.25rem 0 0;
}
