diff --git a/.gitignore b/.gitignore
index 84a7f19..62ffbc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
doc/html
.DS_Store
+node_modules
+.dev
diff --git a/boostlook-v3.css b/boostlook-v3.css
index 00479a8..3843fbd 100644
--- a/boostlook-v3.css
+++ b/boostlook-v3.css
@@ -127,7 +127,12 @@
* 6. Responsive Design - Mobile-first breakpoint variables
*/
-:root:has(.boostlook) {
+/* Core design tokens. Scoped to the .boostlook subtree (not the page root) so a
+ component island on a v3 site page cannot redefine the host page's tokens
+ (which caused the hero heading to shift). The :root:not(.v3) branch keeps them
+ page-level for full-page docs, whose html has no .v3. */
+:root:not(.v3):has(.boostlook),
+.boostlook {
/* General Variables - Core design tokens for all themes */
--bl-primary-color: rgb(255, 159, 0); /* Boost's signature orange color */
@@ -207,7 +212,7 @@
--colors-secondary-950: #000d14;
/* Atom One Dark Theme Colors */
- --atom-one-dark-bg: #282c34;
+ --atom-one-dark-bg: #1A1C29; /* code block surface — Figma 2.0 dark (= primary-850) */
--atom-one-dark-text: #FFFFFF;
--atom-one-dark-keyword: #c678dd;
--atom-one-dark-operator: #e06c75;
@@ -215,7 +220,7 @@
--atom-one-dark-class: #e6c07b;
/* Atom One Light Theme Colors */
- --atom-one-light-bg: #fafafa;
+ --atom-one-light-bg: #ffffff; /* code block surface — Figma 2.0 (#116-5) */
--atom-one-light-text: #050816;
--atom-one-light-keyword: #a626a4;
--atom-one-light-operator: #e45649;
@@ -426,7 +431,8 @@
/*----------------- New Look Responsive Desktop Start -----------------*/
@media (min-width: 768px) {
- :root:has(.boostlook) {
+ :root:not(.v3):has(.boostlook),
+ .boostlook {
/* Spacing — Metalab 2.0 (desktop) */
--spacing-xs: 0.125rem;
--spacing-s: 0.25rem;
@@ -489,15 +495,17 @@
--typography-line-height-4xl: var(--font-line-height-4xl);
/* Heading — Metalab 2.0 (desktop) */
- --typography-font-size-h1: var(--font-size-4xl);
- --typography-font-size-h2: var(--font-size-lg);
- --typography-font-size-h3: var(--font-size-md);
- --typography-font-size-h4: var(--font-size-sm);
+ --typography-font-size-h1: 3rem; /* 48px — Figma Title / 2XL */
+ --typography-font-size-h2: var(--font-size-xl); /* 24px — Figma Large */
+ --typography-font-size-h3: var(--font-size-md); /* 18px */
+ --typography-font-size-h4: var(--font-size-sm); /* 16px */
}
}
@media (min-width: 990px) {
- :root:has(.boostlook) {
+ /* Doc-layout widths, read by ancestors outside .boostlook, so they stay on
+ :root. Gated :not(.v3) so they don't land on a v3 site page. */
+ :root:not(.v3):has(.boostlook) {
--main-max-width-leftbar: 21.25rem;
--main-margin: 8.625rem;
}
@@ -517,8 +525,12 @@
* 2. Dark Theme (activated by html.dark class)
*/
-/* Light Theme (Default) Configuration */
-html:has(.boostlook) {
+/* Light Theme (Default) Configuration.
+ Defined on the .boostlook scope (not the page root) so a component island on
+ a v3 site page does not push these theme vars onto the host :root. The
+ :root:not(.v3) branch keeps them page-level for full-page docs. */
+:root:not(.v3):has(.boostlook),
+.boostlook {
color-scheme: light;
/*----------------- New Look Variables Start -----------------*/
--icon-anchor: var(--icon-anchor-light);
@@ -633,7 +645,7 @@ html:has(.boostlook) {
--surface-icons-icon-blue: var(--colors-secondary-600);
--surface-icons-icon-blue-light: var(--colors-secondary-200);
- --border-border-primary: var(--colors-primary-100);
+ --border-border-primary: rgba(5, 8, 22, 0.1); /* Figma 2.0 standard 1px border (light) */
--border-border-secondary: var(--colors-primary-150);
--border-border-tetriary: var(--colors-primary-300);
--border-border-quaternary: var(--colors-primary-600);
@@ -649,13 +661,15 @@ html:has(.boostlook) {
--surface-weak: var(--colors-primary-0);
--stroke-strong: rgba(5 8 22 / 0.25);
--stroke-mid: rgba(5 8 22 / 0.17);
- --stroke-weak: rgba(13 14 15 / 0.1);
+ --stroke-weak: rgba(5 8 22 / 0.1); /* Figma 2.0 standard 1px stroke (light) */
/*----------------- New Look Variables End -----------------*/
}
-/* Dark Theme Configuration */
-html.dark:has(.boostlook) {
+/* Dark Theme Configuration. Scoped like the light theme above so dark theme
+ vars land on the .boostlook subtree, not the host :root, on v3 site pages. */
+html.dark:not(.v3):has(.boostlook),
+html.dark .boostlook {
color-scheme: dark;
/*----------------- New Look Variables Dark Mode Start -----------------*/
--icon-anchor: var(--icon-anchor-dark);
@@ -769,7 +783,7 @@ html.dark:has(.boostlook) {
--surface-icons-icon-blue: var(--colors-secondary-400);
--surface-icons-icon-blue-light: var(--colors-secondary-700);
- --border-border-primary: var(--colors-primary-850);
+ --border-border-primary: rgba(247, 247, 248, 0.1); /* Figma 2.0 standard 1px border (dark) */
--border-border-secondary: var(--colors-primary-800);
--border-border-tetriary: var(--colors-primary-700);
--border-border-quaternary: var(--colors-primary-500);
@@ -785,15 +799,18 @@ html.dark:has(.boostlook) {
--surface-weak: var(--colors-primary-850);
--stroke-strong: rgba(247 247 248 / 0.21);
--stroke-mid: rgba(247 247 248 / 0.17);
- --stroke-weak: rgba(255 255 255 / 0.1);
+ --stroke-weak: rgba(247 247 248 / 0.1); /* Figma 2.0 standard 1px stroke (dark) */
/*----------------- New Look Variables Dark Mode Start -----------------*/
}
/*----------------- HTML Variables - End -----------------*/
-/* Override for Antora default styles */
-html:has(.boostlook) {
+/* Override for Antora default styles.
+ Gated :not(.v3): page-level html props (root font-size, height, scroll) must
+ not apply when .boostlook is only a component island on a v3 site page. Docs
+ render in an iframe whose html has no .v3, so they keep this. */
+html:not(.v3):has(.boostlook) {
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-size: 1rem;
@@ -1048,13 +1065,20 @@ html:has(.boostlook) {
}
/* Heading Sizes — Metalab 2.0 */
-/* h1: Display/Desktop/Medium/3XL */
+/* h1: Title / 2XL (48px desktop) */
.boostlook h1,
.boostlook .doc h1 {
font-size: var(--typography-font-size-h1, 2rem);
letter-spacing: -0.01em;
}
+/* Antora pins its page title via .doc>h1.page:first-child (0,3,1), which beats
+ .boostlook .doc h1 (0,2,1); restate the global h1 size at higher specificity
+ (0,4,1) so the title matches across Antora + AsciiDoctor. */
+.boostlook .doc > h1.page:first-child {
+ font-size: var(--typography-font-size-h1, 3rem);
+}
+
/* h2: Display/Desktop/Medium/Large */
.boostlook h2,
.boostlook .doc h2 {
@@ -1324,6 +1348,40 @@ html:has(.boostlook) {
margin-top: var(--padding-padding-md, 1rem);
}
+/* Markdown paragraphs — plain
siblings rendered by markdown (site
+ components, READMEs) that lack Antora's .paragraph wrapper, so the rule
+ above never matches them. Scoped :not(:has(.doc)) so Antora doc content
+ keeps its own structure-based spacing below. */
+/* The :not(...) guards are wrapped in :where() so they add no specificity:
+ this bare-markdown layer is a low baseline (.boostlook + element level) that
+ component rules (e.g. .boostlook.markdown-content ul) can override cleanly. */
+.boostlook:where(:not(:has(.doc))) p + p {
+ margin-top: var(--padding-padding-md, 1rem);
+}
+
+/* Markdown lists — bare
/ from markdown (site components, READMEs)
+ that lack Antora's .ulist/.olist wrappers. Tailwind's preflight strips the
+ markers, indent and margins on the site, and boostlook's Antora list rules
+ never match these, so restore them here. Scoped :where(:not(:has(.doc))) and
+ :where(:not([class])) so only bare markdown lists are touched, never Antora
+ or classed nav/tab lists, and with no added specificity. */
+.boostlook:where(:not(:has(.doc))) :is(ul, ol):where(:not([class])) {
+ margin: var(--padding-padding-md, 1rem) 0;
+ padding-left: var(--spacing-size-lg, 1.5rem);
+}
+.boostlook:where(:not(:has(.doc))) ul:where(:not([class])) {
+ list-style: disc;
+}
+.boostlook:where(:not(:has(.doc))) ol:where(:not([class])) {
+ list-style: decimal;
+}
+.boostlook:where(:not(:has(.doc))) :is(ul, ol):where(:not([class])) li + li {
+ margin-top: var(--padding-padding-3xs, 0.25rem);
+}
+.boostlook:where(:not(:has(.doc))) li > :is(ul, ol):where(:not([class])) {
+ margin: var(--padding-padding-3xs, 0.25rem) 0 0;
+}
+
.boostlook:not(:has(.doc)) .section > p + p,
.boostlook:not(:has(.doc)) .chapter > p + p,
.boostlook div.blockquote blockquote p + p,
@@ -1432,11 +1490,14 @@ div.source-docs-antora.boostlook:not(:has(.doc)):not(:has(>.boostlook)) > #conte
transition: color 0.3s ease;
}
-/* Content body links: underline per Figma (paragraphs and lists only) */
-.boostlook #content .doc .paragraph a:not(.anchor),
-.boostlook #content .doc .ulist a:not(.anchor),
-.boostlook #content .doc .olist a:not(.anchor),
-.boostlook #content .doc .dlist a:not(.anchor) {
+/* Content body links: underline per Figma. Scoped to content block classes so
+ it covers BOTH Antora (.doc) and standalone AsciiDoctor (#content, no .doc);
+ nav/TOC links (.nav-list / #toc .sectlevel*) are unaffected. Color comes from
+ the base .boostlook a rule (--text-main-text-link-blue = #0077B8). */
+.boostlook .paragraph a:not(.anchor),
+.boostlook .ulist a:not(.anchor),
+.boostlook .olist a:not(.anchor),
+.boostlook .dlist a:not(.anchor) {
text-decoration: underline;
text-underline-offset: 2px;
}
@@ -1548,7 +1609,7 @@ div.source-docs-antora.boostlook:not(:has(.doc)):not(:has(>.boostlook)) > #conte
.boostlook .sidebarblock {
padding: var(--spacing-size-xs, 0.75rem) var(--spacing-size-sm, 1rem);
background: var(--atom-one-light-bg, #fafafa) !important;
- border-radius: var(--radius-xxl, 1rem);
+ border-radius: 0.5rem; /* 8px — Figma 2.0 code block (#116-5) */
border: 1px solid var(--border-border-primary, #e4e7ea);
box-shadow: none;
line-height: 130%;
@@ -1585,7 +1646,6 @@ html.dark .boostlook .listingblock > .content > pre {
.boostlook .content:has(> pre),
.boostlook .content:has(> pre.highlight) {
border-radius: 0;
- /*border: 1px solid var(--border-border-secondary, #d5d7d9);*/
background: none;
}
@@ -1668,8 +1728,6 @@ html.dark .boostlook .listingblock > .content > pre {
.boostlook#libraryReadMe > pre:not(:is(dd pre, td pre)),
.boostlook#libraryReadMe .literalblock:has(pre):not(:is(dd pre, td pre)),
.boostlook#libraryReadMe div.highlight:has(> pre):not(:is(dd pre, td pre)) {
- /*margin-left: var(--spacing-size-xl);*/
- /*border: 1px solid var(--border-border-secondary, #d5d7d9);*/
background: var(--atom-one-light-bg, #fafafa);
margin-top: var(--padding-padding-xs, 0.75rem);
}
@@ -1712,11 +1770,7 @@ html.dark .boostlook .listingblock > .content > pre {
.boostlook .content:has(> pre) pre.highlight,
.boostlook .literalblock > .content > pre:not(.highlight) {
border: 1px solid var(--border-border-primary, #e4e7ea);
- border-radius: var(--radius-xxl, 1rem);
-}
-.boostlook .content:has(> pre):has(> .source-toolbox) pre {
- /*border: 1px solid var(--border-border-secondary, #d5d7d9);*/
- /*border-radius: var(--spacing-size-2xs, 0.5rem);*/
+ border-radius: 0.5rem; /* 8px — Figma 2.0 code block (#116-5) */
}
.boostlook .content:has(> pre):has(> .source-toolbox) .source-toolbox {
@@ -1730,12 +1784,10 @@ html.dark .boostlook .listingblock > .content > pre {
font-family: inherit;
z-index: 1;
padding: var(--article-article-compressing-from-12-8--, 0.5rem) var(--spacing-size-sm, 1rem);
- /*min-height: 2rem;*/
height: 0;
max-height: 0;
min-height: 0;
padding: 0;
- /*margin-top: -1px;*/
}
.boostlook .content:has(> pre):has(> .source-toolbox):not(:has(.source-lang)) .source-toolbox {
@@ -1870,7 +1922,6 @@ html.dark .boostlook .listingblock > .content > pre {
.boostlook .doc .colist > table code:not(:has(> code)) {
border-radius: unset;
padding: unset;
- /* border: 1px solid var(--border-border-secondary, #d5d7d9); */
background: transparent !important;
}
@@ -1890,54 +1941,12 @@ html.dark .boostlook .listingblock > .content > pre {
.boostlook .doc p:not(:is(table p)) code:has(> a:only-child),
.boostlook .doc .colist > table code:has(> a:first-child:last-child),
.boostlook .doc .colist > table code:has(> a:only-child) {
- /* transition: all 0.2s ease; */
border-radius: unset;
border: none;
background: transparent !important;
color: inherit;
}
-/* Applies to links in code in case where only one link tag inside code */
-/* .boostlook code:not(.tableblock code, .table code):has(> a:first-child:last-child) a,
-.boostlook code:not(.tableblock code, .table code):has(> a:only-child) a,
-.boostlook p code:not(.tableblock code, .table code):has(> a:first-child:last-child) a,
-.boostlook p code:not(.tableblock code, .table code):has(> a:only-child) a,
-.boostlook li code:not(.tableblock code, .table code):has(> a:first-child:last-child) a,
-.boostlook li code:not(.tableblock code, .table code):has(> a:only-child) a,
-.boostlook .doc p code:not(.tableblock code, .table code):has(> a:first-child:last-child) a,
-.boostlook .doc p code:not(.tableblock code, .table code):has(> a:only-child) a,
-.boostlook .doc .colist > table code:has(> a:first-child:last-child) a,
-.boostlook .doc .colist > table code:has(> a:only-child) a {
- text-decoration: none;
- font: inherit;
- color: inherit;
-} */
-
-/* .boostlook .doc table.tableblock code a,
-.boostlook:not(:has(.doc)) table.table code a { */
-/* text-decoration-color: transparent; */
-/* color: var(--text-code-blue, #329cd2); */
-/* line-height: var(--typography-line-height-lg, 1.5rem); */
-/* } */
-
-/* Code Link Hover States */
-/* .boostlook p:not(:is(table p)) a:hover code,
-.boostlook li a:hover code,
-.boostlook .doc p:not(:is(table p)) a:hover code,
-.boostlook .doc table a:hover code,
-.boostlook .doc .colist > table a:hover code,
-.boostlook p:not(:is(table p)) code:has(> a:first-child:last-child):hover,
-.boostlook p:not(:is(table p)) code:has(> a:only-child):hover,
-.boostlook li code:has(> a:first-child:last-child):hover,
-.boostlook li code:has(> a:only-child):hover,
-.boostlook .doc p:not(:is(table p)) code:has(> a:first-child:last-child):hover,
-.boostlook .doc p:not(:is(table p)) code:has(> a:only-child):hover,
-.boostlook .doc .colist > table code:has(> a:first-child:last-child):hover,
-.boostlook .doc .colist > table code:has(> a:only-child):hover {
- border-color: var(--border-border-blue-hover, #329cd2);
- background: var(--surface-background-main-surface-blue-tetriary, #c2e2f4) !important;
-} */
-
.boostlook a:hover code {
color: inherit;
}
@@ -2634,7 +2643,7 @@ html.dark .boostlook nav.pagination > span:hover a {
.boostlook #content .admonitionblock.note,
.boostlook:not(:has(.doc)) div.note,
.boostlook:not(:has(.doc)) .notices.note {
- border-color: var(--stroke-weak, rgba(13 14 15 / 0.1));
+ border-color: var(--stroke-weak, rgba(5 8 22 / 0.1));
background-color: var(--surface-weak, #fff);
}
@@ -2651,11 +2660,6 @@ html.dark .boostlook nav.pagination > span:hover a {
border-color: var(--border-border-positive, #f8fefb);
background-color: var(--surface-background-states-surface-positive-primary, #f6fafd);
}
-/* .boostlook #content .admonitionblock.tip > table tr td.icon,
-.boostlook:not(:has(.doc)) div.tip > table tr:first-child th,
-.boostlook:not(:has(.doc)) .notices.tip .heading {
- background: var(--border-border-positive, #bdeed6);
-} */
.boostlook #content .admonitionblock.tip > table tr td.icon > *,
.boostlook:not(:has(.doc)) div.tip > table tr:first-child th,
.boostlook:not(:has(.doc)) .notices.tip .heading {
@@ -2671,13 +2675,6 @@ html.dark .boostlook nav.pagination > span:hover a {
border-color: var(--border-border-brand-orange, #ffd897);
background-color: var(--surface-background-states-surface-warning-primary, #fefcf9);
}
-/* .boostlook #content .admonitionblock.important > table tr td.icon,
-.boostlook #content .admonitionblock.caution > table tr td.icon,
-.boostlook:not(:has(.doc)) div.important > table tr:first-child th,
-.boostlook:not(:has(.doc)) div.caution > table tr:first-child th,
-.boostlook:not(:has(.doc)) .notices.important {
- background: var(--surface-background-states-surface-warning-tetriary, #ffd4b3);
-} */
.boostlook #content .admonitionblock.important > table tr td.icon > *,
.boostlook #content .admonitionblock.caution > table tr td.icon > *,
.boostlook:not(:has(.doc)) div.important > table tr:first-child th,
@@ -2693,11 +2690,6 @@ html.dark .boostlook nav.pagination > span:hover a {
border-color: var(--border-border-negative, #ffcad2);
background-color: var(--surface-background-states-surface-negative-primary, #fdf1f3);
}
-/* .boostlook #content .admonitionblock.warning > table tr td.icon,
-.boostlook:not(:has(.doc)) div.warning > table tr:first-child th,
-.boostlook:not(:has(.doc)) .notices.warning .heading {
- background: var(--surface-background-states-surface-negative-tetriary, #ffcad2);
-} */
.boostlook #content .admonitionblock.warning > table tr td.icon > *,
.boostlook:not(:has(.doc)) div.warning > table tr:first-child th,
.boostlook:not(:has(.doc)) .notices.warning .heading {
@@ -2709,7 +2701,7 @@ html.dark .boostlook nav.pagination > span:hover a {
.boostlook #content .dlist:not(:first-child):not(.dlist .dlist):has(dl > dt.hdlist1:only-of-type + dd:last-child) {
padding: var(--spacing-large, 1rem);
border-radius: var(--radius-xxl, 1rem);
- border: 1px solid var(--stroke-weak, rgba(13 14 15 / 0.1));
+ border: 1px solid var(--stroke-weak, rgba(5 8 22 / 0.1));
background-color: var(--surface-weak, #fff);
margin-top: var(--padding-padding-sm, 1rem);
}
@@ -2765,7 +2757,6 @@ html.dark .boostlook nav.pagination > span:hover a {
letter-spacing: var(--spacing-size-size-0, 0rem);
font-weight: 600;
color: var(--text-main-text-primary, #18191b) !important;
- /*margin-bottom: var(--spacing-size-2xs, 0.5rem);*/
}
.boostlook #content .dlist:not(:first-child):not(.dlist .dlist):has(.hdlist1) dd a:hover {
color: var(--text-states-text-warning, #FF9442);
@@ -2806,7 +2797,6 @@ html.dark .boostlook nav.pagination > span:hover a {
padding: initial;
border-radius: initial;
border: initial;
- /* border-bottom-left-radius: unset; */
background: initial;
color: var(--text-code-text, #050816);
font-size: var(--typography-font-size-xs, 0.875rem);
@@ -3084,79 +3074,26 @@ div.source-docs-antora.boostlook:not(:has(.doc)):not(:has(>.boostlook)) > #conte
color: #c00;
}
-/* Ordered Lists */
+/* Ordered Lists — native numbering (Metalab 2.0, #116-1) */
.boostlook .olist.arabic > ol,
-.boostlook .olist.loweralpha > ol,
.boostlook:not(:has(.doc)) .orderedlist > ol {
- list-style: none;
- counter-reset: list-counter;
- padding-left: 0;
+ list-style: decimal;
+ padding-left: 2rem;
padding-bottom: 1rem;
}
-/* Arabic Ordered List */
-.boostlook .olist.arabic > ol > li,
-.boostlook:not(:has(.doc)) .orderedlist > ol > li {
- position: relative;
+.boostlook .olist.loweralpha > ol {
+ list-style: lower-alpha;
padding-left: 2rem;
- counter-increment: list-counter;
- line-height: var(--typography-line-height-lg, 1.5rem);
-}
-
-.boostlook .olist.arabic > ol > li::before,
-.boostlook:not(:has(.doc)) .orderedlist > ol > li::before {
- content: counter(list-counter)".";
- position: absolute;
- left: 0;
- top: -4px;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--text-main-text-primary, #18191b);
- font-size: var(--typography-font-size-sm, 1rem);
- line-height: var(--typography-line-height-sm, 1rem); /* 133.333% */
-}
-
-.boostlook .olist.arabic > ol > li::after,
-.boostlook:not(:has(.doc)) .orderedlist > ol > li::after {
- content: "";
- position: absolute;
- left: 1px;
- top: 0px;
- width: 30px;
- height: 24px;
- /*border: 1px solid var(--border-border-tetriary);*/
- /* Mask to make square brackets for marker to make it look like [ 01 ] */
- /*clip-path: polygon(0 0, 3px 0, 3px 3px, 27px 3px, 27px 0, 30px 0, 30px 24px, 27px 24px, 27px 21px, 3px 21px, 3px 24px, 0 24px);*/
+ padding-bottom: 1rem;
}
-/* LowerAlfa Ordered List */
-.boostlook .olist.loweralpha > ol > li {
- position: relative;
- padding-left: 2rem;
- counter-increment: list-counter;
+.boostlook .olist.arabic > ol > li,
+.boostlook .olist.loweralpha > ol > li,
+.boostlook:not(:has(.doc)) .orderedlist > ol > li {
line-height: var(--typography-line-height-lg, 1.5rem);
}
-.boostlook .olist.loweralpha > ol > li::before {
- content: counter(list-counter, lower-alpha) ". ";
- position: absolute;
- left: 0;
- top: 0;
- width: 24px;
- height: 24px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--text-main-text-primary, #18191b);
- font-size: var(--typography-font-size-xs, 0.875rem);
- font-variation-settings: "wght" 500, "wdth" 87.5;
- line-height: var(--Typography-line-height-lg, 1.5rem); /* 171.429% */
- letter-spacing: var(--spacing-size-size-0, 0rem);
-}
-
/* Conum */
.boostlook .doc .conum[data-value] {
position: relative;
@@ -3177,7 +3114,6 @@ div.source-docs-antora.boostlook:not(:has(.doc)):not(:has(>.boostlook)) > #conte
text-indent: unset;
color: var(--text-main-text-primary, #18191b);
text-align: center;
- /*background: var(--surface-background-main-surface-secondary, #e4e7ea);*/
}
.boostlook .doc code .conum[data-value] {
background: transparent;
@@ -3565,8 +3501,11 @@ div.source-docs-antora.boostlook:not(:has(.doc)):not(:has(>.boostlook)) > #conte
*/
@supports (scrollbar-width: thin) {
- /* HTML Matches its scroll background to content background */
- html:has(.boostlook) {
+ /* HTML Matches its scroll background to content background.
+ Gated :not(.v3) so a component-level .boostlook island on a v3 site page
+ does not restyle (and resize) the whole page scrollbar. Docs render in an
+ iframe whose html has no .v3, so they keep this. */
+ html:not(.v3):has(.boostlook) {
scrollbar-width: thin;
scrollbar-color: var(--border-border-tetriary, #afb3b6) var(--surface-background-main-base-primary, #fff);
}
@@ -3596,14 +3535,14 @@ div.source-docs-antora.boostlook:not(:has(.doc)):not(:has(>.boostlook)) > #conte
}
}
-html:has(.boostlook)::-webkit-scrollbar,
+html:not(.v3):has(.boostlook)::-webkit-scrollbar,
.boostlook::-webkit-scrollbar,
.boostlook *::-webkit-scrollbar {
width: 8px !important;
height: 8px !important;
}
-html:has(.boostlook)::-webkit-scrollbar-track {
+html:not(.v3):has(.boostlook)::-webkit-scrollbar-track {
background: var(--surface-background-main-base-primary, #fff);
border-radius: var(--spacing-size-2xs, 0.5rem);
}
@@ -3618,7 +3557,7 @@ html:has(.boostlook)::-webkit-scrollbar-track {
border-radius: var(--spacing-size-2xs, 0.5rem);
}
-html:has(.boostlook)::-webkit-scrollbar-thumb,
+html:not(.v3):has(.boostlook)::-webkit-scrollbar-thumb,
.boostlook::-webkit-scrollbar-thumb,
.boostlook *::-webkit-scrollbar-thumb,
.boostlook pre::-webkit-scrollbar-thumb,
@@ -4192,6 +4131,63 @@ html.dark .boostlook #toctitle .theme-toggle:hover {
html.dark .boostlook #toctitle .theme-toggle .theme-icon-light { display: inline; }
html.dark .boostlook #toctitle .theme-toggle .theme-icon-dark { display: none; }
+/* Collapsible TOC tree — matches the Antora nav-tree caret (see 13-antora.css):
+ parent items become flex rows with a right-aligned dotted chevron that flips
+ from down to up on expand; branches collapse by default (.is-active expands
+ them). A consumer script adds .nav-item + .nav-item-toggle, toggles .is-active. */
+.boostlook #toc ul[class^="sectlevel"] {
+ list-style: none;
+}
+.boostlook #toc .nav-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ cursor: pointer; /* the row collapses on click */
+}
+/* the link keeps normal link behavior; clicking it navigates, not collapses */
+.boostlook #toc .nav-item > a {
+ order: 0;
+ cursor: pointer;
+}
+/* nested list wraps to full width below the row; reset cursor so leaf/child
+ rows aren't falsely marked as collapsible (nested .nav-item rows re-apply it) */
+.boostlook #toc .nav-item > ul {
+ flex-basis: 100%;
+ order: 2;
+ cursor: default;
+}
+.boostlook #toc .nav-item-toggle {
+ order: 1;
+ background: none;
+ border: none;
+ outline: none;
+ width: 1.25rem;
+ height: 1.25rem;
+ padding: 0;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.boostlook #toc .nav-item-toggle::after {
+ content: "";
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ background-color: var(--text-main-text-body-secondary, #494d50);
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M13 16h-2v-2h2v2Zm-2-2H9v-2h2v2Zm4 0h-2v-2h2v2Zm-6-2H7v-2h2v2Zm8 0h-2v-2h2v2ZM7 10H5V8h2v2Zm12 0h-2V8h2v2Z'/%3E%3C/svg%3E") no-repeat center / contain;
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M13 16h-2v-2h2v2Zm-2-2H9v-2h2v2Zm4 0h-2v-2h2v2Zm-6-2H7v-2h2v2Zm8 0h-2v-2h2v2ZM7 10H5V8h2v2Zm12 0h-2V8h2v2Z'/%3E%3C/svg%3E") no-repeat center / contain;
+}
+.boostlook #toc .nav-item.is-active > .nav-item-toggle::after {
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M13 10h-2V8h2v2ZM11 12H9v-2h2v2Zm4 0h-2v-2h2v2ZM9 14H7v-2h2v2Zm8 0h-2v-2h2v2ZM7 16H5v-2h2v2Zm12 0h-2v-2h2v2Z'/%3E%3C/svg%3E");
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M13 10h-2V8h2v2ZM11 12H9v-2h2v2Zm4 0h-2v-2h2v2ZM9 14H7v-2h2v2Zm8 0h-2v-2h2v2ZM7 16H5v-2h2v2Zm12 0h-2v-2h2v2Z'/%3E%3C/svg%3E");
+}
+/* collapsed by default; expanded when active (Antora parity) */
+.boostlook #toc .nav-item:not(.is-active) > ul {
+ display: none;
+}
+
/*----------------- Styles specific to AsciiDoctor content end -----------------*/
/*----------------- Styles specific to Antora Templates start -----------------*/
@@ -4391,6 +4387,11 @@ html.dark .boostlook #toctitle .theme-toggle .theme-icon-dark { display: none; }
display: flex;
}
+/* Hide the Antora on-page TOC sidebar; the article reclaims the width */
+.boostlook .toc.sidebar {
+ display: none;
+}
+
.boostlook #footer:has(> script):not(:has(> div)) {
padding-top: 0;
padding-bottom: 0;
@@ -5499,7 +5500,7 @@ html.dark .boostlook#libraryReadMe {
/* Prevent header/content/footer padding from jumping at 990px breakpoint */
@media (min-width: 990px) {
- :root:has(.boostlook) {
+ :root:not(.v3):has(.boostlook) {
--main-max-width-leftbar: 18.25rem;
--main-margin: 0rem;
}
@@ -5541,7 +5542,7 @@ html.dark .boostlook#libraryReadMe {
/* === Wide Screens: Expanded Content Width (1536px+) === */
@media screen and (min-width: 1536px) {
- :root:has(.boostlook) {
+ :root:not(.v3):has(.boostlook) {
--main-content-width: 1100px;
--main-content-left-spacing: 2rem;
}
@@ -5549,7 +5550,7 @@ html.dark .boostlook#libraryReadMe {
/* === Ultra-Wide Screens: Maximum content width (1920px+) === */
@media screen and (min-width: 1920px) {
- :root:has(.boostlook) {
+ :root:not(.v3):has(.boostlook) {
--main-content-width: 1300px;
--main-content-left-spacing: 4rem;
}
@@ -5562,3 +5563,253 @@ html.dark .boostlook#libraryReadMe {
}
/*----------------- AsciiDoctor-Specific Responsive TOC Layout end -----------------*/
+
+/* ============================================================
+ Site component refinements (website-v2), scoped under .boostlook.
+ These layer on the shared Boostlook typography for specific consumer
+ components. They only match where the component class is present (the
+ website-v2 site), so they are inert in Antora/standalone contexts.
+ Note: these reference website-v2 design tokens by design.
+ ============================================================ */
+
+/* v3 site: a .boostlook island sits on the host page's own surface, not
+ boostlook's doc surface, so clear the background boostlook sets on every
+ .boostlook element. Docs (iframe html has no .v3) keep their surface. */
+html.v3 .boostlook {
+ background: transparent;
+}
+
+/* Non-doc site components use v2's primary text color (near-black in light,
+ white in dark) rather than boostlook's lighter doc body grey. Paragraphs
+ inherit their container instead of boostlook's hardcoded `.boostlook p`
+ grey, so each component's own color flows through.
+ Font: boostlook's base container forces "Mona Sans" (!important) plus a
+ condensed font-variation-settings ("wght" 400, "wdth" 95). Non-doc site
+ components should render the site's own type instead, so inherit both the
+ family (!important to beat boostlook's base rule) and the variation settings
+ from the host page. Headings that set their own font-family (e.g.
+ --font-display) still win. */
+.boostlook:where(:not(:has(.doc))) {
+ color: var(--color-text-primary);
+ font-family: inherit !important;
+ font-variation-settings: inherit;
+}
+
+/* boostlook renders bold as a condensed variable-font axis
+ ("wght" 600, "wdth" 87.5); non-doc components should use the site's normal
+ bold weight, so drop the axis override and let font-weight take effect. */
+.boostlook:where(:not(:has(.doc))) :is(b, strong) {
+ font-variation-settings: inherit;
+}
+.boostlook:where(:not(:has(.doc))) p {
+ color: inherit;
+}
+
+/* Content modal (testimonials) — #2491 */
+.boostlook.content-modal__prose {
+ color: var(--color-text-secondary);
+ font-family: var(--font-sans);
+ font-size: var(--font-size-base);
+ font-weight: var(--font-weight-regular);
+ line-height: var(--line-height-default);
+ letter-spacing: var(--letter-spacing-tight);
+}
+
+.boostlook.content-modal__prose :is(h2, h3, h4, h5, h6) {
+ margin: var(--space-xlarge) 0 var(--space-large);
+ color: var(--color-text-primary);
+ font-size: var(--font-size-large);
+ font-weight: var(--font-weight-medium);
+ line-height: var(--line-height-tight);
+ letter-spacing: var(--letter-spacing-display-regular);
+}
+
+.boostlook.content-modal__prose h2 {
+ font-size: var(--font-size-large);
+}
+
+.boostlook.content-modal__prose h3 {
+ font-size: var(--font-size-base);
+}
+
+.boostlook.content-modal__prose :is(h4, h5, h6) {
+ font-size: var(--font-size-small);
+}
+
+/* Sit flush with the top, no leading margin on the first prose element. */
+.boostlook.content-modal__prose > :first-child {
+ margin-top: 0;
+}
+
+.boostlook.content-modal__prose p {
+ margin: var(--space-default) 0;
+ padding: 0;
+ line-height: var(--line-height-loose);
+}
+
+/* Markdown card + user-profile bio (shared .markdown-content) — #2491 */
+.boostlook.markdown-content {
+ gap: var(--space-medium);
+ padding: 0 var(--space-large);
+ font-size: var(--font-size-small);
+ font-weight: var(--font-weight-regular);
+ line-height: var(--line-height-code);
+ letter-spacing: var(--letter-spacing-tight);
+ overflow-y: auto;
+ overflow-wrap: anywhere;
+ min-width: 0;
+}
+
+.boostlook.markdown-content ul,
+.boostlook.markdown-content ol {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.boostlook.markdown-content li {
+ position: relative;
+ padding-left: var(--space-xlarge);
+ margin-top: var(--space-medium);
+}
+
+.boostlook.markdown-content ul > li::before {
+ content: "\2022";
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: var(--space-xlarge);
+ height: calc(var(--font-size-small) * 1.2);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--color-text-primary);
+}
+
+.boostlook.markdown-content a {
+ color: var(--color-text-link-accent);
+ text-decoration: underline;
+ text-decoration-skip-ink: none;
+ text-underline-position: from-font;
+}
+
+.boostlook.markdown-content pre {
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+
+.boostlook.markdown-content h1,
+.boostlook.markdown-content h2,
+.boostlook.markdown-content h3,
+.boostlook.markdown-content h4,
+.boostlook.markdown-content h5,
+.boostlook.markdown-content h6 {
+ color: var(--color-text-primary);
+ font-family: var(--font-display);
+ font-weight: var(--font-weight-medium);
+ margin: 0;
+}
+
+.boostlook.markdown-content h1 { font-size: var(--font-size-large); }
+.boostlook.markdown-content h2 { font-size: var(--font-size-medium); }
+.boostlook.markdown-content h3 { font-size: var(--font-size-base); }
+.boostlook.markdown-content h4,
+.boostlook.markdown-content h5,
+.boostlook.markdown-content h6 { font-size: var(--font-size-small); }
+
+.boostlook.markdown-content b,
+.boostlook.markdown-content strong {
+ color: var(--color-text-primary);
+ font-weight: var(--font-weight-medium);
+}
+
+.boostlook.markdown-content p {
+ /* Keep the card's paragraph size/spacing faithful to v2. Color comes from
+ the non-doc `color: inherit` rule above, so it follows the container
+ (v2's primary near-black) instead of boostlook's grey. */
+ font-size: var(--font-size-small);
+ line-height: var(--line-height-code);
+ letter-spacing: var(--letter-spacing-tight);
+ padding: 0;
+ margin: 0;
+}
+
+.boostlook.markdown-content :is(code, tt, pre) {
+ display: inline;
+ font-family: var(--font-code);
+ font-size: 0.88em;
+ font-weight: var(--font-weight-medium);
+ color: var(--color-text-primary);
+ background: transparent;
+ padding: 0;
+ border: none;
+ border-radius: 0;
+}
+
+/* Post detail (news article body) — #2491. The container keeps its layout
+ (flex/gap/border) in post-detail.css; the rich-text typography lives here.
+ Body copy is intentionally secondary grey (overrides the non-doc primary
+ default above); headings and bold use primary. */
+.boostlook.post-detail__body {
+ color: var(--color-text-secondary);
+ font-size: var(--font-size-base);
+ line-height: var(--line-height-loose);
+ letter-spacing: var(--letter-spacing-tight);
+}
+
+.boostlook.post-detail__body a {
+ color: inherit;
+ text-decoration: underline;
+}
+
+.boostlook.post-detail__body img {
+ max-width: 100%;
+ height: auto;
+ border-radius: var(--border-radius-m);
+}
+
+.boostlook.post-detail__body :is(pre, code) {
+ font-family: var(--font-code);
+ font-size: var(--font-size-small);
+}
+
+.boostlook.post-detail__body pre {
+ padding: var(--space-medium);
+ border-radius: var(--border-radius-m);
+ background: var(--color-surface-mid);
+ overflow-x: auto;
+}
+
+/* Rhythm between blocks comes from the container's flex `gap`, so strip the
+ block margins boostlook's bare-markdown layer adds; otherwise they stack on
+ the gap and the spacing doubles. Lists stay tight (as v2 had them). */
+.boostlook.post-detail__body :is(p, ul, ol, li, pre, h1, h2, h3, h4, h5, h6) {
+ margin: 0;
+}
+
+.boostlook.post-detail__body :is(ul, ol) {
+ padding-left: var(--space-large);
+ list-style-position: outside;
+}
+
+.boostlook.post-detail__body ul { list-style-type: disc; }
+.boostlook.post-detail__body ol { list-style-type: decimal; }
+.boostlook.post-detail__body ul ul { list-style-type: circle; }
+.boostlook.post-detail__body :is(ol ol, ul ol) { list-style-type: lower-alpha; }
+
+.boostlook.post-detail__body :is(h1, h2, h3, h4, h5, h6) {
+ color: var(--color-text-primary);
+ font-family: var(--font-display);
+ font-weight: var(--font-weight-medium);
+ line-height: var(--line-height-tight);
+}
+
+.boostlook.post-detail__body h1 { font-size: var(--font-size-xl); }
+.boostlook.post-detail__body h2 { font-size: var(--font-size-large); }
+.boostlook.post-detail__body h3 { font-size: var(--font-size-medium); }
+.boostlook.post-detail__body :is(h4, h5, h6) { font-size: var(--font-size-base); }
+
+.boostlook.post-detail__body :is(b, strong) {
+ color: var(--color-text-primary);
+ font-weight: var(--font-weight-medium);
+}
diff --git a/boostlook-v3.rb b/boostlook-v3.rb
new file mode 100644
index 0000000..27b4959
--- /dev/null
+++ b/boostlook-v3.rb
@@ -0,0 +1,210 @@
+# boostlook-v3.rb — Asciidoctor postprocessor for Boostlook 2.0 (boostlook-v3.css)
+#
+# Wraps rendered output in — the scope every v3 selector
+# lives under — and injects the client-side behavior the CSS expects, so docs get
+# it automatically without a per-document docinfo footer:
+# * keeps the left TOC visible/pinned
+# * turns the Asciidoctor :toc: into a collapsible nav-tree matching the Antora
+# nav: caret toggles, collapsed by default, current path expanded,
+# open sections persisted, and scroll-spy active-link highlighting.
+#
+# Caret/collapse styling lives in boostlook-v3.css (src/css/12-asciidoctor.css).
+#
+# Usage: asciidoctor -r ./boostlook-v3.rb ... doc.adoc
+
+Asciidoctor::Extensions.register do
+ postprocessor do
+ process do |doc, output|
+ # Wrap the body content in the .boostlook scope (footer kept outside).
+ output = output.sub(/(]*>)/, '\1
')
+ output = output.sub('', '