From 43da62d30d46e12381c589e07f43577e1383fcc6 Mon Sep 17 00:00:00 2001 From: Thomas Stegemann Date: Mon, 8 Jun 2026 22:45:36 +0200 Subject: [PATCH 1/2] revert: drop reading-mode toggle from docs template (browser-native is enough) --- .docfx/templates/bowire/layout/_master.tmpl | 36 +-------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/.docfx/templates/bowire/layout/_master.tmpl b/.docfx/templates/bowire/layout/_master.tmpl index eaf18eb..85727cf 100644 --- a/.docfx/templates/bowire/layout/_master.tmpl +++ b/.docfx/templates/bowire/layout/_master.tmpl @@ -39,11 +39,6 @@ var el = document.documentElement; el.setAttribute('data-bs-theme', resolved); el.setAttribute('data-theme', mode); - // Reading mode (#119) — same key the marketing site uses - // so the choice persists across site ↔ docs ↔ api-docs. - if (localStorage.getItem('bowire_reading_mode') === '1') { - el.setAttribute('data-reading-mode', '1'); - } })(); @@ -316,9 +311,6 @@ localStorage('theme') key the marketing site uses so the choice carries across site ↔ docs. Icon is injected by the inline script below. ----------------------------}} - @@ -1248,32 +1240,6 @@ - - + {{/redirect_url}} From 5d629106433343f473534343d9b141aab20bc2bc Mon Sep 17 00:00:00 2001 From: Thomas Stegemann Date: Mon, 8 Jun 2026 22:45:47 +0200 Subject: [PATCH 2/2] revert: drop reading-mode CSS from docs template (browser-native is enough) --- .docfx/templates/bowire/public/main.css | 4124 +++++++++++------------ 1 file changed, 2030 insertions(+), 2094 deletions(-) diff --git a/.docfx/templates/bowire/public/main.css b/.docfx/templates/bowire/public/main.css index 0cf5a4f..eb5abcd 100644 --- a/.docfx/templates/bowire/public/main.css +++ b/.docfx/templates/bowire/public/main.css @@ -1,2094 +1,2030 @@ -/* - * Bowire docfx theme — visual parity with the Jekyll marketing site - * (../../site/). Single source of truth for the brand palette is - * src/Kuestenlogik.Bowire/wwwroot/bowire.css:9-25 — values must stay in sync. - * - * The template chain in docs/docfx.json is: - * ["default", "modern", "templates/bowire"] - * - * Modern still ships docfx.min.css for Bootstrap 5 + the article-content - * styling. This file loads AFTER it (see _master.tmpl) and overrides: - * - * 1. Bootstrap variables (--bs-*) so the body bg, links, primary - * colour and font stack switch to Bowire brand - * 2. The .bowire-docs-* classes from our own master template (header, - * footer, content shell) - * 3. A handful of docfx-internal selectors (.toc, .affix, .contribution, - * pre code, .navbar etc.) so the inherited Bootstrap shell looks - * like the Bowire marketing site - * - * Theme switching is driven by the same `theme` localStorage key the - * marketing site writes — see _master.tmpl's inline head script. - */ - -/* ============================================================ - Bowire brand palette - ============================================================ */ -:root { - --bowire-accent: #6366f1; - --bowire-accent-hover: #818cf8; - --bowire-accent-rgb: 99, 102, 241; - --bowire-accent-light: #4f46e5; - --bowire-success: #10b981; - --bowire-warning: #fbbf24; - --bowire-danger: #ef4444; -} - -/* ============================================================ - Bootstrap 5 variable overrides — dark - ============================================================ */ -:root[data-bs-theme="dark"] { - --bs-body-bg: #0f0f17; - --bs-body-color: #e8e8f0; - --bs-secondary-bg: #161621; - --bs-tertiary-bg: #1a1a2e; - --bs-secondary-bg-rgb: 22, 22, 33; - --bs-tertiary-bg-rgb: 26, 26, 46; - - --bs-border-color: #2a2a3d; - --bs-border-color-translucent: rgba(232, 232, 240, 0.1); - - --bs-primary: var(--bowire-accent); - --bs-primary-rgb: var(--bowire-accent-rgb); - --bs-link-color: var(--bowire-accent); - --bs-link-color-rgb: var(--bowire-accent-rgb); - --bs-link-hover-color: var(--bowire-accent-hover); - --bs-link-hover-color-rgb: 129, 140, 248; - - --bs-code-color: var(--bowire-accent-hover); - - --bs-emphasis-color: #e8e8f0; - --bs-emphasis-color-rgb: 232, 232, 240; - --bs-secondary-color: #9898b0; - --bs-tertiary-color: #6a6a82; - --bs-heading-color: #e8e8f0; - - --bs-body-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; - --bs-font-monospace: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; -} - -/* ============================================================ - Bootstrap 5 variable overrides — light - ============================================================ */ -:root[data-bs-theme="light"] { - --bs-body-bg: #fafaff; - --bs-body-color: #1a1a2e; - --bs-secondary-bg: #f4f4fa; - --bs-tertiary-bg: #eeeef0; - --bs-secondary-bg-rgb: 244, 244, 250; - --bs-tertiary-bg-rgb: 238, 238, 240; - - --bs-border-color: #e1e1ee; - --bs-border-color-translucent: rgba(26, 26, 46, 0.1); - - --bs-primary: var(--bowire-accent-light); - --bs-primary-rgb: 79, 70, 229; - --bs-link-color: var(--bowire-accent-light); - --bs-link-color-rgb: 79, 70, 229; - --bs-link-hover-color: var(--bowire-accent); - - --bs-code-color: var(--bowire-accent-light); - - --bs-emphasis-color: #0a0a1a; - --bs-secondary-color: #5a5a72; - --bs-tertiary-color: #8a8aa0; - --bs-heading-color: #1a1a2e; - - --bs-body-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; - --bs-font-monospace: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; -} - -/* Smooth font rendering on both themes */ -body.bowire-docs { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - margin: 0; - /* Reserve room for the fixed header */ - padding-top: 64px; -} - -/* ============================================================ - Bowire header — fixed top bar mirroring the marketing site - ============================================================ */ -/* Using body.bowire-docs prefix to beat docfx.min.css's default - `header { position: sticky; display: flex; ... }` rule that otherwise - wins on equal-specificity and leaves our header non-fixed at y=64. */ -body.bowire-docs .bowire-docs-header { - /* Mirror site/_includes/header.html behaviour exactly: header is - transparent on page-top and turns into a translucent solid bar - after the first 20px of scroll. */ - position: fixed !important; - top: 0 !important; - left: 0; - right: 0; - width: 100%; - z-index: 1030; - height: 64px; - display: block; - background: transparent; - backdrop-filter: none; - -webkit-backdrop-filter: none; - border-bottom: 1px solid transparent; - transition: background 0.3s, border-color 0.3s, backdrop-filter 0.3s, -webkit-backdrop-filter 0.3s; - font-family: var(--bs-body-font-family); -} -body.bowire-docs .bowire-docs-header.scrolled { - background: rgba(15, 15, 23, 0.9) !important; - backdrop-filter: blur(12px) !important; - -webkit-backdrop-filter: blur(12px) !important; - border-bottom-color: var(--bs-border-color) !important; -} -:root[data-bs-theme="light"] body.bowire-docs .bowire-docs-header.scrolled { - background: rgba(250, 250, 255, 0.9) !important; -} - -.bowire-docs-header-inner { - /* Mirror site/_includes/header.html's three-zone grid exactly: - logo left, nav centred, actions right. 1fr-auto-1fr keeps the - nav horizontally centred even when logo and actions differ in - width — matching the marketing header pixel-for-pixel avoids a - layout jump on site ↔ docs transitions. */ - max-width: 1120px; - margin: 0 auto; - padding: 0 24px; - display: grid; - grid-template-columns: 1fr auto 1fr; - align-items: center; - gap: 24px; - height: 100%; -} -.bowire-docs-header-actions { - justify-self: end; -} - -.bowire-docs-logo { - /* Mirror site .logo — inline-flex + justify-self:start so the - click area hugs the mark + wordmark instead of stretching to - fill the 1fr grid column the header layout puts it in. */ - display: inline-flex; - justify-self: start; - align-items: center; - gap: 8px; - font-weight: 700; - font-size: 1.125rem; - color: var(--bs-emphasis-color); - text-decoration: none; - transition: color 0.15s; -} -.bowire-docs-logo:hover { - color: var(--bowire-accent); -} -.bowire-docs-logo-mark { - /* Tile logo (1:1) — same 28px sizing as site/_includes/header.html. - Color follows currentColor so it flips with theme via the parent - link's color (var(--bs-emphasis-color)). */ - width: 28px; - height: 28px; - display: block; - color: inherit; - flex-shrink: 0; -} -/* Hover lifts the brand mark to accent colour while the wordmark - next to it stays on its link colour. */ -.bowire-docs-logo:hover .bowire-docs-logo-mark { - color: var(--bowire-accent); -} - -.bowire-docs-nav { - display: flex; - align-items: center; - gap: 28px; - /* Mirror the marketing site's 3px baseline nudge so smaller nav - text aligns with the bigger wordmark next to the logo. */ - margin-top: 3px; -} -.bowire-docs-nav a { - color: var(--bs-secondary-color); - font-size: 0.875rem; - font-weight: 500; - text-decoration: none; - transition: color 0.15s; -} -.bowire-docs-nav a:hover { - color: var(--bowire-accent); -} -/* Active section (current page) — distinct from hover so the user can - tell "I am here" vs "I can go here". Lifts to emphasis colour + - semibold while hover stays on accent. */ -.bowire-docs-nav a.is-active { - color: var(--bs-emphasis-color); - font-weight: 600; -} - -.bowire-docs-header-actions { - display: flex; - align-items: center; - gap: 12px; -} - -/* Search form in the header — replaces the modern template's navbar - search. docfx.min.js looks up #search and #search-query by id. */ -/* ============================================================ - Pagefind search overlay — shared with the Jekyll marketing site. - Trigger button sits in the header actions next to home / theme / - github and opens a centred overlay with the PagefindUI widget. - ============================================================ */ -.bowire-search-trigger { - width: 32px; - height: 32px; - padding: 0; - background: transparent; - border: none; - color: var(--bs-secondary-color); - cursor: pointer; - display: inline-flex; - align-items: center; - justify-content: center; - transition: color 0.15s, opacity 0.15s; -} -.bowire-search-trigger:hover { - color: var(--bowire-accent); -} -.bowire-search-trigger:focus-visible { - outline: 2px solid var(--bowire-accent); - outline-offset: 2px; - border-radius: 4px; -} -/* Disabled state when the Pagefind index isn't available — typically - hit during local-only docfx serve runs where the post-build pagefind - step hasn't run. Greyed out + non-interactive so clicks don't fire - into uninitialised PagefindUI and surface uncaught exceptions. */ -.bowire-search-trigger[disabled] { - opacity: 0.35; - cursor: not-allowed; - pointer-events: none; -} - -.bowire-search-overlay { - position: fixed; - inset: 0; - z-index: 2000; - display: flex; - align-items: flex-start; - justify-content: center; - padding-top: min(12vh, 120px); - background: rgba(15, 15, 23, 0.55); - backdrop-filter: blur(6px); - -webkit-backdrop-filter: blur(6px); - opacity: 0; - pointer-events: none; - transition: opacity 0.15s ease; -} -:root[data-bs-theme="light"] .bowire-search-overlay { - background: rgba(200, 200, 220, 0.55); -} -.bowire-search-overlay.is-open { - opacity: 1; - pointer-events: auto; -} -.bowire-search-overlay-panel { - width: min(680px, calc(100% - 48px)); - max-height: 80vh; - display: flex; - flex-direction: column; - overflow: hidden; - background: var(--bs-secondary-bg); - border: 1px solid var(--bs-border-color); - border-radius: 12px; - padding: 0; - box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35); - transform: translateY(-8px); - transition: transform 0.2s ease; -} -.bowire-search-overlay #search { - display: flex; - flex-direction: column; - flex: 1 1 auto; - min-height: 0; -} -.bowire-search-overlay .pagefind-ui { - display: flex; - flex-direction: column; - flex: 1 1 auto; - min-height: 0; -} -.bowire-search-overlay .pagefind-ui__form { - display: flex; - flex-direction: column; - flex: 1 1 auto; - min-height: 0; - padding: 20px; - /* Form is the "header zone" — same tertiary bg as the footer hint - band so the input + result-count read as one capsule, with the - results drawer below it visually distinct (secondary bg). */ - background: var(--bs-tertiary-bg); -} -.bowire-search-overlay .pagefind-ui__search-input { - flex: 0 0 auto; -} -.bowire-search-overlay .pagefind-ui__drawer { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - margin: 16px -20px -20px; - padding: 16px 20px 20px; - background: var(--bs-secondary-bg); - border-top: 1px solid var(--bs-border-color); - scrollbar-width: thin; - scrollbar-color: var(--bs-border-color) transparent; -} -.bowire-search-overlay .pagefind-ui__drawer::-webkit-scrollbar { width: 10px; } -.bowire-search-overlay .pagefind-ui__drawer::-webkit-scrollbar-track { background: transparent; } -.bowire-search-overlay .pagefind-ui__drawer::-webkit-scrollbar-thumb { - background: var(--bs-border-color); - border-radius: 8px; - border: 2px solid transparent; - background-clip: padding-box; -} -.bowire-search-overlay.is-open .bowire-search-overlay-panel { - transform: translateY(0); -} - -/* Theme the PagefindUI widget to the Bowire brand palette. Bind to - data-bs-theme so dark/light mode switch picks up synchronously with - the rest of the docs. Attribute selectors (0,2,0) beat Pagefind's - default :root declaration (0,1,0). */ -html[data-bs-theme="dark"], -html[data-bs-theme="light"] { - --pagefind-ui-scale: 1; - --pagefind-ui-primary: var(--bowire-accent); - --pagefind-ui-text: var(--bs-emphasis-color); - --pagefind-ui-background: var(--bs-secondary-bg); - --pagefind-ui-border: var(--bs-border-color); - --pagefind-ui-tag: var(--bs-tertiary-bg); - --pagefind-ui-border-width: 1px; - --pagefind-ui-border-radius: 10px; - --pagefind-ui-image-border-radius: 6px; - --pagefind-ui-image-box-ratio: 3 / 2; - --pagefind-ui-font: inherit; -} - -.pagefind-ui { - padding-top: 0 !important; -} -.pagefind-ui__drawer { - gap: 24px !important; -} -.pagefind-ui__results-area { - margin-top: 8px !important; -} -/* Result count — relocated by JS from inside the drawer to between - the search input and the drawer (still inside the form so it - inherits the tertiary "header" bg). Smaller font than the previous - in-drawer placement so it reads as a sub-line of the input area - rather than a result row. */ -.pagefind-ui__message { - color: var(--bs-secondary-color) !important; - font-size: 0.75rem !important; - font-weight: 500 !important; - padding: 8px 0 0 !important; - margin: 0 !important; - height: auto !important; -} -.pagefind-ui__result { - padding: 18px 0 20px !important; - border-top: 1px solid var(--bs-border-color) !important; - cursor: pointer; -} -/* The drawer already carries a border-top above the first result — - skip the per-result rule for the first item to avoid the - double-line stack. */ -.pagefind-ui__result:first-child { - border-top: none !important; - padding-top: 0 !important; -} -.pagefind-ui__result-title { - font-size: 1.0625rem !important; - font-weight: 600 !important; - line-height: 1.35 !important; - margin-bottom: 4px !important; -} -.pagefind-ui__result-excerpt { - font-size: 0.9375rem !important; - color: var(--bs-secondary-color) !important; - line-height: 1.55 !important; -} -.pagefind-ui__result-tags { - margin-top: 10px !important; -} -.pagefind-ui__result-tag { - font-size: 0.75rem !important; - padding: 3px 8px !important; - color: var(--bs-secondary-color) !important; -} - -/* Pagefind-UI-specific selector overrides where --pagefind-ui-* doesn't - reach (focus ring, link hover, mark highlight). */ -.pagefind-ui__search-input { - color: var(--bs-emphasis-color) !important; - font-weight: 500 !important; - font-size: 0.9375rem !important; - padding: 0 52px 0 44px !important; - height: 52px !important; - display: inline-flex !important; - align-items: center !important; - line-height: 1 !important; -} -.pagefind-ui__form::before { - top: 38px !important; - left: 34px !important; - width: 16px !important; - height: 16px !important; -} -.pagefind-ui__search-input::placeholder { - color: var(--bs-secondary-color) !important; - opacity: 0.6 !important; - font-weight: 400 !important; -} -.pagefind-ui__search-input:focus-visible { - outline: none !important; - border-color: var(--bowire-accent) !important; - box-shadow: 0 0 0 3px rgba(var(--bowire-accent-rgb), 0.15) !important; -} -/* Theme the overlay panel's scrollbar so dark mode doesn't paint a - bright browser-default track on top of the panel. */ -.bowire-search-overlay-panel { - scrollbar-width: thin; - scrollbar-color: var(--bs-border-color) transparent; -} -.bowire-search-overlay-panel::-webkit-scrollbar { - width: 10px; - height: 10px; -} -.bowire-search-overlay-panel::-webkit-scrollbar-track { - background: transparent; -} -.bowire-search-overlay-panel::-webkit-scrollbar-thumb { - background: var(--bs-border-color); - border-radius: 8px; - border: 2px solid transparent; - background-clip: padding-box; -} -.bowire-search-overlay-panel::-webkit-scrollbar-thumb:hover { - background: var(--bs-secondary-color); - background-clip: padding-box; -} -.pagefind-ui__result-link { - color: var(--bs-emphasis-color) !important; -} -.pagefind-ui__result-link:hover { - color: var(--bowire-accent) !important; -} -.pagefind-ui mark { - color: var(--bowire-accent); - background: rgba(var(--bowire-accent-rgb), 0.14); - padding: 0 2px; - border-radius: 3px; -} - -/* Arrow-key / hover highlight on the currently selected result. - Background tint + accent text colour only — no left-stripe, since - it would curve with the border-radius and read as comma-shaped. */ -.pagefind-ui__result.is-highlighted { - background: rgba(var(--bowire-accent-rgb), 0.08); - border-radius: 8px; - padding-left: 12px !important; - padding-right: 12px !important; - margin-left: -12px; - margin-right: -12px; -} -.pagefind-ui__result.is-highlighted .pagefind-ui__result-link { - color: var(--bowire-accent) !important; -} - -.bowire-search-hint { - flex: 0 0 auto; - padding: 14px 20px; - border-top: 1px solid var(--bs-border-color); - background: var(--bs-tertiary-bg); - color: var(--bs-secondary-color); - font-size: 0.75rem; - text-align: center; -} -.bowire-search-hint kbd { - display: inline-block; - min-width: 20px; - padding: 1px 5px; - margin: 0 2px; - background: var(--bs-tertiary-bg); - border: 1px solid var(--bs-border-color); - border-bottom-width: 2px; - border-radius: 4px; - font-family: var(--bs-body-font-family); - font-size: 0.6875rem; - color: var(--bs-emphasis-color); - line-height: 1.4; -} - -/* DocFX injects an anchorjs "#" link beside every heading that pops in - on hover. The id is already on the element itself, so the extra - glyph is visual noise — hide it everywhere. Direct deep-links via URL - fragment still work. */ -.anchorjs-link { - display: none !important; -} - -/* Form layout is set on .bowire-search-overlay .pagefind-ui__form - above — nothing more needed here. */ - -/* Overlay is a Suggest popup, capped at 5 results — no Load-More here. */ -.bowire-search-overlay .pagefind-ui__button { - display: none !important; -} - -/* "Load more results" — secondary button style matching the Bowire - docs buttons (neutral background, accent on hover). */ -.pagefind-ui__button { - background: var(--bs-tertiary-bg) !important; - color: var(--bs-emphasis-color) !important; - border: 1px solid var(--bs-border-color) !important; - border-radius: 8px !important; - font-weight: 600 !important; - transition: background 0.2s, border-color 0.2s, color 0.2s, transform 0.2s !important; - cursor: pointer !important; -} -.pagefind-ui__button:hover { - background: var(--bs-secondary-bg) !important; - border-color: var(--bowire-accent) !important; - color: var(--bowire-accent) !important; - transform: translateY(-1px); -} -.pagefind-ui__button:focus-visible { - outline: 2px solid var(--bowire-accent) !important; - outline-offset: 2px; -} - -/* Clear-query button — circular 28×28 × icon button. Mirrors the - marketing site's styling exactly so site and docs share the same - affordance in the search popout. */ -.pagefind-ui__search-clear { - position: absolute !important; - width: 28px !important; - height: 28px !important; - padding: 0 !important; - /* 20 px form padding-top + (52 px input - 28 px button) / 2 = 32 px */ - top: 32px !important; - /* Inside the input's right edge — 28 px from form-right leaves an - 8-px gap between button and input border. */ - right: 28px !important; - transform: none !important; - /* Rounded square to match the input's 10 px radius + the rest of - the button system. */ - border-radius: 8px !important; - background: var(--bs-border-color) !important; - color: transparent !important; - border: none !important; - font-size: 0 !important; - line-height: 0 !important; - display: flex !important; - align-items: center !important; - justify-content: center !important; - cursor: pointer !important; - transition: background 0.15s, color 0.15s, transform 0.15s; -} -.pagefind-ui__search-clear::before { - content: ""; - display: block; - width: 10px; - height: 10px; - background-color: var(--bs-emphasis-color); - -webkit-mask-image: url("data:image/svg+xml;utf8,"); - mask-image: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-size: contain; - mask-size: contain; - transition: background-color 0.15s; -} -.pagefind-ui__search-clear:hover { - background: var(--bowire-accent) !important; - transform: scale(1.05) !important; -} -.pagefind-ui__search-clear:hover::before { - background-color: #fff; -} -.pagefind-ui__search-clear:focus-visible { - outline: 2px solid var(--bowire-accent) !important; - outline-offset: 2px; -} -.bowire-docs-nav-home, -.bowire-docs-nav-github { - display: inline-flex; - align-items: center; - color: var(--bs-secondary-color); - text-decoration: none; - transition: color 0.2s; -} -.bowire-docs-nav-home:hover, -.bowire-docs-nav-github:hover { - color: var(--bowire-accent); -} -.bowire-docs-theme-toggle { - /* Match site `.theme-toggle` exactly: 32×32 hitbox, 16×16 icon - centred inside. Without this the button was only as big as its - svg child (16×16), making the header action row visually shorter - than the marketing site's. */ - width: 32px; - height: 32px; - padding: 0; - background: transparent; - border: none; - display: inline-flex; - align-items: center; - justify-content: center; - color: var(--bs-secondary-color); - cursor: pointer; - transition: color 0.2s; -} -.bowire-docs-theme-toggle svg { - width: 16px; - height: 16px; -} -.bowire-docs-theme-toggle:hover, -.bowire-docs-theme-toggle:focus { - color: var(--bowire-accent); - outline: none; -} -.bowire-docs-theme-toggle:focus-visible { - outline: 2px solid var(--bowire-accent); - outline-offset: 2px; - border-radius: 4px; -} - -/* ============================================================ - Main content shell — same Bootstrap container as modern, but - we make sure it doesn't slide under the fixed header and we - tighten the max-width so it visually matches the marketing - site's 1120px column. - ============================================================ */ -main.bowire-docs-main-shell { - /* Match site/assets/css/style.css `.container` exactly: - max-width 1120px + 24px horizontal padding. Bootstrap's - container-xxl defaults to 1320px with 12px padding, which - made the docs content column visibly wider than the marketing - site's hero/cards. Force identical outer box + padding here - so the jump site ↔ docs feels seamless. */ - max-width: 1120px; - padding-left: 24px; - padding-right: 24px; - padding-top: 24px; - /* Neutralise Bootstrap's gutter system inside the docs shell. - `.container-xxl` and Bootstrap's row/col classes pull - --bs-gutter-x (default 1.5rem) into both negative row margins - and column padding — that's where the stray 12px on the right - of the affix sidebar comes from, leaving the "In this article" - column ending visibly inside the header's GitHub icon column. - Setting the gutter to 0 here keeps every nested .row + .col - flush with main's own 24px padding edge, so the affix lines up - with the header's right edge pixel-for-pixel. */ - --bs-gutter-x: 0; -} - - -/* === Right rail (article tools + section-nav) ==================== - Two stacked pills on the right edge of the viewport: - • .docs-rail-tools — top pill, hosts per-article tool buttons - (currently just the "On this page" outline toggle; future tools - — share, copy-link, edit, mark-read — would land alongside). - • .docs-section-nav — bottom pill, scrollspy dots built at - runtime from article h2 elements (one per section). - Both pills share visual treatment (translucent + blur, pill shape, - thin border) so the rail reads as a coherent vertical band; the - parent .docs-rail keeps them centred and stacks them with a small - gap so each can scale independently. Hidden on mobile (< 768 px). - ============================================================ */ -.docs-rail { - position: fixed; - right: 18px; - top: 50%; - transform: translateY(-50%); - z-index: 1015; - display: flex; - flex-direction: column; - align-items: flex-end; - gap: 12px; - pointer-events: none; /* gaps between pills don't block clicks */ -} -/* Explicit because `display: flex` above overrides the user-agent - default `[hidden] { display: none }` and the rail-hide JS uses - the [hidden] attribute. */ -.docs-rail[hidden] { display: none; } -.docs-rail > * { - pointer-events: auto; -} - -/* Tools pill — small per-article-action surface. Style matches the - section-nav pill so the two read as siblings. */ -.docs-rail-tools { - display: flex; - flex-direction: column; - gap: 4px; - padding: 6px; - background: rgba(15, 15, 23, 0.55); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - border-radius: 999px; - border: 1px solid var(--bs-border-color); -} -:root[data-bs-theme="light"] .docs-rail-tools { - background: rgba(250, 250, 255, 0.7); -} -.docs-rail-tool { - width: 24px; - height: 24px; - display: flex; - align-items: center; - justify-content: center; - border: none; - background: transparent; - color: var(--bs-secondary-color); - cursor: pointer; - border-radius: 50%; - padding: 0; - transition: color 0.15s, background 0.15s; -} -.docs-rail-tool:hover, -.docs-rail-tool:focus-visible { - color: var(--bs-link-color); - outline: none; -} -.docs-rail-tool[aria-expanded="true"] { - color: var(--bs-link-color); -} -.docs-rail-tool svg { display: block; } -/* Explicit because `display: flex` on the parent + `display: inline- - flex` here override the user-agent default `[hidden]{display:none}`, - so the JS that hides empty triggers needs a CSS hand. */ -.docs-rail-tools[hidden], -.docs-rail-tool[hidden] { - display: none; -} - -/* Section-nav pill — sits inside the rail, no longer fixed-positioned - itself (the parent .docs-rail handles viewport anchoring). */ -.docs-section-nav { - position: static; - transform: none; - right: auto; - top: auto; - display: flex; - flex-direction: column; - gap: 6px; - padding: 8px 6px; - background: rgba(15, 15, 23, 0.55); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - border-radius: 999px; - border: 1px solid var(--bs-border-color); -} -:root[data-bs-theme="light"] .docs-section-nav { - background: rgba(250, 250, 255, 0.7); -} -.docs-section-nav[hidden] { display: none; } - -.docs-section-nav-dot { - position: relative; - display: flex; - align-items: center; - justify-content: center; - width: 24px; - height: 24px; - border-radius: 50%; - cursor: pointer; - background: transparent; - border: none; - padding: 0; - text-decoration: none; - color: inherit; -} -.docs-section-nav-dot::before { - content: ''; - width: 8px; - height: 8px; - border-radius: 50%; - background: var(--bs-secondary-color); - opacity: 0.4; - transition: opacity 0.15s, transform 0.15s, background 0.15s; -} -.docs-section-nav-dot:hover::before, -.docs-section-nav-dot:focus-visible::before { - opacity: 0.85; - transform: scale(1.25); -} -.docs-section-nav-dot.is-active::before { - background: var(--bs-link-color); - opacity: 1; - transform: scale(1.35); -} -.docs-section-nav-dot:focus-visible { - outline: 2px solid var(--bs-link-color); - outline-offset: 2px; -} - -/* Tooltip-style label to the left of each dot — only visible on - hover/focus so the pill stays minimal at rest. */ -.docs-section-nav-dot-label { - position: absolute; - right: calc(100% + 8px); - top: 50%; - transform: translateY(-50%) translateX(4px); - white-space: nowrap; - padding: 4px 10px; - background: var(--bs-body-bg); - border: 1px solid var(--bs-border-color); - border-radius: 6px; - font-size: 0.8125rem; - color: var(--bs-body-color); - opacity: 0; - pointer-events: none; - transition: opacity 0.15s, transform 0.15s; - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18); -} -.docs-section-nav-dot:hover .docs-section-nav-dot-label, -.docs-section-nav-dot:focus-visible .docs-section-nav-dot-label { - opacity: 1; - transform: translateY(-50%) translateX(0); -} - -/* Gap marker — inserted between two non-adjacent picked dots when the - article has more headings than the pill can show (sampled mode). - Two stacked micro-dots in the same dot-language as the surrounding - pill so the strip reads as "… some entries hidden here", without - adding clickable noise. Use the Sections / Outline overlay to find - the skipped headings. */ -.docs-section-nav-gap { - width: 24px; - height: 10px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 2px; - pointer-events: none; -} -.docs-section-nav-gap::before, -.docs-section-nav-gap::after { - content: ''; - width: 2px; - height: 2px; - border-radius: 50%; - background: var(--bs-secondary-color); - opacity: 0.35; -} - -@media (max-width: 768px) { - .docs-rail { display: none; } -} - -/* === "On this page" outline overlay ============================== - Modal popup analog to the Pagefind .bowire-search-overlay — - centred panel with translucent backdrop, opened from the right- - rail tool button. Same backdrop colour, same panel chrome, same - slide-in animation so the docs site has one cohesive overlay - idiom across search and outline. The overlay is purely transient: - no localStorage, opens fresh, dismisses on backdrop / Esc / link - click inside the list. ====================================== */ -.bowire-docs-overlay { - position: fixed; - inset: 0; - z-index: 1100; - display: flex; - align-items: flex-start; - justify-content: center; - padding-top: min(12vh, 120px); - background: rgba(15, 15, 23, 0.55); - backdrop-filter: blur(6px); - -webkit-backdrop-filter: blur(6px); - opacity: 0; - pointer-events: none; - transition: opacity 0.15s ease; -} -:root[data-bs-theme="light"] .bowire-docs-overlay { - background: rgba(200, 200, 220, 0.55); -} -.bowire-docs-overlay.is-open { - opacity: 1; - pointer-events: auto; -} -.bowire-docs-overlay-panel { - width: min(560px, calc(100% - 48px)); - max-height: 80vh; - display: flex; - flex-direction: column; - overflow: hidden; - background: var(--bs-secondary-bg); - border: 1px solid var(--bs-border-color); - border-radius: 12px; - padding: 0; - box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35); - transform: translateY(-8px); - transition: transform 0.2s ease; -} -.bowire-docs-overlay.is-open .bowire-docs-overlay-panel { - transform: translateY(0); -} -.bowire-docs-overlay-title { - flex-shrink: 0; - font-size: 0.85em; - text-transform: uppercase; - letter-spacing: 0.06em; - color: var(--bs-secondary-color); - margin: 0; - font-weight: 600; - padding: 16px 20px; - /* Header capsule — same tertiary bg as the search overlay's input - zone, with a 1 px separator below before the link list (which - sits on the lighter secondary bg). Reads as a clear "title + - content + footer" three-band layout. */ - background: var(--bs-tertiary-bg); - border-bottom: 1px solid var(--bs-border-color); -} -.bowire-docs-overlay nav#affix { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - overflow-x: hidden; - background: var(--bs-secondary-bg); - scrollbar-width: thin; - scrollbar-color: var(--bs-border-color) transparent; - margin: 0; - padding: 16px 20px; -} -.bowire-docs-overlay nav#affix::-webkit-scrollbar { width: 6px; } -.bowire-docs-overlay nav#affix::-webkit-scrollbar-track { background: transparent; } -.bowire-docs-overlay nav#affix::-webkit-scrollbar-thumb { - background: var(--bs-border-color); - border-radius: 3px; -} -/* DocFX injects its own h5 inside the nav — hide it; our static - .bowire-docs-overlay-title above already labels the panel. */ -.bowire-docs-overlay nav#affix > h5 { - display: none; -} - -/* --- Tree styling for the article outline --- - DocFX's runtime renders a single flat