// Warm Workbench Theme for Worktrunk Docs
// A clean workbench in a sunlit garage: warm paper, neatly labeled trays
// ============================================================================
// Base
// ============================================================================
html {
// Reserve scrollbar space to prevent layout shift when navigating
// Browser support: Safari 17+, Chrome 94+, Firefox 97+. Graceful degradation.
scrollbar-gutter: stable;
}
body {
padding: 0;
margin: 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
// iOS viewport jank fix: --vh-full is set by JS in base.html for iOS browsers.
// Fallback to 100lvh for other browsers. See base.html for full explanation.
min-height: var(--vh-full, 100lvh);
font-family: var(--wt-font-sans);
font-size: 15px;
line-height: 1.5;
color: var(--wt-color-text);
background-color: var(--wt-color-bg);
}
a {
text-decoration: none;
}
// ============================================================================
// Utility Classes
// ============================================================================
.text-center {
text-align: center;
}
// ============================================================================
// Typography
// ============================================================================
// Shared heading underline effect (H1/H2)
// Turns gold on hover, otherwise subtle craft brown
%heading-underline {
&::after {
content: "";
position: absolute;
left: 0;
bottom: -0.3rem;
width: 45%;
height: 2px;
background: var(--wt-color-craft-brown);
opacity: 0.5;
border-radius: 1px;
transition: background 150ms ease-out, opacity 150ms ease-out;
}
&:hover::after {
background: var(--wt-color-accent);
opacity: 1;
}
}
// Headings
h1, h2, h3, h4, h5, h6 {
font-family: var(--wt-font-head);
color: var(--wt-color-text);
// Account for sticky header when scrolling to anchors
scroll-margin-top: calc(var(--wt-header-height) + var(--wt-main-padding-top));
}
h1 {
font-size: 1.5rem;
font-weight: 650;
letter-spacing: -0.02em;
margin-top: 2rem;
margin-bottom: 0.5rem;
position: relative;
width: fit-content; // Block-level but sized to content (for underline effect)
> a {
@extend %heading-underline;
}
}
h2 {
font-size: 1.4rem;
font-weight: 600;
letter-spacing: -0.02em;
margin-top: 1.6rem;
margin-bottom: 0.4rem;
position: relative;
display: inline-block;
> a {
@extend %heading-underline;
}
}
h3 {
font-size: 1.15rem;
font-weight: 550;
margin-top: 1.2rem;
margin-bottom: 0.3rem;
color: var(--wt-color-text-muted);
}
h4 {
font-size: 1rem;
font-weight: 550;
margin-top: 1rem;
margin-bottom: 0.25rem;
}
// Heading anchor links - entire heading is clickable
// .heading-anchor = custom anchors in templates, .zola-anchor = Zola-generated
h1 > a.heading-anchor,
h1 > a.zola-anchor,
h2 > a.zola-anchor,
h3 > a.zola-anchor,
h4 > a.zola-anchor {
color: inherit;
text-decoration: none;
&:hover {
text-decoration: none;
}
}
// h3/h4 hover: color shift to accent (h1/h2 have underline intensify via ::after)
h3 > a.zola-anchor,
h4 > a.zola-anchor {
transition: color 150ms ease-out;
&:hover {
color: var(--wt-color-accent);
}
}
// Page title heading (used on content pages and hero)
// These are standalone titles, not section headers, so no underline
.heading-text {
font-family: var(--wt-font-head);
font-size: 1.75rem;
font-weight: 650;
letter-spacing: -0.02em;
margin-top: 0;
margin-bottom: 0.5rem;
color: var(--wt-color-text);
width: auto; // Override h1's fit-content to allow centering
// Disable the h1 > a underline for page titles
> a::after {
display: none;
}
}
// ============================================================================
// Header & Bench Rail
// ============================================================================
header {
// Height includes safe-area-inset so content isn't compressed on notched devices
height: calc(var(--wt-header-height) + env(safe-area-inset-top, 0px));
box-sizing: border-box;
background-color: var(--wt-color-bg-soft);
border-bottom: 1px solid var(--wt-color-border-subtle);
padding: 0 50px;
// iOS safe area: push content below notch/Dynamic Island
padding-top: env(safe-area-inset-top, 0px);
position: sticky;
top: 0;
// Z-index hierarchy: overlay(199) < scrim(200) = menu(200) < header(201)
// Header on top so toggle button remains clickable when menu is open
z-index: 201;
display: flex;
align-items: center;
justify-content: space-between;
}
// iOS 26 Liquid Glass fix: solid scrim behind translucent browser chrome
// Safari's translucent URL bar samples underlying content - this ensures it
// samples a stable solid color (header background) instead of scrolling content.
// Hidden on non-iOS to avoid unnecessary DOM/paint cost.
.ios-chrome-scrim {
display: none;
}
@supports (-webkit-touch-callout: none) {
.ios-chrome-scrim {
display: block;
position: fixed;
top: 0;
left: 0;
right: 0;
// Cover safe area inset plus header height so the browser chrome
// always samples this solid color, not scrolling content beneath
height: calc(env(safe-area-inset-top, 0px) + var(--wt-header-height));
background: var(--wt-color-bg-soft);
// Below header (201) so header remains interactive
z-index: 200;
pointer-events: none;
}
}
.logo {
display: flex;
align-items: center;
gap: 0.35rem;
font-family: var(--wt-font-sans);
font-weight: 600;
font-size: 1.25rem;
color: var(--wt-color-text);
img {
width: 44px;
height: 44px;
object-fit: contain;
}
}
// Navigation
nav {
display: flex;
align-items: center;
gap: 0;
}
// Navigation links
.nav-item {
font-size: 0.85rem;
font-weight: 500;
color: var(--wt-color-text-muted);
padding: 0.2rem 0.4rem;
border-radius: var(--wt-radius-pill);
transition: color 150ms, background 150ms;
&:hover {
color: var(--wt-color-text);
background: var(--wt-color-bg-soft);
}
}
// ============================================================================
// Search - Dropdown style (elasticlunr)
// ============================================================================
.search-container {
position: relative;
margin-right: 1rem;
// Keep input expanded while anything in container has focus (including
// clicking a search result link). Prevents jarring shrink during navigation.
&:focus-within #userinput {
width: 240px;
border-color: var(--wt-color-accent);
}
// Freeze search container during view transitions to prevent layout shift.
// Without this, focus loss during transition causes input to shrink.
// Progressive enhancement: View Transitions API (Chrome 111+, Safari 18+)
&:focus-within {
view-transition-name: search-frozen;
}
}
#userinput {
width: 180px;
padding: 0.4rem 0.75rem;
font-size: 0.9rem;
font-family: var(--wt-font-sans);
color: var(--wt-color-text);
background: var(--wt-color-bg);
border: 1px solid var(--wt-color-border-subtle);
border-radius: var(--wt-radius-md);
transition: width 150ms, border-color 150ms;
&::placeholder {
color: var(--wt-color-text-soft);
}
}
#suggestions {
display: none;
position: absolute;
top: calc(100% + 0.5rem);
left: 0;
width: 400px;
max-height: 70vh;
overflow-y: auto;
background: var(--wt-color-bg-elevated);
border: 1px solid var(--wt-color-border-subtle);
border-radius: var(--wt-radius-md);
box-shadow: 0 8px 30px var(--wt-shadow-medium);
z-index: 1000;
}
.search-result {
display: flex;
flex-direction: column;
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--wt-color-border-subtle);
text-decoration: none;
transition: background 150ms;
&:last-child {
border-bottom: none;
}
&:hover, &:focus {
background: var(--wt-color-bg-soft);
outline: none;
}
}
.search-title {
font-weight: 600;
color: var(--wt-color-text);
margin-bottom: 0.25rem;
}
.search-excerpt {
font-size: 0.85rem;
color: var(--wt-color-text-muted);
line-height: 1.4;
b {
color: var(--wt-color-text);
font-weight: 600;
}
}
// ============================================================================
// Main Content Area
// ============================================================================
main {
display: flex;
flex-grow: 1;
background-color: var(--wt-color-bg);
padding: var(--wt-main-padding-top) 80px;
gap: 2.5rem;
}
.content {
display: block;
box-sizing: border-box;
width: 100%;
max-width: 922px;
min-width: 0;
overflow-x: auto;
padding: 1.5rem 30px;
background-color: var(--wt-color-bg-elevated);
border-radius: var(--wt-radius-lg);
border: 1px solid var(--wt-color-border-subtle);
box-shadow: 0 1px 3px var(--wt-shadow-soft);
// Account for sticky header when scrolling to page anchor (e.g., /#worktrunk)
scroll-margin-top: calc(var(--wt-header-height) + var(--wt-main-padding-top));
}
// Paragraphs
.content p {
margin-bottom: 0.75rem;
}
// Images - horizontally scrollable, never shrink
.content p:has(> img) {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.content img {
display: block;
max-width: 100%;
height: auto; // Maintain aspect ratio when width/height attrs set for CLS prevention
box-sizing: border-box;
border: 1px solid var(--wt-color-code-border);
border-left: 3px solid var(--wt-color-accent);
border-radius: 0 var(--wt-radius-md) var(--wt-radius-md) 0;
box-shadow: 0 2px 8px var(--wt-shadow-soft), 0 1px 2px var(--wt-shadow-medium);
}
// Demo GIFs - shrink to min-width, then horizontal scroll
.content figure.demo {
margin-top: 0.25rem;
picture {
display: block;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
img {
display: block;
min-width: 800px;
max-width: 100%;
height: auto;
// Hide until loaded (JS adds .loaded class) - visibility preserves GIF animation state
visibility: hidden;
&.loaded {
visibility: visible;
}
}
}
// Tighten spacing between paragraphs and code blocks
.content p + pre,
.content p + .terminal,
.content pre + p,
.content .terminal + p {
margin-top: 0.5rem;
}
// Links
.content a {
color: var(--wt-color-link);
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
// ============================================================================
// Inline Code
// ============================================================================
.content code {
padding: 0.1rem 0.3rem;
color: var(--wt-color-code-inline-text);
font-family: var(--wt-font-mono);
font-size: 0.92rem;
font-weight: 400;
}
// Remove padding from code inside links so underline animation matches text width
.content a code {
padding: 0;
}
// ============================================================================
// Code Blocks - Distinctive card style with left accent
// ============================================================================
// Override syntect's background to use our theme colors
.z-code {
background-color: transparent;
}
// Quoted strings get olive color via CSS sibling selector (light mode only).
// Giallo emits: <span class="z-punctuation z-definition z-string">'</span><span class="z-string">content</span>
// Bare strings (subcommands like `switch`) are just <span class="z-string"> without a preceding quote span.
// Must match punctuation.definition.string in worktrunk-light.json (#588a10).
@media (prefers-color-scheme: light) {
.z-punctuation.z-definition.z-string + .z-string {
color: #588a10;
}
}
// Shared styles for code blocks and terminal output
%code-block-base {
position: relative;
background-color: var(--wt-color-code-bg);
border: 1px solid var(--wt-color-code-border);
border-left: 3px solid var(--wt-color-accent);
border-radius: 0 var(--wt-radius-md) var(--wt-radius-md) 0;
padding: 0.875rem 1rem;
overflow-x: auto;
margin: 1.25rem 0;
box-shadow: 0 2px 8px var(--wt-shadow-soft), 0 1px 2px var(--wt-shadow-medium);
transition: box-shadow 50ms;
&:hover {
box-shadow: 0 0 0 1px var(--wt-color-accent-soft),
0 4px 16px var(--wt-shadow-accent),
0 2px 8px var(--wt-shadow-medium);
}
code {
background-color: transparent;
padding: 0;
font-family: var(--wt-font-mono);
font-size: 0.875rem;
line-height: 1.6;
// Note: color is NOT set here to allow syntax highlighting themes to apply
}
}
.content pre {
@extend %code-block-base;
// Override .content code color to allow syntax highlighting
code {
color: inherit;
}
}
// Wrapper for code blocks - enables fixed copy button during horizontal scroll
.code-block-wrapper {
position: relative;
}
// Copy button for code blocks
// Positioned on the wrapper (not the pre) so it stays fixed when code scrolls horizontally
.code-copy-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
padding: 0.4rem;
background: var(--wt-color-bg-soft);
border: 1px solid var(--wt-color-border-subtle);
border-radius: var(--wt-radius-sm);
cursor: pointer;
color: var(--wt-color-text-muted);
opacity: 0;
transition: opacity 150ms, background 150ms, color 150ms;
line-height: 0;
z-index: 1;
&:hover {
background: var(--wt-color-bg);
color: var(--wt-color-text);
}
&.copied {
color: var(--wt-color-accent);
}
}
.code-block-wrapper:hover .code-copy-btn {
opacity: 1;
}
// Terminal output styling (ANSI colors)
.terminal {
@extend %code-block-base;
font-family: var(--wt-font-mono);
font-size: 0.875rem;
line-height: 1.5;
color: var(--wt-color-text); // Default text color for terminal (not syntax-highlighted)
// Command text with $ prompt (generated via ::before, making it non-copyable)
// When giallo spans are present, their colors take precedence over the base color
.cmd {
color: var(--wt-color-accent);
&::before {
content: "$ ";
color: var(--wt-color-text-soft);
}
}
// Softer bold for table headers and branch names
b {
font-weight: 550;
}
// ANSI color classes for terminal output
.d { opacity: 0.67; }
.g { color: var(--green, #0a0); }
.r { color: var(--red, #a00); }
.c { color: var(--cyan, #0aa); }
.y { color: var(--yellow, #a60); }
.b { color: var(--blue, #00a); }
// Gutter spans - extend vertically to form continuous line
span[style*="background:var(--bright-white"] {
display: inline-block;
margin: -0.25em 0;
padding: 0.25em 0;
}
}
// ============================================================================
// Blockquotes / Callouts
// ============================================================================
.content blockquote {
border-radius: var(--wt-radius-md);
padding: 0.75rem 1rem;
border: 1px solid var(--wt-color-border-subtle);
border-left: 3px solid var(--wt-color-accent);
position: relative;
background: var(--wt-color-bg-elevated);
margin: 1rem 0;
p {
margin: 0;
}
}
// ============================================================================
// Tables - Scrollable like code blocks
// ============================================================================
// Tables use display: block + overflow-x: auto for horizontal scrolling within
// the content area. This prevents tables from breaking out of the container.
// border-collapse: separate + overflow: clip on inner tbody handles border-radius.
.content > table {
display: block;
overflow-x: auto;
width: fit-content;
max-width: 100%;
border-collapse: separate;
border-spacing: 0;
margin: 1rem 0;
border-radius: var(--wt-radius-md);
border: 1px solid var(--wt-color-border-subtle);
th, td {
border: 1px solid var(--wt-color-border-subtle);
border-top: none;
border-left: none;
padding: 0.6rem 0.875rem;
text-align: left;
vertical-align: top;
}
// Remove right border on last column (table border handles it)
th:last-child, td:last-child {
border-right: none;
}
// Remove bottom border on last row (table border handles it)
tr:last-child td {
border-bottom: none;
}
th {
background-color: var(--wt-color-bg-soft);
font-size: 0.8rem;
font-weight: 600;
color: var(--wt-color-text-muted);
text-transform: uppercase;
letter-spacing: 0.03em;
}
td {
font-size: 0.9rem;
}
// Prevent inline code from wrapping (paths, commands)
td code {
white-space: nowrap;
}
// But allow multiline code blocks in tables to wrap
td pre code {
white-space: pre;
}
// Plain multiline code without block styling
td code.multiline {
white-space: pre;
display: block;
}
td:first-child {
font-weight: 550;
color: var(--wt-color-text);
}
}
// ============================================================================
// TOC / Sidebar
// ============================================================================
.toc {
width: 220px;
flex-shrink: 0;
}
.toc-sticky {
position: sticky;
top: calc(var(--wt-header-height) + var(--wt-main-padding-top));
box-sizing: border-box;
border-radius: var(--wt-radius-md);
background-color: var(--wt-color-bg-elevated);
border: 1px solid var(--wt-color-border-subtle);
border-top: 3px solid var(--wt-color-accent);
padding: 0.75rem 0 1rem;
// iOS jank fix: --vh-full set by JS, fallback to lvh. See base.html.
max-height: calc(var(--vh-full, 100lvh) - var(--wt-header-height) - var(--wt-main-padding-top) - 20px);
overflow-y: auto;
overscroll-behavior: contain;
}
.toc-group-label {
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--wt-color-text-soft);
padding: 0.6rem 0.45rem 0.2rem;
margin: 0.5rem 0.4rem 0;
&:first-child {
margin-top: 0;
}
}
.toc-item {
padding: 0;
margin: 0 0.4rem;
a {
display: block;
padding: 0.55rem 0.5rem;
border-radius: var(--wt-radius-sm);
font-size: 0.8rem;
color: var(--wt-color-text-muted);
transition: color 150ms, background 150ms;
&:hover {
background: var(--wt-color-bg-soft);
color: var(--wt-color-text);
}
&.active {
border-left: 3px solid var(--wt-color-accent);
background: var(--wt-color-accent-soft);
color: var(--wt-color-text);
padding-left: calc(0.5rem - 3px);
}
}
}
.toc-item-child {
padding: 0;
margin: 0 0.4rem;
a {
font-size: 0.75rem;
color: var(--wt-color-text-soft);
padding: 0.2rem 0.8rem 0.2rem 1.35rem;
border-radius: var(--wt-radius-sm);
display: block;
transition: color 150ms, background 150ms;
&:hover {
color: var(--wt-color-text-muted);
background: var(--wt-color-bg-soft);
}
}
&.nested {
a {
font-size: 0.7rem;
padding-left: 1.95rem;
}
}
// H1 entries in TOC - section markers
// Distinguished by size, weight, and spacing from H2 items
&.toc-h1 {
margin-top: 0.5rem;
a {
font-size: 0.8rem;
font-weight: 600;
color: var(--wt-color-text-muted);
&:hover {
color: var(--wt-color-text);
background: var(--wt-color-bg-soft);
}
}
}
// H2s under H1s - same alignment as standalone H2s
&.toc-h2-under-h1 {
// No extra indent - aligns with standalone H2s
}
}
// ============================================================================
// Page Navigation
// ============================================================================
.page-nav {
display: flex;
justify-content: space-between;
margin-top: 3rem;
padding-top: 1.5rem;
border-top: 1px solid var(--wt-color-border-subtle);
a {
color: var(--wt-color-accent);
font-weight: 500;
padding: 0.5rem 1rem;
border-radius: var(--wt-radius-md);
transition: color 150ms, background 150ms;
&:hover {
background: var(--wt-color-accent-soft);
}
}
}
// ============================================================================
// Footer
// ============================================================================
footer {
padding: 1.5rem 0;
border-top: 1px solid var(--wt-color-border-subtle);
display: flex;
justify-content: center;
background-color: var(--wt-color-bg-soft);
}
.footer-social {
display: flex;
gap: 0.75rem;
a {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
color: var(--wt-color-text-muted);
background: var(--wt-color-bg);
border: 1px solid var(--wt-color-border-subtle);
transition: color 150ms, border-color 150ms, background 150ms;
&:hover,
&:focus-visible {
color: var(--wt-color-text);
border-color: var(--wt-color-accent);
background: var(--wt-color-accent-soft);
}
svg {
flex-shrink: 0;
}
}
}
// ============================================================================
// Hero Section
// ============================================================================
.hero {
// Warm gradient background with subtle radial glow
background: radial-gradient(ellipse 80% 60% at 70% 40%, rgba(254, 243, 199, 0.7) 0%, transparent 60%),
radial-gradient(ellipse 50% 40% at 30% 70%, rgba(251, 243, 219, 0.5) 0%, transparent 50%),
var(--wt-color-bg-soft);
// iOS jank fix: --vh-full set by JS, fallback to lvh. See base.html.
height: calc(var(--vh-full, 100lvh) - var(--wt-header-height) - env(safe-area-inset-top, 0px));
max-height: calc(var(--vh-full, 100lvh) - var(--wt-header-height) - env(safe-area-inset-top, 0px));
padding: 4rem 40px 3rem;
position: relative;
display: flex;
align-items: center;
justify-content: space-evenly;
overflow: hidden;
box-sizing: border-box;
// Ensure flex children respect container bounds
> * {
flex-shrink: 1;
min-height: 0;
}
.hero-image {
// iOS jank fix: --vh-full set by JS, fallback to lvh. See base.html.
max-height: calc(var(--vh-full, 100lvh) * 0.55);
width: auto;
aspect-ratio: 1;
object-fit: contain;
flex-shrink: 1;
// Subtle glow behind the logo
filter: drop-shadow(0 8px 24px rgba(217, 119, 6, 0.15));
transition: filter 300ms, transform 300ms;
&:hover {
filter: drop-shadow(0 12px 32px rgba(217, 119, 6, 0.25));
transform: scale(1.02);
}
}
// Collapse when empty (subpages don't have hero content)
&:not(:has(*)) {
display: none;
}
.heading-text {
font-size: 2.5rem;
font-weight: 650;
letter-spacing: -0.02em;
color: var(--wt-color-text);
}
.title-text {
font-size: 1.25rem;
font-weight: 400;
color: var(--wt-color-text-muted);
max-width: 35ch;
}
.explore-more {
position: absolute;
bottom: 3.5rem;
left: 50%;
transform: translateX(-50%);
color: var(--wt-color-text-muted);
cursor: pointer;
transition: color 150ms;
animation: float 3s ease-in-out infinite;
&:hover {
color: var(--wt-color-text);
animation-play-state: paused;
}
}
}
@keyframes float {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-6px); }
}
// Dark mode hero adjustments
@media (prefers-color-scheme: dark) {
.hero {
background: radial-gradient(ellipse 80% 60% at 70% 40%, rgba(245, 158, 11, 0.08) 0%, transparent 60%),
radial-gradient(ellipse 50% 40% at 30% 70%, rgba(139, 115, 85, 0.06) 0%, transparent 50%),
var(--wt-color-bg-soft);
.hero-image {
filter: drop-shadow(0 8px 24px rgba(245, 158, 11, 0.2));
&:hover {
filter: drop-shadow(0 12px 32px rgba(245, 158, 11, 0.3));
}
}
}
}
// Primary button
.button {
display: inline-block;
background: var(--wt-color-accent);
color: white;
padding: 0.6rem 1.5rem;
border-radius: var(--wt-radius-pill);
font-weight: 600;
font-size: 1rem;
border: none;
cursor: pointer;
transition: background 150ms, box-shadow 150ms;
box-shadow: 0 2px 4px var(--wt-shadow-accent);
&:hover {
background: var(--wt-color-accent-strong);
box-shadow: 0 4px 12px var(--wt-shadow-accent-strong);
}
&:active {
box-shadow: 0 1px 2px var(--wt-shadow-accent);
}
}
// Reset button styles for non-button buttons
button.explore-more {
background: none;
border: none;
font: inherit;
}
// ============================================================================
// Lists
// ============================================================================
ul, ol {
padding-left: 1.5rem;
margin-top: 0.5rem;
}
ul > li, ol > li {
padding: 0.15rem 0;
color: var(--wt-color-text);
}
ul > li::marker {
color: var(--wt-color-accent);
}
// ============================================================================
// Badges — status labels (experimental, deprecated, etc.)
// ============================================================================
// Experimental badge — empty span, text via ::after so it doesn't affect
// Zola's heading slug generation or page TOC entries.
.badge-experimental {
display: inline-block;
vertical-align: 0.15em;
white-space: nowrap;
&::after {
content: "EXPERIMENTAL";
font-size: 0.65rem;
font-weight: 600;
letter-spacing: 0.04em;
color: var(--wt-color-text-soft);
border: 1px solid var(--wt-color-border-subtle);
border-radius: var(--wt-radius-pill);
padding: 0.05rem 0.5rem;
line-height: 1.4;
}
}
// Badge after heading — generated on a separate line so Zola's anchor link
// doesn't wrap it. The badge lands in a <p> (CommonMark wraps inline HTML);
// collapse that <p> to inline so it flows on the heading's line.
:is(h1, h2, h3, h4):has(+ p > .badge-experimental:only-child) {
display: inline-block;
}
:is(h1, h2, h3, h4) + p:has(> .badge-experimental:only-child) {
display: inline;
margin: 0;
}
// ============================================================================
// Figures
// ============================================================================
figure {
margin: 1.5rem 0;
}
figcaption {
text-align: center;
font-size: 0.9rem;
color: var(--wt-color-text-muted);
margin-top: 0.5rem;
}
// ============================================================================
// Responsive
// ============================================================================
@media screen and (max-width: 1024px) {
:root {
--wt-main-padding-top: 30px;
}
main {
padding: var(--wt-main-padding-top) 40px;
gap: 1.5rem;
}
.content {
max-width: 100%;
padding: 1.5rem 24px;
}
}
// ============================================================================
// Mobile Menu
// Z-index: overlay(199) < menu(200) < header(201)
// ============================================================================
.mobile-menu-toggle {
display: none;
align-items: center;
justify-content: center;
background: none;
border: none;
padding: 0.5rem;
margin-right: auto;
cursor: pointer;
color: var(--wt-color-text);
transition: color 150ms;
-webkit-tap-highlight-color: transparent;
&:hover {
color: var(--wt-color-accent);
}
.close-icon {
display: none;
}
&[aria-expanded="true"] {
.menu-icon {
display: none;
}
.close-icon {
display: block;
}
}
}
.mobile-menu-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 199;
opacity: 0;
transition: opacity 200ms ease;
&.active {
display: block;
opacity: 1;
}
}
.mobile-menu {
display: none;
position: fixed;
top: calc(var(--wt-header-height) + env(safe-area-inset-top, 0px));
left: 0;
width: min(260px, 70vw);
// iOS jank fix: --vh-full set by JS, fallback to lvh. See base.html.
height: calc(var(--vh-full, 100lvh) - var(--wt-header-height) - env(safe-area-inset-top, 0px));
background: var(--wt-color-bg-elevated);
border-right: 1px solid var(--wt-color-border-subtle);
z-index: 200;
transform: translateX(-100%);
transition: transform 250ms ease;
overflow-y: auto;
overscroll-behavior: contain;
&.active {
display: block;
transform: translateX(0);
}
}
.mobile-menu-content {
padding: 1rem 0.75rem 2rem;
}
.mobile-menu-section {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.mobile-nav-item {
display: block;
padding: 0.6rem 0.75rem;
font-size: 0.95rem;
font-weight: 500;
color: var(--wt-color-text);
border-radius: var(--wt-radius-sm);
transition: background 150ms, color 150ms;
&:hover {
background: var(--wt-color-bg-soft);
}
}
.mobile-menu-divider {
height: 1px;
background: var(--wt-color-border-subtle);
margin: 1rem 0;
}
.mobile-menu-toc {
gap: 0;
}
.mobile-toc-group {
font-size: 0.65rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--wt-color-text-soft);
padding: 0.6rem 0.75rem 0.2rem;
margin-top: 0.4rem;
&:first-child {
margin-top: 0;
}
}
.mobile-toc-item {
display: block;
padding: 0.5rem 0.75rem;
font-size: 0.85rem;
color: var(--wt-color-text-muted);
border-radius: var(--wt-radius-sm);
transition: background 150ms, color 150ms;
&:hover {
background: var(--wt-color-bg-soft);
color: var(--wt-color-text);
}
}
// Prevent body scroll when mobile menu is open
body.mobile-menu-open {
overflow: hidden;
}
@media screen and (max-width: 768px) {
:root {
--wt-header-height: 50px;
--wt-main-padding-top: 20px;
}
body {
font-size: 16px;
}
header {
height: calc(var(--wt-header-height) + env(safe-area-inset-top, 0px));
padding: 10px 20px;
padding-top: calc(env(safe-area-inset-top, 0px) + 10px);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
// Hide desktop nav on mobile
header nav {
display: none;
}
main {
padding: var(--wt-main-padding-top);
flex-direction: column;
}
.content {
padding: 1rem 16px;
border-radius: var(--wt-radius-lg);
}
h1, .heading-text {
font-size: 1.5rem;
}
h2 {
font-size: 1.25rem;
}
.hero {
height: calc(var(--vh-full, 100lvh) - var(--wt-header-height) - env(safe-area-inset-top, 0px));
padding: 2rem 20px;
flex-direction: column;
gap: 2rem;
.heading-text {
font-size: 2rem;
}
}
.toc {
display: none;
}
.mobile-menu-toggle {
display: flex;
}
}
// ============================================================================
// View Transitions (smooth page navigation)
// ============================================================================
@view-transition {
navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 50ms;
}
// Freeze focused search box during transition - no animation, just cross-fade
::view-transition-old(search-frozen),
::view-transition-new(search-frozen) {
animation: none;
}
// ============================================================================
// Transitions & Accessibility
// ============================================================================
button, .nav-item {
transition: color 150ms, background 150ms, box-shadow 150ms;
}
// Focus states
a:focus-visible,
button:focus-visible,
input:focus-visible {
outline: 2px solid var(--wt-color-accent);
outline-offset: 2px;
}
// Reduce motion for users who prefer it
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none !important;
}
}
// ============================================================================
// Micro-interactions
// ============================================================================
// Search - subtle glow on focus
#userinput:focus {
box-shadow: 0 0 0 3px var(--wt-shadow-accent);
}
// Content links - animated underline flourish on hover
// Permanent underline via text-decoration; ::after adds animated thickening
.content a:not(.button):not(.heading-anchor):not(.zola-anchor) {
position: relative;
&::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 0;
height: 2px;
background: var(--wt-color-link);
transition: width 200ms ease-out;
}
&:hover::after {
width: 100%;
}
}
// .button shadows defined in Hero Section
// Custom scrollbar (webkit browsers)
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--wt-color-border-subtle);
border-radius: var(--wt-radius-sm);
&:hover {
background: var(--wt-color-text-soft);
}
}
// Firefox scrollbar
* {
scrollbar-width: thin;
scrollbar-color: var(--wt-color-border-subtle) transparent;
}
// Custom text selection
::selection {
background: var(--wt-color-accent-soft);
color: var(--wt-color-text);
}
// Nav item hover underlines
header nav .nav-item {
position: relative;
&::after {
content: "";
position: absolute;
left: 0;
bottom: -2px;
width: 0;
height: 2px;
background: var(--wt-color-accent);
transition: width 200ms ease-out;
}
&:hover::after {
width: 100%;
}
}
// TOC hover defined in .toc-item a:hover
// Logo hover effect
header .logo:hover img {
filter: drop-shadow(0 0 8px var(--wt-shadow-accent-strong));
transition: filter 200ms ease;
}
// button.explore-more uses .hero .explore-more animation (float keyframes)
// ============================================================================
// Dark Mode Adjustments
// ============================================================================
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
}
#suggestions {
.search-title b,
.search-excerpt b {
color: var(--wt-color-accent);
}
}
}
// ============================================================================
// Print Styles
// ============================================================================
@media print {
// Hide navigation elements
header,
footer,
.toc,
.hero,
.mobile-menu,
.mobile-menu-overlay,
.mobile-menu-toggle,
.code-copy-btn,
.page-nav {
display: none !important;
}
// Reset layout
body {
background: white;
color: black;
font-size: 12pt;
}
main {
display: block;
padding: 0;
}
.content {
max-width: 100%;
padding: 0;
border: none;
box-shadow: none;
background: transparent;
}
// Improve link visibility
.content a {
color: black;
text-decoration: underline;
&[href^="http"]::after {
content: " (" attr(href) ")";
font-size: 0.8em;
color: #666;
}
}
// Code blocks - keep together, remove decorative elements
// Use !important to override dark mode variables that might bleed through
.content pre,
.terminal {
border: 1px solid #ccc !important;
box-shadow: none !important;
page-break-inside: avoid;
background: #f5f5f5 !important;
}
// Tables
.content > table {
page-break-inside: avoid;
}
// Headings - keep with following content
h1, h2, h3, h4, h5, h6 {
page-break-after: avoid;
}
// Images
img {
max-width: 100%;
page-break-inside: avoid;
}
}