/* ===================================================================
   COMPONENTS PAGE — page-scoped chrome for components.html only (the
   new "Components" showcase page, Phase 4). Named components-page.css,
   not components.css, deliberately: components/components.js already
   owns that name for the shared design-system component loader — a
   second, unrelated file called "components.js"/"components.css" sitting
   at the project root would be exactly the kind of naming collision this
   project's own naming discipline exists to avoid, especially on the one
   page that's actually about component naming.

   Reuses field-guide.css's .sandbox-shell/.sandbox-header/.sandbox-note
   for the page's own outer column and header block (this page is a
   fourth reference-kit sibling to Type Scale/Color System/Layout &
   Spacing, not shipped product UI) — only what's genuinely new to this
   page (the nav/jump-link section, group headings, stub sections) lives
   here.
   =================================================================== */

/* This page also loads search.css (below the two links above, in
   components.html's own <head>) — needed for .category-tree,
   .date-mode-*, and .card-filter*, real component classes with no
   other home. But search.css's own file-header comment is explicit
   that its html,body rule (height:100%, overflow:hidden) is a
   deliberate, page-specific choice for search.html's own single-screen
   app shell (the map fills the remaining viewport, the page itself
   never scrolls) — not a general reset. This page is an ordinary long
   scrolling document, not an app shell, so that assumption doesn't
   hold here; loading search.css for its component classes pulled it in
   as an unintended side effect anyway. Reset back to a normal
   scrolling page, specifically here (loaded after search.css, so this
   wins the cascade at equal specificity) rather than editing search.css
   itself, which still needs its own real rule unchanged for search.html. */
html, body {
  height: auto;
  overflow: visible;
}

/* ---- Nav / jump-link section ---- */

.components-nav {
  position: sticky;
  /* top is set live via JS (components.html's own inline script), read
     from the masthead's own real rendered height at mount time — not
     calc()'d from spacing tokens. Same "measure live, don't guess"
     discipline this project's own dropdown menus already use (Reference
     doc, Section 45): a hardcoded number here would silently drift out
     of sync with any future masthead height change (narrow-viewport
     tag/divider hiding, a font-metrics change, a new masthead element)
     with nothing to flag it at build time. 25, not the original 5 —
     see the .masthead override below for the stacking conflict that
     forced this number: every masthead demo inherits a real z-index:10
     from masthead.css's own base .masthead rule, and once each demo
     masthead became position:relative (below) that z-index stopped
     being a no-op and started competing directly with this nav. 25
     clears both that (10) and the hamburger/profile menu dropdowns'
     own z-index:20 (masthead.css) — this nav must stay on top even if
     an open dropdown demo would otherwise overlap it, per this page's
     own explicit requirement. */
  z-index: 25;
  background: var(--color-surface);
  margin-bottom: var(--space-8);
}

.components-nav-divider {
  height: var(--border-width-hairline);
  background: var(--color-hairline);
}

/* Chevron + heading row — the filter card's own disclosure pattern
   reused deliberately (native <details>/<summary>, marker hidden,
   chevron rotates on [open]; see .filter-section-summary/-chevron,
   search.css), not a fresh toggle mechanism invented for this one page.
   The one deliberate departure, per this page's own spec: closed by a
   single .components-nav-divider, a SIBLING of .components-nav-details
   (not a child of it — post-Phase-5 correction, below) instead of
   filter-section's own top-of-panel divider — since it's an ordinary
   sibling following the <details> element in flow, it always renders
   directly below whatever the <details> element currently shows
   (summary alone, closed; summary + grid, open), giving the "grows
   downward to contain the list" effect the task described with no JS
   or scroll-tracking needed, purely from ordinary document flow, in
   BOTH states (Phase 5 batch 2). There is deliberately no second
   divider above the summary any more, at .components-nav's own top
   edge, addressing two real symptoms of the same removed element: at
   the page's normal scroll position it duplicated .sandbox-header's
   own trailing border-bottom immediately above it (field-guide.css) —
   that rule already IS this section's real top boundary, needing no
   second independent line — and once scrolled far enough that
   .components-nav is stuck flush below the masthead (top offset
   above), that same removed line used to read as a stray extra 1px
   seam on the masthead's own bottom edge; with it gone, the sticky nav
   now sits flush against the masthead with no visible seam either way.

   Corrected post-Phase-5: Batch 2 had originally placed the divider as
   the LAST CHILD of .components-nav-details itself, not a sibling —
   which produced the exact same visible open-state result (also the
   last thing to render, also below the grid) but silently broke the
   CLOSED state, since a native <details> element renders nothing but
   its own <summary> while closed — every other child, including that
   divider, is display:none regardless of source order. Confirmed live
   before fixing: with the section closed, .components-nav-divider
   measured a real height/width but zero actual paint (parent <details>
   collapsed around it) — moving the divider outside <details> entirely
   fixes the closed state without changing the open state's own
   rendered position at all, confirmed live post-fix (below). */
.components-nav-summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--font-ui);
  font-size: var(--ui-body-sm-size);
  font-weight: var(--w-medium);
  color: var(--color-ink);
}

.components-nav-summary::-webkit-details-marker {
  display: none;
}

.components-nav-summary::marker {
  content: '';
}

/* Real Lucide chevron-right glyph (icons/icons.js), filled in by this
   page's own [data-icon] sweep — CSS-icon audit finding #6
   (Reference/css-icon-audit.md), replacing the ‘›’ text character this
   used to be. Same width/height + inner svg pattern every other icon
   on this site uses (.controls-map-icon, .results-command-icon). */
.components-nav-chevron {
  display: inline-flex;
  flex-shrink: 0;
  width: var(--ui-h4-size);
  height: var(--ui-h4-size);
  color: var(--color-ink);
  transition: transform 0.15s ease;
}

.components-nav-chevron svg {
  display: block;
  width: 100%;
  height: 100%;
}

.components-nav-details[open] > .components-nav-summary .components-nav-chevron {
  transform: rotate(90deg);
}

/* Responsive multi-column grid — the same auto-fill formula
   field-guide.css's own .swatch-grid already uses
   (repeat(auto-fill, minmax(...), 1fr)) — column count derives from
   available width and the minmax floor, never a hardcoded count. 180px
   floor (vs. swatch-grid's 140px) since component names run longer than
   color-swatch names — "Data Provenance section" is the longest entry
   below, at 24 characters. */
.components-nav-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-3) var(--space-5);
  padding: var(--space-4) 0 var(--space-6);
}

.components-nav-group-label {
  grid-column: 1 / -1;
  font-family: var(--font-ui);
  font-size: var(--ui-overline-size);
  font-weight: var(--w-semibold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-faint);
  margin-top: var(--space-3);
}

.components-nav-group-label:first-child {
  margin-top: 0;
}

.components-nav-link {
  font-family: var(--font-ui);
  font-size: var(--ui-body-sm-size);
  color: var(--color-ink-secondary);
  text-decoration: none;
}

.components-nav-link:hover,
.components-nav-link:focus-visible {
  color: var(--color-ink);
  text-decoration: underline;
}

/* ---- Component-group headings + stub sections ---- */

.components-group-heading {
  margin: 0 0 var(--space-5);
  padding-top: var(--space-8);
  border-top: var(--border-width-hairline) solid var(--color-hairline);
}

.components-group-heading:first-of-type {
  padding-top: 0;
  border-top: none;
}

/* scroll-margin-top keeps a jumped-to stub clear of the sticky masthead
   + nav section (both real, opaque, stacked at the viewport's top edge)
   instead of landing directly underneath them. --sticky-header-height is
   set live via JS (components.html's own inline script) from the two
   sticky elements' own real combined height — the same "measure, don't
   guess" reasoning as .components-nav's own top offset above. The
   120px fallback only covers the moment before that JS runs. */
.component-stub {
  padding: var(--space-6) 0;
  border-bottom: var(--border-width-hairline) solid var(--color-hairline);
  scroll-margin-top: var(--sticky-header-height, 120px);
}

.component-stub:last-child {
  border-bottom: none;
}

.component-stub-title {
  margin: 0;
}

/* ---- Live-example scaffolding (Prompt 2+) ----
   Subtitle reuses colors.html's own .swatch-hex SF Mono treatment
   verbatim (field-guide.css) for the real in-code name — same "raw
   identifier, monospace, faint" convention, just applied to a component
   name instead of a hex value. */
.component-stub-subtitle {
  font-family: 'SF Mono', 'Consolas', monospace;
  font-size: 0.75rem;
  color: var(--color-faint);
  margin: var(--space-1) 0 0;
}

.component-stub-copy {
  font-family: var(--font-ui);
  font-size: var(--ui-body-sm-size);
  color: var(--color-muted);
  max-width: 640px;
  margin: var(--space-3) 0 var(--space-5);
}

.component-stub-example-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.component-stub-example-label {
  font-family: var(--font-ui);
  font-size: var(--ui-caption-size);
  font-weight: var(--w-medium);
  color: var(--color-muted);
  margin: 0 0 var(--space-3);
}

/* Sunken card, matching the "content sits on a visibly recessed tray"
   convention .filter-section-summary already established (search.css)
   for setting worked/demo content apart from ordinary page copy.
   position:relative — see the .masthead override below for why this
   matters for the Masthead/Hamburger menu/Profile menu examples
   specifically. */
.component-stub-example {
  position: relative;
  border: var(--border-width-hairline) solid var(--color-hairline);
  border-radius: var(--radius-card);
  background: var(--color-surface-sunken);
  padding: var(--space-6);
  overflow: auto;
}

/* Masthead/Hamburger menu/Profile menu examples mount a real, live
   .masthead — edge-to-edge, no padding (a masthead with a padded margin
   around it wouldn't look like the real full-bleed bar it actually is).
   Deliberately NOT overflow:hidden here, even though that would also
   clip the masthead's own square corners to match the box's rounded
   ones: the hamburger/profile menu dropdowns mounted in these same
   examples are position:absolute, extending below the masthead's own
   box — clipping this wrapper would cut them off the moment they open.
   A masthead's real corners are square by design (it's normally a
   full-bleed bar with nothing to round against), so left square here
   too rather than faked round only in this one demo context. */
.component-stub-example--flush {
  padding: 0;
  /* .component-stub-example's own base overflow:auto (below) exists for
     the Filter card shell's sideways-safety; here it would clip the
     hamburger/profile dropdowns the moment they extend below the
     masthead's own box, since this wrapper otherwise shrink-wraps to
     exactly the masthead's own height. Dropdowns are meant to overlay
     whatever's below them, same as the real masthead's own — visible
     lets them render past this box's edge instead of being cut off. */
  overflow: visible;
}

/* .masthead's own base rule (masthead.css) is unconditionally
   position:sticky — correct for the one REAL masthead this page mounts
   at its very top, wrong for every demo instance further down the page:
   those would try to pin themselves to the viewport's own top edge
   while scrolling past, competing with the real masthead above and with
   each other. Overridden to position:relative here specifically (not
   static) because relative still establishes a containing block for the
   dropdown menus' own position:absolute/top:100% — exactly what
   position:sticky already did for the real masthead (Reference doc,
   Section 45) — static would silently break that positioning instead of
   just fixing the scroll behavior. Higher specificity than the bare
   .masthead rule (two classes vs. one) wins regardless of stylesheet
   load order.

   z-index reset to auto here too — masthead.css's own base rule pairs
   position:sticky with z-index:10, which was harmless as long as this
   override only touched position/top: a positioned-but-z-index:auto
   element doesn't create its own stacking context, so that 10 was
   inert. The instant this element became position:relative WITHOUT
   also resetting z-index, that inherited 10 stopped being inert — it
   made every demo masthead its own real stacking-context root, high
   enough to paint over .components-nav's own sticky bar (z-index:5 at
   the time) as it scrolled past underneath. Resetting to auto removes
   that accidental stacking context entirely, so this element's real
   stacking position is governed purely by document order within its
   ancestors', same as any other ordinary in-flow content — which is
   the correct behavior for a demo masthead that isn't supposed to be
   competing for stacking priority with anything on this page. */
.component-stub-example .masthead {
  position: relative;
  top: auto;
  z-index: auto;
}

/* Hamburger menu / Profile menu examples (Phase 5 batch 10,
   post-Phase-5 straggler) — these two still mount a real, complete
   ComponentLoader.mountMasthead({variant:'primary'}) internally (the
   icon button genuinely needs it: .masthead-icon-btn is styled
   color:var(--color-surface), meant to read against .masthead's own
   real --color-ink background — there's no way to render the button's
   real look without that host), but everything about that masthead
   OTHER than the one relevant icon and its dropdown is surrounding
   context, not the menu component itself, the same "show the
   component in isolation" framing every other example on this page
   already follows (Buttons/Checkboxes/etc. never render inside a full
   page shell either). Hidden via display:none rather than removed
   from the DOM or from the mount call, so Copy HTML still reflects the
   real, complete masthead markup underneath unchanged — only this
   demo's own visual presentation is simplified, not the actual copied
   snippet.

   .masthead itself switches to inline-flex (from its base rule's
   plain block header) so it shrink-wraps to whatever content remains
   visible instead of spanning the full example width as an empty ink
   bar with one icon stranded at its far right edge — the same
   "the box should size to a lone icon, not a full bar" problem item 5
   above diagnoses inside a real masthead; this is the isolated-demo
   version of avoiding it. .masthead-inner's own base max-width:760px/
   margin:0 auto (sized to match the page's own content column) is
   reset to width:fit-content/margin:0 for the same reason — with
   .masthead now shrink-wrapped, that centering/capping logic has
   nothing left to size against. */
/* The outer .component-stub-example wrapper itself — real bug, found
   live post-Batch-10: the modifier above correctly shrinks .masthead
   down to just the one relevant icon, but never touched the WRAPPER's
   own base rule (.component-stub-example above), which still carries
   its real border + background:var(--color-surface-sunken). The
   result was the shrink-wrapped ink masthead sitting inside a second,
   full-width sunken plate — the exact "recessed tray" treatment every
   other example genuinely needs (Buttons/Checkboxes/etc.), which is
   precisely the surrounding chrome these two examples are supposed to
   have none of, per this section's own "show the component in
   isolation" framing. Same fix as .component-stub-example--card-filter
   above (Batch 10, item 4) — reset to nothing; .component-stub-example
   --flush's own padding:0/overflow:visible are left alone, still
   needed for the dropdown's own sideways-safety. */
.component-stub-example--menu-only {
  border: none;
  background: none;
}

.component-stub-example--menu-only .masthead {
  display: inline-flex;
}

.component-stub-example--menu-only .masthead-inner {
  max-width: none;
  width: fit-content;
  margin: 0;
}

.component-stub-example--menu-only .masthead-wordmark,
.component-stub-example--menu-only .masthead-divider,
.component-stub-example--menu-only .masthead-tag,
.component-stub-example--menu-only .theme-toggle {
  display: none;
}

/* Each demo shows only the icon it's actually demonstrating — the
   Hamburger menu example hides the unused profile icon, the Profile
   menu example hides the unused hamburger icon — rather than showing
   both side by side, which would misrepresent either section as
   demonstrating two components at once. */
#demo-masthead-hamburger .masthead-icon-profile {
  display: none;
}

#demo-masthead-profile .masthead-icon-hamburger {
  display: none;
}

/* Filter card — shown at its own full natural height, no internal
   scroll clipping it (Reference doc, Section 80; a fixed-height demo
   box with .card-filter__scroll's own real overflow-y:auto, the original
   approach, meant expanding a section could leave the rest of the card
   scrolled out of view within its own small box — not a good showcase
   experience for a page whose whole point is showing what's actually
   there). The real .card-filter is position:absolute with top/bottom
   offsets sized to whatever positioned ancestor it's given (search.css)
   — since this demo wants the opposite (grow to fit real content, no
   fixed box to fill), .card-filter itself is switched to position:static
   here instead of overriding the wrapper's own height, and
   .card-filter__panel/.card-filter__scroll both get overflow:visible so
   nothing about their own real flex-scroll mechanism (sized for a fixed
   viewport-relative box) tries to clip or scroll this naturally-tall
   one. */
/* No sunken plate around this one example (Phase 5 batch 10,
   post-Phase-5 straggler) — .component-stub-example's own base
   border/background/padding (above) is a generic "recessed tray"
   treatment every other example on this page genuinely needs (raw
   buttons/checkboxes/pills with no visual boundary of their own would
   otherwise read as loose page content, not a demo). The real
   .card-filter__panel already carries its own real border, background,
   and box-shadow (search.css) — a genuine floating-card look with its
   own visual boundary — so wrapping it in a second, unrelated surface
   here incorrectly implied that outer plate was part of the component
   itself. Reset to nothing; position:relative/overflow:auto from the
   base rule are left alone (still needed for this demo's own sideways-
   safety, per the comment on .component-stub-example above), only the
   plate's own three visual properties are removed. */
.component-stub-example--card-filter {
  height: auto;
  border: none;
  background: none;
  padding: 0;
}

.component-stub-example--card-filter .card-filter {
  position: static;
}

.component-stub-example--card-filter .card-filter__panel {
  height: auto;
  overflow: visible;
}

.component-stub-example--card-filter .card-filter__scroll {
  overflow: visible;
}

/* display: flex + width: fit-content + margin-left: auto, not the
   original inline-flex (Phase 5 batch 7) — right-aligns this button to
   its own example, per the long-standing Phase 5 queue item (Section
   74: "should be right-aligned to its own example, currently left-
   aligned, flush with the example box's own left edge"). Confirmed
   before fixing: .component-stub-example has no width of its own
   narrower than .component-stub (its parent), so this button's own
   right edge, once pulled right, lands flush with the example's own
   right border — not a separate alignment target needing its own
   value. inline-flex couldn't be pulled right at all (inline-level
   boxes ignore margin-left:auto the way block-level ones don't); flex
   (block-level) + fit-content keeps the button sized to its own text
   instead of stretching full-width, the same pairing search.css's own
   .btn-collapse-all (Phase 5 batch 7) uses for the identical reason. */
.component-stub-copy-btn {
  display: flex;
  width: fit-content;
  margin-left: auto;
  align-items: center;
  margin-top: var(--space-3);
  padding: 0;
  border: none;
  background: none;
  font-family: var(--font-ui);
  font-size: var(--ui-caption-size);
  color: var(--color-muted);
  cursor: pointer;
}

.component-stub-copy-btn:hover,
.component-stub-copy-btn:focus-visible {
  color: var(--color-ink);
  text-decoration: underline;
}

/* ---- Compound components batch 2 (Prompt 3) ---- */

/* Multiple small instances of one component shown together (Tag-
   confidence's tiers, Tag-source's shapes) — a plain wrapping flex row,
   not a grid, since these are label-width content, not a fixed-size
   grid of cells. */
.component-stub-example-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

/* Summary pills demo only (Phase 5 batch 5) — .region-tier-summary-pill
   carries a real margin-top: var(--space-2) in its own production
   context (search.css), needed there to space it below whatever renders
   above it inside .region-tier-pills. Confirmed live as the actual,
   sole cause of a real, unintentional ~4px vertical shift against its
   two .dp-blanket-pill row-mates here — not differing line-height,
   padding, or a font/icon baseline mismatch (all three pills share the
   exact same font-size/padding/line-height); a plain A/B test (zeroing
   just this pill's own margin-top) snapped all three to pixel-identical
   top/bottom edges. align-items: center on the row above centers each
   item by its own margin box, so this one item's extra top-only margin
   reads as "lower," not "taller." This demo row has its own real gap
   (var(--space-4)) already providing separation, so the production
   margin serves no purpose here — reset to 0, scoped to this one real
   demo instance rather than touching the shared class every other real
   consumer of .region-tier-summary-pill still needs it for. */
#demo-pills-wrap .region-tier-summary-pill {
  margin-top: 0;
}

/* Card-datapoint's three examples, stacked in a single column (Phase 5
   batch 10, post-Phase-5 straggler) — matching this component's real
   production layout on results.html exactly, where 16 real instances
   render one after another in a single content column, never side by
   side. Previously a responsive 2-3 column grid (Phase 5 batch 5, see
   git history) — that side-by-side arrangement was this section's own
   original spec at build time (Section 77), not an oversight, but it
   meant this demo showed a layout the real product never actually
   uses. The grid version's own narrow-container overflow bug (a hard
   340px column-track floor genuinely overflowing a real narrow phone
   width) was later fixed properly at the time (Phase 5 batch 5, item
   3 — a `@container` query on `.card-datapoint` itself), not left
   broken; this isn't a re-fix of that bug, it's a different, later
   decision to stop using the side-by-side layout at all. A plain
   single-column flex stack needs no responsive formula of its own —
   at any container width, one card per row is correct, so there's
   nothing left for a breakpoint or auto-fit/auto-fill grid to decide. */
.component-stub-example-cards {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* Citation modal — the real component is normally position:fixed, a
   full-viewport overlay (modal-citation.css) attached straight to
   <body> by its own real JS (modal-citation.js's buildModal()). Not
   driven by that real JS here — clicking a real citation isn't a
   meaningful interaction on this documentation page (that section's
   own copy explains why) — so it's shown as a static markup replica
   instead, reusing the exact same real CSS classes for authentic
   styling, with position overridden back to a normal in-flow box
   constrained to this page's own content-column width instead of the
   viewport. (Search modal — Filter card's own sub-part — used to get
   the identical static-replica treatment here too, but that's been
   reversed: Reference doc, Section 80 — its real narrow-viewport
   trigger is now left genuinely live instead of faked, so this rule no
   longer needs to cover it.) */
.component-stub-example .modal-citation {
  position: static;
  transform: none;
  width: 100%;
  max-width: 100%;
  inset: auto;
  /* The real rule is position:fixed with top/right/bottom offsets that
     become inert once overridden to static — with no explicit height of
     its own, the modal would just shrink-wrap to its tallest child's
     natural content height instead (the citation image alone can run
     well past 85vh), and .modal-citation-body's own flex:1 wouldn't
     have a real height to fill. 100% fills the wrapper's own explicit
     height (.component-stub-example--modal-citation below) instead, so
     the real internal flex layout (fixed topbar, growing/scrolling
     body, fixed bottom bar) works the same way it does in its real
     fixed-viewport context. */
  height: 100%;
}

.component-stub-example--modal-citation {
  height: 480px;
  padding: 0;
  overflow: hidden;
}

/* A plain, visible note distinguishing the two "shown pre-opened"
   examples above from every genuinely-interactive example elsewhere on
   this page — sits right above the example box, not buried in the copy
   paragraph, since it's a real caveat about what the demo can and can't
   do, not incidental description. */
.component-stub-static-note {
  font-family: var(--font-ui);
  font-size: var(--ui-caption-size);
  font-style: italic;
  color: var(--color-faint);
  margin: 0 0 var(--space-3);
}

/* ---- Atomic elements + icon gallery (Prompt 4) ---- */

/* Groups several button/pill treatments inside one shared example box
   (Buttons, Summary pills) — each group gets its own small label above
   its own .component-stub-example-row, stacked with real breathing
   room between groups so "these four rows are four different
   treatments" reads clearly, not as one undifferentiated row. */
.component-stub-example-group-label {
  font-family: var(--font-ui);
  font-size: var(--ui-caption-size);
  font-weight: var(--w-medium);
  color: var(--color-muted);
  margin: var(--space-5) 0 var(--space-2);
}

.component-stub-example-group-label:first-child {
  margin-top: 0;
}

/* Icon gallery — a plain reference grid, not a demo (this section's own
   copy explains why it has no Copy HTML button). Same auto-fill
   responsive-column formula as every other grid on this page, floored
   low (88px) since each cell is just one small glyph plus a short
   filename caption, not full text content. */
.icon-gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: var(--space-4);
}

.icon-gallery-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
}

.icon-gallery-glyph {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--space-7);
  height: var(--space-7);
  color: var(--color-ink-secondary);
}

.icon-gallery-glyph svg {
  width: 100%;
  height: 100%;
}

/* SF Mono caption — same raw-identifier treatment as
   .component-stub-subtitle/.swatch-hex above, just smaller (a filename
   under a small glyph, not a section-level subtitle). */
.icon-gallery-name {
  font-family: 'SF Mono', 'Consolas', monospace;
  font-size: 0.7rem;
  color: var(--color-faint);
  word-break: break-word;
}
