/* layout: no top bar on desktop, the sidebar carries logo and search, no
dividers anywhere, a narrow reading column */
:root,
:root[data-theme="light"] {
--sl-content-width: 36rem;
--sl-sidebar-width: 18.5rem;
--sl-sidebar-pad-x: 3rem;
/* one top inset shared by sidebar, content and table of contents */
--docs-top: 5rem;
--sl-color-hairline: transparent;
--sl-color-hairline-light: transparent;
--sl-color-hairline-shade: transparent;
}
@media (min-width: 50rem) {
:root[data-has-sidebar] {
--sl-nav-height: 0rem;
}
:root[data-has-sidebar] .header {
display: none;
}
}
/* the landing page keeps a header, but it scrolls away with the page */
:root:not([data-has-sidebar]) .header {
position: absolute;
background: transparent;
}
.docs-header,
.docs-header-end {
display: flex;
align-items: center;
gap: 0.5rem;
}
.docs-header {
justify-content: space-between;
height: 100%;
}
::selection {
background-color: var(--color-background-info-subtle-hover);
color: var(--color-foreground-default);
}
/* sidebar */
@media (min-width: 50rem) {
.sidebar-content {
padding-top: var(--docs-top);
/* more gutter on the left, with the freed space taken from the invisible
right side so the nav keeps its width and long labels don't wrap */
padding-inline: 5rem 1rem;
gap: 1.75rem;
}
:root[data-has-sidebar] main > .content-panel:first-of-type {
padding-top: var(--docs-top);
/* the title panel and the body panel each add 1.5rem of padding, which
leaves a 3rem gap under the title; trim it to the reference's 1rem */
padding-bottom: 0.5rem;
}
:root[data-has-sidebar] main > .content-panel:first-of-type + .content-panel {
padding-top: 0.5rem;
}
.right-sidebar-panel {
padding-top: var(--docs-top);
}
:root[data-has-sidebar] main > .content-panel:first-of-type h1 {
margin-top: 0;
}
}
/* the "On this page" label is just a bold entry, the same size as the links */
.right-sidebar-panel h2 {
font-size: var(--sl-text-xs);
font-weight: var(--font-weight-semibold);
}
/* every ToC entry aligns with the label: no indent for nested headings */
.right-sidebar-panel nav a {
padding-inline-start: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.sidebar-top {
align-items: center;
justify-content: space-between;
}
.site-title {
color: var(--sl-color-white);
}
/* search: a pill at the top of the sidebar that opens the search dialog */
.sidebar-search button[data-open-modal] {
display: flex;
width: 100%;
height: 2rem;
max-width: none;
gap: 0.5rem;
padding-inline: 0.75rem;
border: 1px solid var(--color-border-default);
border-radius: 9999px;
background-color: var(--color-background-default);
color: var(--color-foreground-subtle);
font-size: 0.875rem;
}
.sidebar-search button[data-open-modal]:hover {
border-color: var(--color-border-strong);
color: var(--color-foreground-muted);
}
.sidebar-search button[data-open-modal] > span {
display: block;
}
.sidebar-search button[data-open-modal] kbd {
margin-inline-start: auto;
background: transparent;
color: var(--color-foreground-subtle);
}
/* the dialog takes the reading column's width, and its corners follow the
input's radius out by the frame's padding, so the two curves are concentric */
site-search dialog {
margin-top: 12vh;
border: 1px solid var(--color-border-default);
border-radius: calc(var(--radius-md) + var(--spacing-xs));
background-color: var(--color-background-default);
box-shadow: 0 24px 48px -12px var(--color-shadow-ambient-strong);
}
@media (min-width: 50rem) {
site-search dialog {
max-width: var(--sl-content-width);
min-height: 0;
}
site-search .dialog-frame {
padding: var(--spacing-xs);
}
}
site-search .dialog-frame {
scrollbar-width: none;
}
site-search .dialog-frame::-webkit-scrollbar {
display: none;
}
site-search dialog::backdrop {
/* the web app's modal scrim: black in both themes, so dark mode dims rather
than lightens the page behind the dialog */
background-color: rgb(0 0 0 / 0.4);
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
/* the search dialog's input and results are set at the prose size. pagefind
groups results by page; the page titles are hidden so the matches read as
one flat list of cards, which only show a background on hover. the input follows the app's list search
(Input with a search icon and a ghost clear button) */
#starlight__search {
--pagefind-ui-border-radius: var(--radius-md);
--search-match: #fef08a;
}
:root[data-theme="dark"] #starlight__search {
--search-match: rgb(250 204 21 / 0.3);
}
#starlight__search .pagefind-ui__search-input {
height: 2rem;
padding-inline: 1.875rem 2rem;
border: 0;
background-color: var(--color-background-default);
box-shadow: inset 0 0 0 1px var(--color-shadow-ring);
font-size: var(--sl-text-body);
transition: box-shadow 150ms;
}
#starlight__search input:focus {
outline: none;
box-shadow:
inset 0 0 0 1px var(--color-border-strong),
0 0 0 1px var(--color-border-strong);
}
#starlight__search .pagefind-ui__search-input::placeholder {
color: var(--color-foreground-placeholder);
opacity: 1;
}
#starlight__search .pagefind-ui__form::before {
top: 0.5625rem;
left: 0.5rem;
width: 0.875rem;
height: 0.875rem;
background-color: var(--color-foreground-subtle);
}
#starlight__search .pagefind-ui__search-clear {
top: 0.25rem;
right: 0.25rem;
width: 1.5rem;
height: 1.5rem;
border-radius: var(--radius-sm);
}
#starlight__search .pagefind-ui__search-clear:hover {
background-color: var(--color-background-inset);
}
#starlight__search .pagefind-ui__search-clear::before {
background-color: var(--color-foreground-muted);
mask-size: 0.875rem;
-webkit-mask-size: 0.875rem;
}
#starlight__search .pagefind-ui__results-area {
margin-top: var(--spacing-xs);
}
#starlight__search .pagefind-ui__message {
height: auto;
padding: 0 var(--spacing-sm) var(--spacing-xs);
color: var(--color-foreground-subtle);
font-size: var(--sl-text-sm);
font-weight: 400;
}
#starlight__search :is(.pagefind-ui__results, .pagefind-ui__result-inner) {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 0.125rem;
}
#starlight__search .pagefind-ui__results > * + * {
margin-top: 0;
}
#starlight__search .pagefind-ui__result-inner > .pagefind-ui__result-title {
display: none;
}
#starlight__search .pagefind-ui__result-nested::before {
content: none;
}
#starlight__search .pagefind-ui__result-nested {
padding: 0.375rem var(--spacing-sm);
border-radius: var(--radius-md);
background-color: transparent;
}
#starlight__search .pagefind-ui__result-nested .pagefind-ui__result-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: var(--sl-text-body);
line-height: var(--sl-line-height);
}
#starlight__search .pagefind-ui__result-link[data-page]::before {
position: static;
content: attr(data-page) " / ";
color: var(--color-foreground-muted);
}
#starlight__search .pagefind-ui__result-nested .pagefind-ui__result-link {
color: var(--color-foreground-default);
font-size: inherit;
font-weight: var(--font-weight-medium);
}
#starlight__search .pagefind-ui__result-excerpt {
min-width: 0;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--color-foreground-muted);
font-size: var(--sl-text-body);
line-height: var(--sl-line-height);
}
#starlight__search .pagefind-ui__result-excerpt[data-clipped]::before {
content: "… ";
}
#starlight__search .pagefind-ui__result-excerpt[data-trails]::after {
content: " …";
}
#starlight__search mark {
border-radius: 0.125rem;
background-color: var(--search-match);
color: inherit;
font-weight: inherit;
}
#starlight__search .pagefind-ui__result-nested:is(:hover, [data-active]) {
outline: none;
background-color: var(--color-background-inset);
}
#starlight__search .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):focus-within,
#starlight__search .pagefind-ui__result-nested:focus-within {
outline: none;
}
#starlight__search .pagefind-ui__result-nested a:focus-visible {
outline: none;
}
#starlight__search .pagefind-ui__result-nested:has(a:focus-visible) {
outline: 2px solid var(--color-border-focus);
outline-offset: 2px;
}
/* results show a page of cards at a time (see Search.astro). while more can
load, the last shown card fades out, and scrolling it into view loads more
in place of pagefind's button */
#starlight__search .pagefind-ui__result-nested[data-overflow],
#starlight__search .pagefind-ui__button {
display: none;
}
#starlight__search .pagefind-ui__result-nested[data-faded] {
mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.5), transparent);
pointer-events: none;
}
/* the sidebar scrolls, but without a visible scrollbar */
.sidebar-pane {
scrollbar-width: none;
}
.sidebar-pane::-webkit-scrollbar {
display: none;
}
/* the mobile menu toggle is a ghost button */
starlight-menu-button button {
background-color: transparent;
box-shadow: none;
border-radius: var(--radius-md);
color: var(--color-foreground-muted);
}
starlight-menu-button button:hover,
starlight-menu-button[aria-expanded="true"] button {
background-color: var(--color-background-inset);
}
starlight-menu-button button:focus-visible {
outline: 2px solid var(--color-border-focus);
outline-offset: 2px;
}
/* on mobile the header reserves room for the fixed menu button, with a 0.5rem gap */
@media (max-width: 49.999rem) {
:root[data-has-sidebar] .header {
padding-inline-end: calc(0.5rem + var(--sl-nav-pad-x) + var(--sl-menu-button-size));
}
}
/* the nav: one size throughout, bold group headings, whitespace between groups */
.docs-nav {
font-size: 0.875rem;
line-height: 1.2;
}
.docs-nav ul {
list-style: none;
margin: 0;
padding: 0;
}
.docs-nav > * + * {
margin-top: 1.75rem;
}
.docs-nav h2,
.docs-nav h3 {
margin: 0 0 0.25rem;
font-size: inherit;
line-height: inherit;
color: var(--color-foreground-default);
}
.docs-nav h2 {
font-weight: var(--font-weight-semibold);
}
.docs-nav h3 {
font-weight: var(--font-weight-medium);
}
.docs-nav .subgroup {
margin-block: 0.75rem;
}
.docs-nav a {
display: block;
padding-block: 0.25rem;
color: var(--color-foreground-muted);
text-decoration: none;
}
.docs-nav a:hover {
color: var(--color-foreground-default);
}
.docs-nav a[aria-current="page"] {
color: var(--color-foreground-default);
font-weight: var(--font-weight-medium);
}
/* content: markup.css does the typography. what's left is fitting it around
the elements starlight adds */
/* body text sits a step below the brightest foreground; headings and links
stay bright. markup.css sets the container colour and each heading's, so a
rule on the container re-tints the prose without dimming the headings */
.markup {
color: var(--color-foreground-muted);
}
/* tables take the web app's card/panel radius (--radius-md). the outer border
sits on the table (a block scroll container), so its corners follow the
radius cleanly: the cells keep only their inner rules and no border is
clipped at the corners */
.markup table {
border: 1px solid var(--color-border-default);
border-radius: var(--radius-md);
border-collapse: separate;
border-spacing: 0;
}
/* code blocks are the same kind of panel, so match the table radius.
markup.css gives every `pre` the smaller inline radius, which also wins over
expressive-code's own border radius, so override it here */
.markup pre {
border-radius: var(--radius-md);
}
/* keyboard keys follow kumo-svelte's prose `kbd`: a flat keycap -- a hairline
border on the base surface, no inset shadow -- set in mono at 0.875em */
.markup kbd {
padding: 0.125rem 0.375rem;
border: 1px solid var(--color-border-default);
border-radius: 0.25rem;
background-color: var(--color-background-default);
color: var(--color-foreground-default);
font-family: var(--font-mono);
font-size: 0.875em;
font-weight: 400;
line-height: inherit;
box-shadow: none;
}
.markup :is(th, td) {
border: 0;
border-inline-end: 1px solid var(--color-border-default);
border-block-end: 1px solid var(--color-border-default);
}
/* the last column and row drop their inner rules, the table border closes them */
.markup tr > :last-child {
border-inline-end: 0;
}
.markup tbody tr:last-child > * {
border-block-end: 0;
}
.markup :is(p, li, dd, blockquote) {
overflow-wrap: break-word;
}
.markup :is(h1, h2, h3, h4, h5, h6) {
text-wrap: balance;
}
/* starlight wraps each heading with its anchor link. the rule under a
readme's h1 and h2 goes on the wrapper, so it spans the column */
.markup .sl-heading-wrapper {
margin-top: var(--spacing-xl);
margin-bottom: var(--spacing-sm);
}
.markup .sl-heading-wrapper > :is(h1, h2, h3, h4, h5, h6) {
margin: 0;
border: 0;
padding: 0;
}
.markup .sl-heading-wrapper:is(.level-h1, .level-h2) {
border-bottom: 1px solid var(--color-border-default);
padding-bottom: var(--spacing-xs);
}
.markup > :first-child,
.markup > .sl-heading-wrapper:first-child {
margin-top: 0;
}
/* keep the shared markup styles' always-on underline: the text stays the
brightest foreground, the underline is muted until hover, then brightens.
this drops the indigo link-hover colour (web/src/markup.css). the heading
anchor keeps its `#` */
.markup a:not(.sl-anchor-link) {
color: var(--color-foreground-default);
text-decoration-color: var(--color-foreground-muted);
}
.markup a:not(.sl-anchor-link):hover {
color: var(--color-foreground-default);
text-decoration-color: var(--color-foreground-default);
}
/* the anchor link, shown as tangled.org's `#` on hover */
.markup .sl-anchor-link {
margin-inline-start: var(--spacing-xs);
color: var(--color-foreground-placeholder);
text-decoration: none;
opacity: 0;
transition: opacity 150ms;
}
.markup .sl-heading-wrapper:hover .sl-anchor-link,
.markup .sl-anchor-link:focus-visible {
opacity: 1;
}
.markup .sl-anchor-link svg {
display: none;
}
.markup .sl-anchor-link::before {
content: "#";
}
/* asides, styled like tangled.org's github alerts */
.markup .starlight-aside {
margin-block: var(--spacing-sm);
padding: 0 0 0 var(--spacing-md);
border: 0;
border-inline-start: 2px solid var(--color-border-default);
background: transparent;
}
.markup .starlight-aside__title {
gap: 0;
font-size: inherit;
font-weight: var(--font-weight-semibold);
}
.markup .starlight-aside__icon {
display: none;
}
.markup .starlight-aside--note,
.markup .starlight-aside--tip {
border-color: var(--color-background-info-emphasis);
}
.markup .starlight-aside--note .starlight-aside__title {
color: var(--color-foreground-info);
}
.markup .starlight-aside--tip {
border-color: var(--color-background-success-emphasis);
}
.markup .starlight-aside--tip .starlight-aside__title {
color: var(--color-foreground-success);
}
.markup .starlight-aside--caution {
border-color: var(--color-background-warning-emphasis);
}
.markup .starlight-aside--caution .starlight-aside__title {
color: var(--color-foreground-warning);
}
.markup .starlight-aside--danger {
border-color: var(--color-background-danger-emphasis);
}
.markup .starlight-aside--danger .starlight-aside__title {
color: var(--color-foreground-danger);
}
/* no next/previous links at the foot of the page */
.pagination-links {
display: none;
}
/* expressive code sets its own size on pre; markup.css sizes code at 0.875em of
pre, so pre takes the body size and code lands on tangled.org's 13px */
.markup .expressive-code pre {
font-size: 0.9375rem;
}
/* no copy button on code blocks */
.expressive-code .copy {
display: none;
}
/* starlight sizes the heading wrapper with its own scale, which the anchor link
inherits; match each level to the heading markup.css gives it */
.markup .sl-heading-wrapper.level-h1 {
font-size: 1.5rem;
}
.markup .sl-heading-wrapper.level-h2 {
font-size: 1.25rem;
}
.markup .sl-heading-wrapper.level-h3 {
font-size: 1rem;
}
.markup .sl-heading-wrapper:is(.level-h4, .level-h5, .level-h6) {
font-size: 0.8125rem;
}
/* starlight lets inline code break anywhere; in a table that splits short
identifiers mid-word, so keep them whole and let the table scroll instead */
.markup :is(td, th) code {
overflow-wrap: normal;
white-space: nowrap;
}
body {
text-wrap-style: pretty;
}