6
1
Fork 0

more updates

pull/1/head
Antonio De Lucreziis 11 months ago
parent b808dc93e7
commit cf38b8710a

@ -1 +1,242 @@
# Poisson Blog Template
An Astro-based academic blog template designed for the PHC (Dipartimento di Matematica) at University of Pisa. This template provides a clean, mathematical content-friendly platform for sharing academic posts, notes, and research materials.
## Features
- ✨ Built with [Astro](https://astro.build/) for fast, static site generation
- 📝 Support for Markdown and MDX content with mathematical expressions
- 🎨 Multiple customizable themes
- 🏷️ Tag-based post organization
- 📚 Dedicated sections for posts and notes
- 🔍 SEO-friendly structure
- 📱 Responsive design
## Available Themes
The template includes several pre-built themes located in `src/themes/`:
- **base.css** - Clean, minimal base theme
- **colorful.css** - Vibrant, colorful theme
- **modern.css** - Contemporary design with modern styling
- **mono.css** - Monochromatic, minimalist theme
- **sober.css** - Professional, academic-focused theme
To change themes, modify the CSS import in `src/layouts/Base.astro`.
## Project Structure
```
/
├── public/
│ ├── favicon.svg
│ └── materiale/ # Static files and documents
├── src/
│ ├── components/ # Reusable Astro components
│ ├── layouts/ # Page layouts
│ ├── pages/
│ │ ├── index.astro # Homepage
│ │ ├── appunti/ # Notes section
│ │ └── posts/ # Blog posts
│ ├── themes/ # CSS theme files
│ └── config.ts # Site configuration
├── astro.config.mjs # Astro configuration
└── package.json
```
## Getting Started
1. **Clone or download this template**
```bash
git clone https://git.phc.dm.unipi.it/phc/poisson-template-astro.git
cd poisson-template-astro
```
2. **Install dependencies:**
```bash
npm install
# or
bun install
```
3. **To edit the site locally:**
```bash
npm run dev
```
4. **Edit the configuration:**
- Update `src/config.ts` with your information
- Modify the site title and other settings
5. **Add your content:**
- Create posts in `src/pages/posts/`
- Add notes in `src/pages/appunti/`
- Include any static files in `public/materiale/`
## Content Creation
### Blog Posts
Create new markdown posts in `src/pages/posts/` with the following frontmatter:
```markdown
---
title: 'Your Post Title'
description: 'Brief description of the post'
tags: ['tag1', 'tag2']
publishDate: '2025-06-08'
draft: false
---
Your content goes here...
```
### Mathematical Content
The template supports mathematical expressions using [KaTeX](https://katex.org/):
- Inline math: `$E = mc^2$`
- Display math: `$$\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}$$`
## Deployment
### Deploy to Poisson Server
The template is pre-configured for deployment to the PHC Poisson server:
1. **Build for Poisson:**
```bash
npm run build:poisson
```
2. **Update the Poisson configuration:**
- Edit the `build:poisson` script in `package.json`
- Replace `ncognome` with your actual username
- Update the site URL accordingly
3. **Upload the built files:**
- The build creates a `dist/` folder
- Upload the contents to your Poisson web directory, for example using `scp`:
```bash
scp -r dist/* ncognome@poisson.phc.dm.unipi.it:/home/ncognome/public_html/
```
or with `rsync`:
```bash
rsync -avz dist/ ncognome@poisson.phc.dm.unipi.it:/home/ncognome/public_html/
```
4. **Access your site:**
- Visit `https://poisson.phc.dm.unipi.it/~ncognome/` to see your deployed site
### Deploy to GitHub Pages
For GitHub Pages deployment, follow these steps:
1. **Configure Astro for GitHub Pages:**
Update `astro.config.mjs` to include your GitHub Pages settings:
```javascript
export default defineConfig({
site: 'https://yourusername.github.io',
base: '/your-repo-name', // Only if not deploying to yourusername.github.io
// ... other config
})
```
2. **Create GitHub Action workflow:**
Create `.github/workflows/deploy.yml`:
```yaml
name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout your repository using git
uses: actions/checkout@v4
- name: Install, build, and upload your site
uses: withastro/action@v3
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
```
3. **Enable GitHub Pages:**
- Go to your repository's **Settings** → **Pages**
- Select **GitHub Actions** as the source
- Commit and push your changes
4. **Configure for custom domain (optional):**
- Add a `CNAME` file in the `public/` directory with your domain
- Update the `site` config to use your custom domain
- Remove the `base` configuration
## Configuration Options
### Site Configuration
Edit `src/config.ts` to customize:
- Site title
- Post frontmatter types
- Other site-wide settings
### Build Scripts
- `npm run dev` - Start development server
- `npm run build` - Build for production
- `npm run build:poisson` - Build for Poisson server deployment
- `npm run preview` - Preview the built site
## Contributing
This template is designed for academic use at the University of Pisa. Feel free to customize and extend it for your needs.
## License
This template is provided as-is for educational and academic purposes.

@ -13,6 +13,9 @@ export default defineConfig({
},
markdown: {
remarkPlugins: [remarkMath],
remarkRehype: {
passThrough: ['html'],
},
shikiConfig: {
theme: 'github-light',
},

@ -1,5 +1,5 @@
{
"name": "theme-poisson-blog",
"name": "poisson-template-astro",
"type": "module",
"version": "0.0.1",
"scripts": {

@ -5,6 +5,7 @@ type Props = {
publishDate: string
description: string
url: string
tags?: string[]
}
}
@ -32,4 +33,13 @@ const { post } = Astro.props
<div class="description">
{post.description}
</div>
<div class="tags">
{
post.tags?.map(tag => (
<a href={`/posts/tags/${tag}`} class="tag">
#{tag}
</a>
))
}
</div>
</div>

@ -1,8 +1,16 @@
---
import config from '@/config'
import 'katex/dist/katex.min.css'
import '@/style.css'
import '@/themes/base.css'
import config from '@/config'
//
// Uncomment below the theme you want to use
//
import '@/themes/modern.css'
// import '@/themes/colorful.css'
// import '@/themes/mono.css'
// import '@/themes/sober.css'
---
<!doctype html>
@ -13,7 +21,7 @@ import config from '@/config'
<script>
// @ts-nocheck
// This import "katex" only on the client side, on the user's browser.
import katex from 'katex'
document.addEventListener('DOMContentLoaded', function () {
@ -24,7 +32,6 @@ import config from '@/config'
katex.render($e.textContent, $e, {
throwOnError: false,
displayMode: false,
// trust: true,
})
$s.appendChild($e.firstChild)
@ -41,7 +48,6 @@ import config from '@/config'
katex.render($e.textContent, $e, {
throwOnError: false,
displayMode: true,
// trust: true,
})
$s.appendChild($e.firstChild)
@ -72,7 +78,7 @@ import config from '@/config'
<nav>
<div class="nav-item"><a href="/">Home</a></div>
<div class="nav-item"><a href="/appunti">Appunti</a></div>
<div class="nav-item"><a href="/posts">Posts</a></div>
<div class="nav-item"><a href="/posts">Post</a></div>
</nav>
</header>

@ -2,12 +2,45 @@
import config from '@/config'
import Base from './Base.astro'
type Props = {
frontmatter: {
title: string
publishDate?: string
tags?: string[]
}
}
const { frontmatter } = Astro.props
---
<Base>
<article class="text">
<h1>{frontmatter.title}</h1>
{
frontmatter.publishDate && (
<div class="text-dimmed">
{new Date(frontmatter.publishDate)
.toLocaleDateString('it-IT', {
year: 'numeric',
month: 'long',
day: 'numeric',
})
// to Title Case
.replace(/(\w)(\w*)/g, (match, p1, p2) => p1.toUpperCase() + p2.toLowerCase())}
</div>
)
}
{
frontmatter.tags && frontmatter.tags.length > 0 ? (
<div class="tags">
{frontmatter.tags.map(tag => (
<a href={`/posts/tags/${tag}`} class="tag">
#{tag}
</a>
))}
</div>
) : null
}
<slot />
</article>
</Base>

@ -1,44 +0,0 @@
---
import Base from '@/layouts/Base.astro'
import config from '@/config'
---
<Base>
<main>
<h2>Appunti</h2>
<div>
<h3>Corso 1</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod beatae, alias vitae assumenda quia
corporis quos natus laboriosam illo consectetur. Praesentium explicabo vitae assumenda saepe impedit
commodi iusto. Enim harum perspiciatis quae ea nihil iusto saepe cum! Doloribus, ullam dolorum.
</p>
<p class="text-center">
<a href="#">Scarica</a>
</p>
</div>
<div>
<h3>Corso 2</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod beatae, alias vitae assumenda quia
corporis quos natus laboriosam illo consectetur. Praesentium explicabo vitae assumenda saepe impedit
commodi iusto. Enim harum perspiciatis quae ea nihil iusto saepe cum! Doloribus, ullam dolorum.
</p>
<p class="text-center">
<a href="#">Scarica</a>
</p>
</div>
<div>
<h3>Corso 3</h3>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod beatae, alias vitae assumenda quia
corporis quos natus laboriosam illo consectetur. Praesentium explicabo vitae assumenda saepe impedit
commodi iusto. Enim harum perspiciatis quae ea nihil iusto saepe cum! Doloribus, ullam dolorum.
</p>
<p class="text-center">
<a href="#">Scarica</a>
</p>
</div>
</main>
</Base>

@ -0,0 +1,34 @@
---
layout: '@/layouts/Post.astro'
title: Appunti
---
## Corso 1
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod beatae, alias vitae assumenda quia
corporis quos natus laboriosam illo consectetur. Praesentium explicabo vitae assumenda saepe impedit
commodi iusto. Enim harum perspiciatis quae ea nihil iusto saepe cum! Doloribus, ullam dolorum.
<p class="text-center">
<a class="button" href="/materiale/dispensa-1.pdf">Scarica</a>
</p>
## Corso 2
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod beatae, alias vitae assumenda quia
corporis quos natus laboriosam illo consectetur. Praesentium explicabo vitae assumenda saepe impedit
commodi iusto. Enim harum perspiciatis quae ea nihil iusto saepe cum! Doloribus, ullam dolorum.
<p class="text-center">
<a class="button" href="/materiale/dispensa-1.pdf">Scarica</a>
</p>
## Corso 3
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod beatae, alias vitae assumenda quia
corporis quos natus laboriosam illo consectetur. Praesentium explicabo vitae assumenda saepe impedit
commodi iusto. Enim harum perspiciatis quae ea nihil iusto saepe cum! Doloribus, ullam dolorum.
<p class="text-center">
<a class="button" href="/materiale/dispensa-1.pdf">Scarica</a>
</p>

@ -0,0 +1,123 @@
---
layout: '@/layouts/Post.astro'
title: Getting Started with Astro
publishDate: 2025-06-07
description: |
Discover the power of Astro, a modern web framework that delivers
lightning-fast websites with zero JavaScript by default.
tags: ['astro', 'web-development', 'javascript', 'performance', 'static-site']
---
Astro is revolutionizing the way we build websites by prioritizing performance and developer experience. Unlike traditional frameworks that ship JavaScript by default, Astro follows a **zero-JavaScript** approach, only adding interactivity when you explicitly need it.
## What Makes Astro Special?
### 🚀 Lightning Fast Performance
Astro generates static HTML at build time, resulting in incredibly fast loading times. Your users get the content they need without waiting for JavaScript to load and execute.
### 🏝️ Islands Architecture
With Astro's unique **Islands Architecture**, you can use components from different frameworks (React, Vue, Svelte) on the same page, but they remain isolated and only hydrate when needed.
```astro
---
// You can mix and match frameworks!
import ReactCounter from './ReactCounter.jsx'
import VueCalendar from './VueCalendar.vue'
import SvelteChart from './SvelteChart.svelte'
---
<main>
<h1>My Astro Page</h1>
<ReactCounter client:load />
<VueCalendar client:visible />
<SvelteChart client:idle />
</main>
```
### 📝 Content-First Approach
Astro excels at content-heavy sites like blogs, documentation, and marketing pages. It supports:
- **Markdown** out of the box
- **MDX** for interactive content
- **Content Collections** for type-safe content management
## Key Features
> Astro combines the best of static site generation with the flexibility of modern component frameworks.
1. **Zero JavaScript by Default** - Only add JS when you need it
2. **Framework Agnostic** - Use React, Vue, Svelte, or plain HTML
3. **Built-in Optimizations** - Image optimization, CSS bundling, and more
4. **TypeScript Support** - First-class TypeScript support
5. **Excellent DX** - Fast dev server, hot reloading, and great tooling
## Mathematical Expressions
Astro works great with mathematical content too! Here's the famous Euler's identity:
$$e^{i\pi} + 1 = 0$$
This equation beautifully connects five fundamental mathematical constants:
- $e$ (Euler's number)
- $i$ (imaginary unit)
- $\pi$ (pi)
- $1$ (multiplicative identity)
- $0$ (additive identity)
## Code Example
Here's how you can create a simple Astro component:
```astro
---
// Component Script (runs at build time)
const greeting = 'Hello, Astro!'
const currentYear = new Date().getFullYear()
---
<!-- Component Template -->
<div class="greeting-card">
<h2>{greeting}</h2>
<p>Welcome to the future of web development!</p>
<footer>
<small>© {currentYear} - Built with Astro</small>
</footer>
</div>
<style>
.greeting-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
h2 {
margin-top: 0;
font-size: 2rem;
}
</style>
```
## Getting Started
Ready to try Astro? Here's how to create your first project:
<p class="text-center">
<a class="button" href="https://docs.astro.build/en/getting-started/">Start Building</a>
</p>
## Conclusion
Astro represents a paradigm shift in web development, prioritizing performance without sacrificing developer experience. Whether you're building a blog, documentation site, or marketing page, Astro provides the tools you need to create fast, modern websites.
The combination of static generation, islands architecture, and framework flexibility makes Astro an excellent choice for your next project. Give it a try and experience the difference!
---
_Happy coding! 🚀_

@ -11,6 +11,9 @@ const posts = import.meta.glob<MarkdownInstance<PostFrontmatter>>('./*.md', { ea
<Base>
<main>
<h1>Archivio Post</h1>
<p>
<a href="/posts/tags" class="forward-link">Vai all'Archivio Tag →</a>
</p>
<div class="card-list">
{
Object.values(posts)

@ -0,0 +1,96 @@
---
import Base from '@/layouts/Base.astro'
import PostCard from '@/components/PostCard.astro'
import type { MarkdownInstance } from 'astro'
import type { PostFrontmatter } from '@/config'
export async function getStaticPaths() {
const posts = import.meta.glob<MarkdownInstance<PostFrontmatter>>('../*.md', { eager: true })
const postsArray = Object.values(posts).filter(post => !post.frontmatter.draft)
// Collect all unique tags
const tags = new Set<string>()
postsArray.forEach(post => {
post.frontmatter.tags?.forEach(tag => tags.add(tag))
})
// Generate paths for each tag with precomputed related tags
return Array.from(tags).map(tag => {
// Filter posts by the current tag
const taggedPosts = postsArray
.filter(post => post.frontmatter.tags?.includes(tag))
.toSorted((a, b) => {
return new Date(b.frontmatter.publishDate).getTime() - new Date(a.frontmatter.publishDate).getTime()
})
// Get all other tags from these posts for related tags
const relatedTags = new Set<string>()
taggedPosts.forEach(post => {
post.frontmatter.tags?.forEach(t => {
if (t !== tag) {
relatedTags.add(t)
}
})
})
return {
params: { tag },
props: {
tag,
relatedTags: Array.from(relatedTags).sort(),
taggedPosts,
},
}
})
}
const { tag, taggedPosts, relatedTags } = Astro.props
---
<Base>
<main>
<h2>Post con tag <a href={`/posts/tags/${tag}`}>#{tag}</a></h2>
<p>
{taggedPosts.length} post{taggedPosts.length !== 1 ? 's' : ''} trovato{taggedPosts.length !== 1 ? 'i' : ''}.
<a href="/posts/tags" class="back-link">← Torna a tutti i tag</a>
</p>
{
taggedPosts.length > 0 ? (
<div class="card-list">
{taggedPosts.map(post => (
<PostCard
post={{
...post.frontmatter,
url: post.url ?? '#',
}}
/>
))}
</div>
) : (
<>
<p>Nessun post trovato per questo tag.</p>
<p>
<a href="/posts" class="button">
Esplora tutti i post
</a>
</p>
</>
)
}
{
relatedTags.length > 0 && (
<>
<h2>Tag correlati</h2>
<div class="tags">
{relatedTags.map(relatedTag => (
<a href={`/posts/tags/${relatedTag}`} class="tag">
#{relatedTag}
</a>
))}
</div>
</>
)
}
</main>
</Base>

@ -0,0 +1,50 @@
---
import Base from '@/layouts/Base.astro'
import type { MarkdownInstance } from 'astro'
import type { PostFrontmatter } from '@/config'
const posts = import.meta.glob<MarkdownInstance<PostFrontmatter>>('../*.md', { eager: true })
// Collect all tags and count their usage
const tagCounts = new Map<string, number>()
const tagPosts = new Map<string, Array<MarkdownInstance<PostFrontmatter>>>()
Object.values(posts)
.filter(post => !post.frontmatter.draft)
.forEach(post => {
post.frontmatter.tags?.forEach(tag => {
tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1)
if (!tagPosts.has(tag)) {
tagPosts.set(tag, [])
}
tagPosts.get(tag)!.push(post)
})
})
// Sort tags by usage count (descending) then alphabetically
const sortedTags = Array.from(tagCounts.entries()).sort((a, b) => {
if (a[1] !== b[1]) {
return b[1] - a[1] // Sort by count descending
}
return a[0].localeCompare(b[0]) // Then alphabetically
})
---
<Base>
<main>
<h1>Archivio Tag</h1>
<p>Esplora i post per argomento. Clicca su un tag per vedere tutti i post correlati.</p>
<div class="tags">
{
sortedTags.map(([tag, count]) => (
<a href={`/posts/tags/${tag}`} class="tag">
#{tag} ({count})
</a>
))
}
</div>
{sortedTags.length === 0 && <p class="no-tags">Nessun tag trovato.</p>}
</main>
</Base>

@ -1,5 +0,0 @@
@layer base, typography, components, utilities;
/* @import url(@/themes/base.css); */
/* @import url(@/themes/colorful.css); */
@import url(@/themes/mono.css);

@ -1,14 +1,4 @@
:root {
--heading-base-size: 18px;
--heading-scale-factor: 1.33;
}
@media screen and (max-width: 768px) {
:root {
--heading-base-size: 16px;
--heading-scale-factor: 1.25;
}
}
@layer base, typography, component, page, utility;
@layer base {
*,
@ -21,6 +11,9 @@
html,
body {
padding: 0;
margin: 0;
min-height: 100%;
font-size: 16px;
@ -31,12 +24,6 @@
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Inter', 'Open Sans',
'Helvetica Neue', sans-serif;
}
body {
background: var(--bg, #fff);
padding: 0;
margin: 0;
}
}
@layer typography {
@ -44,13 +31,40 @@
color: var(--text-fg, #333);
}
main,
article {
max-width: 52rem;
margin: 9rem auto;
> * {
margin: 1rem 0;
}
/* Responsive main/article styles */
@media (max-width: 1024px) and (min-width: 769px) {
max-width: 90%;
padding: 0 1rem;
}
@media (max-width: 768px) {
margin-top: 6rem;
padding: 0 1rem;
max-width: none;
}
@media (max-width: 480px) {
margin-top: 2rem;
padding: 0 0.75rem;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1;
line-height: 1.25;
margin-top: 0.75em;
@media screen and (max-width: 768px) {
@ -104,334 +118,12 @@
}
}
@layer components {
blockquote {
padding: 0.5rem 1rem;
border-left: var(--blockquote-border, 4px solid #ccc);
background: var(--blockquote-bg, #f9f9f9);
font-style: italic;
border-top-right-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
}
a {
color: var(--link-color, #007bff);
text-decoration: none;
&:hover,
&:focus {
text-decoration: 2px solid underline;
}
}
pre:not(:has(.katex)),
code {
font-family: 'Courier New', Courier, monospace;
background: var(--code-bg, #f5f5f5) !important;
border-radius: 0.5rem;
font-size: 95%;
}
pre:not(:has(.katex)) {
padding: 0.5rem;
line-height: 1.35;
}
header {
width: 100%;
max-width: 60rem;
position: absolute;
top: 1rem;
left: 50%;
transform: translateX(-50%);
display: grid;
grid-template-columns: auto 1fr auto auto;
align-items: center;
border: var(--header-border, 1px solid #ccc);
border-radius: var(--header-border-radius, 1rem);
padding: var(--header-padding, 0.5rem);
> h1 {
justify-self: start;
display: grid;
place-content: center;
font-size: 1.5rem;
font-weight: 600;
margin: 0;
padding: 0 0.5rem;
> a {
color: inherit;
text-decoration: none;
}
}
/* Hide hamburger menu elements on desktop */
.hamburger-toggle {
display: none;
}
.hamburger-icon {
display: none;
flex-direction: column;
cursor: pointer;
padding: 0.5rem;
gap: 0.25rem;
span {
width: 1.5rem;
height: 0.125rem;
background-color: var(--text-fg, #333);
transition: all 0.3s ease;
border-radius: 0.125rem;
}
}
> nav {
justify-self: end;
display: grid;
grid-auto-flow: column;
gap: 1rem;
> .nav-item {
display: grid;
> a {
text-decoration: none;
color: inherit;
font-weight: 500;
border-radius: 0.5rem;
padding: 0.5rem 1rem;
&:hover,
&:focus {
/* text-decoration: 2px solid underline; */
background-color: var(--nav-hover-bg-color, #f0f0f0);
}
}
}
}
/* Responsive header styles */
@media (max-width: 1024px) and (min-width: 769px) {
max-width: 90%;
margin: 0 auto;
}
@media (max-width: 768px) {
position: fixed;
top: 0;
left: 0;
right: 0;
transform: none;
max-width: none;
width: 100%;
border-radius: 0;
border: none;
border-bottom: var(--header-border, 1px solid #ccc);
background-color: var(--background-color, #fff);
z-index: 1000;
grid-template-columns: auto 1fr auto;
padding: 1rem;
> h1 {
font-size: 1.25rem;
padding: 0;
}
/* Show hamburger icon on mobile */
.hamburger-icon {
display: flex;
z-index: 1001;
}
/* Animate hamburger icon when menu is open */
.hamburger-toggle:checked + .hamburger-icon span:nth-child(1) {
transform: rotate(45deg) translate(0.15rem, 0.375rem);
}
.hamburger-toggle:checked + .hamburger-icon span:nth-child(2) {
opacity: 0;
}
.hamburger-toggle:checked + .hamburger-icon span:nth-child(3) {
transform: rotate(-45deg) translate(0.15rem, -0.375rem);
}
/* Mobile navigation */
> nav {
position: fixed;
top: 0;
right: -100%;
width: 80%;
max-width: 300px;
height: 100vh;
background-color: var(--background-color, #fff);
border-left: var(--header-border, 1px solid #ccc);
transition: right 0.3s ease;
z-index: 999;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: 0;
padding-top: 54px;
> .nav-item {
display: block;
border-bottom: var(--header-border, 1px solid #ccc);
&:first-child {
border-top: var(--header-border, 1px solid #ccc);
}
> a {
display: block;
padding: 1rem 1.5rem;
border-radius: 0;
font-size: 1.1rem;
&:hover,
&:focus {
background-color: var(--nav-hover-bg-color, #f0f0f0);
}
}
}
}
/* Show navigation when checkbox is checked */
.hamburger-toggle:checked ~ nav {
right: 0;
}
/* Overlay when menu is open */
.hamburger-toggle:checked::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 998;
}
}
@media (max-width: 480px) {
padding: 0.75rem;
> h1 {
font-size: 1.1rem;
}
> nav {
width: 90%;
max-width: none;
}
}
}
main,
article {
max-width: 52rem;
margin: 9rem auto;
/* Responsive main/article styles */
@media (max-width: 1024px) and (min-width: 769px) {
max-width: 90%;
padding: 0 1rem;
}
@media (max-width: 768px) {
margin-top: 6rem;
padding: 0 1rem;
max-width: none;
}
@media (max-width: 480px) {
margin-top: 5rem;
padding: 0 0.75rem;
}
}
.card {
display: grid;
grid-auto-flow: row;
gap: 0.5rem;
padding: 1rem;
border: var(--header-border, 1px solid #ccc);
border-radius: 0.5rem;
background: var(--card-bg, #fff);
.title {
font-size: 1.25rem;
font-weight: 600;
}
.date {
font-size: 0.875rem;
color: var(--text-fg-dimmed, #666);
}
.description {
font-size: 1rem;
color: var(--text-fg, #333);
}
&:hover {
background: var(--card-hover-bg, #f0f0f0);
}
@media (max-width: 480px) {
padding: 0.75rem;
}
}
.card-list {
display: grid;
grid-auto-flow: row;
gap: 1rem;
margin: 1rem 0;
}
.jumbotron {
height: 50vh;
display: grid;
place-content: center;
@layer utility {
.text-center {
text-align: center;
}
p {
max-width: 40ch;
}
/* Responsive jumbotron */
@media (max-width: 768px) {
height: 40vh;
padding: 0 1rem;
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 3));
}
h2 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
}
}
@media (max-width: 480px) {
height: 35vh;
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
}
}
.text-dimmed {
opacity: 0.7;
}
}

@ -54,72 +54,7 @@
}
}
@layer typography {
body {
color: var(--text-fg, #333);
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1;
margin-top: 0.75em;
@media screen and (max-width: 768px) {
margin-top: 1em;
}
}
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 5));
font-weight: 600;
}
h2 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 4));
font-weight: 600;
}
h3 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 3));
font-weight: 600;
}
h4 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
font-weight: 600;
}
h5 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 1));
font-weight: 600;
}
h6 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 0));
font-weight: 600;
}
p,
ul,
ol,
blockquote,
li,
pre,
table,
figure {
margin: 1rem 0;
}
ul,
ol {
padding-left: 1.5rem;
}
ol {
list-style-type: lower-roman;
}
}
@layer components {
@layer component {
blockquote {
padding: 0.5rem 1rem;
border-left: var(--blockquote-border, 4px solid #ccc);
@ -141,14 +76,14 @@
}
}
pre:not(:has(.katex)),
pre:not(:has(.math-inline, .math-display, .katex)),
code {
font-family: 'Courier New', Courier, monospace;
border-radius: 0.5rem;
font-size: 95%;
}
pre:not(:has(.katex)) {
pre:not(:has(.math-inline, .math-display, .katex)) {
padding: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #cbd5e0;
@ -411,29 +346,6 @@
}
}
main,
article {
max-width: 52rem;
margin: 9rem auto;
/* Responsive main/article styles */
@media (max-width: 1024px) and (min-width: 769px) {
max-width: 90%;
padding: 0 1rem;
}
@media (max-width: 768px) {
margin-top: 6rem;
padding: 0 1rem;
max-width: none;
}
@media (max-width: 480px) {
margin-top: 5rem;
padding: 0 0.75rem;
}
}
.card {
display: grid;
grid-auto-flow: row;
@ -531,4 +443,110 @@
}
}
}
.button {
display: inline-block;
padding: 0.75rem 1.5rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
color: #ffffff;
border: none;
border-radius: 0.75rem;
text-decoration: none;
font-family: inherit;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow:
0 4px 15px rgba(102, 126, 234, 0.3),
0 2px 8px rgba(118, 75, 162, 0.2);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0.1) 50%,
transparent 100%
);
transition: left 0.3s ease;
}
&:hover,
&:focus {
background: linear-gradient(135deg, #5a6fd8 0%, #6b4190 50%, #e081e9 100%);
color: #ffffff;
text-decoration: none;
transform: translateY(-2px);
box-shadow:
0 6px 20px rgba(102, 126, 234, 0.4),
0 4px 12px rgba(118, 75, 162, 0.3);
}
&:hover::before {
left: 100%;
}
&:active {
transform: translateY(-1px);
box-shadow:
0 4px 15px rgba(102, 126, 234, 0.3),
0 2px 8px rgba(118, 75, 162, 0.2);
}
}
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
display: inline-block;
padding: 0.25rem 0.75rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
font-size: 0.875rem;
font-weight: 500;
text-decoration: none;
border-radius: 0.5rem;
transition: all 0.3s ease;
box-shadow:
0 2px 8px rgba(102, 126, 234, 0.2),
0 1px 4px rgba(118, 75, 162, 0.1);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
transition: left 0.3s ease;
z-index: -1;
}
&:hover,
&:focus {
color: #ffffff;
transform: translateY(-1px);
box-shadow:
0 4px 12px rgba(102, 126, 234, 0.3),
0 2px 6px rgba(118, 75, 162, 0.2);
}
&:hover::before {
left: 0;
}
}
}

@ -0,0 +1,381 @@
:root {
--heading-base-size: 18px;
--heading-scale-factor: 1.33;
}
@media screen and (max-width: 768px) {
:root {
--heading-base-size: 16px;
--heading-scale-factor: 1.25;
}
}
@layer base {
body {
background: var(--bg, #fff);
}
}
@layer component {
blockquote {
padding: 0.5rem 1rem;
border-left: var(--blockquote-border, 4px solid #ccc);
background: var(--blockquote-bg, #f9f9f9);
font-style: italic;
border-top-right-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
}
a {
color: var(--link-color, #007bff);
text-decoration: none;
&:hover,
&:focus {
text-decoration: 2px solid underline;
}
}
pre:not(:has(.math-inline, .math-display, .katex)),
code {
font-family: 'Courier New', Courier, monospace;
background: var(--code-bg, #f5f5f5) !important;
border-radius: 0.5rem;
font-size: 95%;
}
pre:not(:has(.math-inline, .math-display, .katex)) {
padding: 0.5rem;
line-height: 1.35;
}
header {
width: 100%;
max-width: 60rem;
position: absolute;
top: 1rem;
left: 50%;
transform: translateX(-50%);
display: grid;
grid-template-columns: auto 1fr auto auto;
align-items: center;
border: var(--header-border, 1px solid #ccc);
border-radius: var(--header-border-radius, 1rem);
padding: var(--header-padding, 0.5rem);
> h1 {
justify-self: start;
display: grid;
place-content: center;
font-size: 1.5rem;
font-weight: 600;
margin: 0;
padding: 0 0.5rem;
> a {
color: inherit;
text-decoration: none;
}
}
/* Hide hamburger menu elements on desktop */
.hamburger-toggle {
display: none;
}
.hamburger-icon {
display: none;
flex-direction: column;
cursor: pointer;
padding: 0.5rem;
gap: 0.25rem;
span {
width: 1.5rem;
height: 0.125rem;
background-color: var(--text-fg, #333);
transition: all 0.3s ease;
border-radius: 0.125rem;
}
}
> nav {
justify-self: end;
display: grid;
grid-auto-flow: column;
gap: 1rem;
> .nav-item {
display: grid;
> a {
text-decoration: none;
color: inherit;
font-weight: 500;
border-radius: 0.5rem;
padding: 0.5rem 1rem;
&:hover,
&:focus {
/* text-decoration: 2px solid underline; */
background-color: var(--nav-hover-bg-color, #f0f0f0);
}
}
}
}
/* Responsive header styles */
@media (max-width: 1024px) and (min-width: 769px) {
max-width: 90%;
margin: 0 auto;
}
@media (max-width: 768px) {
position: fixed;
top: 0;
left: 0;
right: 0;
transform: none;
max-width: none;
width: 100%;
border-radius: 0;
border: none;
border-bottom: var(--header-border, 1px solid #ccc);
background-color: var(--background-color, #fff);
z-index: 1000;
grid-template-columns: auto 1fr auto;
padding: 1rem;
> h1 {
font-size: 1.25rem;
padding: 0;
}
/* Show hamburger icon on mobile */
.hamburger-icon {
display: flex;
z-index: 1001;
}
/* Animate hamburger icon when menu is open */
.hamburger-toggle:checked + .hamburger-icon span:nth-child(1) {
transform: rotate(45deg) translate(0.15rem, 0.375rem);
}
.hamburger-toggle:checked + .hamburger-icon span:nth-child(2) {
opacity: 0;
}
.hamburger-toggle:checked + .hamburger-icon span:nth-child(3) {
transform: rotate(-45deg) translate(0.15rem, -0.375rem);
}
/* Mobile navigation */
> nav {
position: fixed;
top: 0;
right: -100%;
width: 80%;
max-width: 300px;
height: 100vh;
background-color: var(--background-color, #fff);
border-left: var(--header-border, 1px solid #ccc);
transition: right 0.3s ease;
z-index: 999;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: 0;
padding-top: 54px;
> .nav-item {
display: block;
border-bottom: var(--header-border, 1px solid #ccc);
&:first-child {
border-top: var(--header-border, 1px solid #ccc);
}
> a {
display: block;
padding: 1rem 1.5rem;
border-radius: 0;
font-size: 1.1rem;
&:hover,
&:focus {
background-color: var(--nav-hover-bg-color, #f0f0f0);
}
}
}
}
/* Show navigation when checkbox is checked */
.hamburger-toggle:checked ~ nav {
right: 0;
}
/* Overlay when menu is open */
.hamburger-toggle:checked::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 998;
}
}
@media (max-width: 480px) {
padding: 0.75rem;
> h1 {
font-size: 1.1rem;
}
> nav {
width: 90%;
max-width: none;
}
}
}
.card {
display: grid;
grid-auto-flow: row;
gap: 0.5rem;
padding: 1rem;
border: var(--header-border, 1px solid #ccc);
border-radius: 0.5rem;
background: var(--card-bg, #fff);
.title {
font-size: 1.25rem;
font-weight: 600;
}
.date {
font-size: 0.875rem;
color: var(--text-fg-dimmed, #666);
}
.description {
font-size: 1rem;
color: var(--text-fg, #333);
}
&:hover {
background: var(--card-hover-bg, #f0f0f0);
}
@media (max-width: 480px) {
padding: 0.75rem;
}
}
.card-list {
display: grid;
grid-auto-flow: row;
gap: 1rem;
margin: 1rem 0;
}
.jumbotron {
height: 50vh;
display: grid;
place-content: center;
text-align: center;
p {
max-width: 40ch;
}
/* Responsive jumbotron */
@media (max-width: 768px) {
height: 40vh;
padding: 0 1rem;
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 3));
}
h2 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
}
}
@media (max-width: 480px) {
height: 35vh;
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
}
}
}
.button {
display: inline-block;
padding: 0.25rem 1rem;
background: var(--link-color, #007bff);
color: #ffffff;
border: none;
border-radius: 0.5rem;
text-decoration: none;
font-family: inherit;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: all 64ms ease-out;
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
&:hover,
&:focus {
background: #0056b3;
color: #ffffff;
text-decoration: none;
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
}
&:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
}
}
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
display: inline-block;
padding: 0 0.35rem;
background: #ddd;
color: #333;
font-size: 0.875rem;
font-weight: 500;
text-decoration: none;
border-radius: 0.5rem;
transition: all 0.2s ease;
&:hover,
&:focus {
text-decoration: none;
background: #bbb;
color: #222;
}
}
}

@ -4,11 +4,14 @@
--heading-base-size: 18px;
--heading-scale-factor: 1.33;
/* Minimal monospace theme colors */
/* Base Colors */
--bg: #fafafa;
--text-fg: #1a1a1a;
--text-fg-dimmed: #666666;
--link-color: #df3131; /* Cornflower Blue */
--accent-color: #df3131;
/* Specific Colors */
--link-color: var(--accent-color, #df3131);
--blockquote-border: 3px solid #333333;
--blockquote-bg: #f5f5f5;
--code-bg: #f0f0f0;
@ -47,80 +50,9 @@
font-family:
'SF Mono', Monaco, 'Inconsolata', 'Roboto Mono', 'Source Code Pro', 'Courier New', Courier, monospace;
}
body {
background: var(--bg, #fff);
padding: 0;
margin: 0;
}
}
@layer typography {
body {
color: var(--text-fg, #333);
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1;
margin-top: 0.75em;
@media screen and (max-width: 768px) {
margin-top: 1em;
}
}
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 5));
font-weight: 600;
}
h2 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 4));
font-weight: 600;
}
h3 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 3));
font-weight: 600;
}
h4 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
font-weight: 600;
}
h5 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 1));
font-weight: 600;
}
h6 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 0));
font-weight: 600;
}
p,
ul,
ol,
blockquote,
li,
pre,
table,
figure {
margin: 1rem 0;
}
ul,
ol {
padding-left: 1.5rem;
}
ol {
list-style-type: lower-roman;
}
}
@layer components {
@layer component {
blockquote {
padding: 0.5rem 1rem;
border-left: var(--blockquote-border, 4px solid #ccc);
@ -144,19 +76,19 @@
}
}
pre:not(:has(.katex)),
pre:not(:has(.math-inline, .math-display, .katex)),
code {
font-family: inherit;
background: var(--code-bg, #f5f5f5) !important;
border-radius: 0;
font-size: 95%;
border: 1px solid #e0e0e0;
}
pre:not(:has(.katex)) {
pre:not(:has(.math-inline, .math-display, .katex)) {
padding: 0.5rem;
line-height: 1.35;
overflow-x: auto;
border: 1px solid #e0e0e0;
}
header {
@ -362,29 +294,6 @@
}
}
main,
article {
max-width: 52rem;
margin: 9rem auto;
/* Responsive main/article styles */
@media (max-width: 1024px) and (min-width: 769px) {
max-width: 90%;
padding: 0 1rem;
}
@media (max-width: 768px) {
margin-top: 6rem;
padding: 0 1rem;
max-width: none;
}
@media (max-width: 480px) {
margin-top: 5rem;
padding: 0 0.75rem;
}
}
.card {
display: grid;
grid-auto-flow: row;
@ -475,4 +384,54 @@
}
}
}
.button {
display: inline-block;
padding: 0.25rem 1rem;
background: var(--bg, #fafafa);
color: var(--text-fg, #1a1a1a);
border: 2px solid var(--text-fg, #1a1a1a);
border-radius: 0;
text-decoration: none;
font-family: inherit;
font-size: 1rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
cursor: pointer;
transition: all 64ms linear;
&:hover,
&:focus {
background: var(--text-fg, #1a1a1a);
color: var(--bg, #fafafa);
text-decoration: none;
}
&:active {
transform: translateY(1px);
}
}
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
display: inline-block;
padding: 0 0.5rem;
background: hsl(from var(--accent-color, #df3131) h 75% 65%);
color: hsl(from var(--accent-color, #df3131) h 100% 100%);
font-size: 13px;
text-decoration: none;
&:hover,
&:focus {
color: var(--text-fg, #1a1a1a);
}
}
}

@ -0,0 +1,511 @@
/* Sober Theme - Clean and polished old-style with left sidebar */
:root {
--heading-base-size: 18px;
--heading-scale-factor: 1.33;
/* Sober color palette - muted, sophisticated tones */
--sidebar-bg: #2c2c2c;
--sidebar-text: #e8e8e8;
--sidebar-accent: #b8860b;
--content-bg: #fafafa;
--content-text: #333;
--border-color: #d0d0d0;
--card-bg: #ffffff;
--hover-bg: #f5f5f5;
--muted-text: #666;
--link-color: #8b4513;
--code-bg: #f8f8f8;
--blockquote-bg: #f9f7f4;
--blockquote-border: #d4a574;
}
@media screen and (max-width: 768px) {
:root {
--heading-base-size: 16px;
--heading-scale-factor: 1.25;
}
}
@layer base {
body {
background: var(--content-bg);
color: var(--content-text);
display: grid;
grid-template-columns: 250px 1fr;
min-height: 100vh;
}
/* Responsive grid adjustments */
@media (max-width: 1024px) {
body {
grid-template-columns: 220px 1fr;
}
}
@media (max-width: 768px) {
body {
display: block;
}
}
}
@layer typography {
main,
article {
grid-column: 2;
padding: 2rem 3rem;
max-width: 52rem;
margin: 0 auto;
width: 100%;
> * {
margin: 1rem 0;
}
@media (max-width: 1024px) {
padding: 2rem;
}
@media (max-width: 768px) {
grid-column: 1;
grid-row: 2;
padding: 1rem;
}
}
}
@layer component {
/* Left Sidebar Header */
header {
grid-column: 1;
background: var(--sidebar-bg);
color: var(--sidebar-text);
padding: 2rem 1.5rem;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 2rem;
> .spacer {
display: none;
}
> h1 {
font-size: 1.75rem;
font-weight: 700;
margin: 0;
padding-bottom: 1rem;
border-bottom: 2px solid var(--sidebar-accent);
text-align: center;
letter-spacing: 0.05em;
> a {
color: var(--sidebar-text);
text-decoration: none;
transition: color 0.3s ease;
&:hover {
color: var(--sidebar-accent);
}
}
}
> nav {
display: flex;
flex-direction: column;
gap: 1rem;
> .nav-item {
> a {
display: block;
color: var(--sidebar-text);
text-decoration: none;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
font-weight: 500;
font-size: 1rem;
transition: all 0.3s ease;
border: 1px solid transparent;
margin: 0.125rem 0;
font-weight: 600;
&:hover,
&:focus {
background: rgba(255, 255, 255, 0.05);
border-color: var(--sidebar-accent);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
color: var(--sidebar-accent);
}
}
}
}
/* Hide hamburger elements on desktop */
.hamburger-toggle {
display: none;
}
.hamburger-icon {
display: none;
}
/* Mobile responsive sidebar */
@media (max-width: 1024px) {
padding: 1.5rem 1rem;
}
@media (max-width: 768px) {
grid-column: 1;
grid-row: 1;
position: sticky;
top: 0;
height: 60px;
flex-direction: row;
align-items: center;
padding: 0 1rem;
gap: 1rem;
z-index: 1000;
> h1 {
font-size: 1.25rem;
padding: 0;
border: none;
text-align: left;
}
/* Hide hamburger elements on larger screens */
.hamburger-toggle {
display: none;
}
.hamburger-icon {
display: flex;
flex-direction: column;
cursor: pointer;
padding: 0.5rem;
gap: 0.25rem;
margin-left: auto;
span {
width: 1.5rem;
height: 0.125rem;
background-color: var(--sidebar-text);
transition: all 0.3s ease;
border-radius: 0.125rem;
}
}
> nav {
position: fixed;
top: 60px;
left: -100%;
width: 80%;
max-width: 300px;
height: calc(100vh - 60px);
background: var(--sidebar-bg);
transition: left 0.3s ease;
padding: 1rem;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
}
/* Show navigation when checkbox is checked */
.hamburger-toggle:checked ~ nav {
left: 0;
}
/* Animate hamburger icon */
.hamburger-toggle:checked + .hamburger-icon span:nth-child(1) {
transform: rotate(45deg) translate(0.15rem, 0.375rem);
}
.hamburger-toggle:checked + .hamburger-icon span:nth-child(2) {
opacity: 0;
}
.hamburger-toggle:checked + .hamburger-icon span:nth-child(3) {
transform: rotate(-45deg) translate(0.15rem, -0.375rem);
}
/* Overlay */
.hamburger-toggle:checked::before {
content: '';
position: fixed;
top: 60px;
left: 0;
width: 100%;
height: calc(100vh - 60px);
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
}
}
/* Typography and Content Styling */
blockquote {
padding: 1rem 1.5rem;
border-left: 4px solid var(--blockquote-border);
background: var(--blockquote-bg);
font-style: italic;
border-radius: 0 0.5rem 0.5rem 0;
margin: 1.5rem 0;
position: relative;
&::before {
content: '"';
font-size: 3rem;
color: var(--blockquote-border);
position: absolute;
top: -0.5rem;
left: 0.5rem;
font-family: Georgia, serif;
}
}
a {
color: var(--link-color);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: all 0.3s ease;
&:hover,
&:focus {
border-bottom-color: var(--link-color);
color: #654321;
}
}
pre:not(:has(.math-inline, .math-display, .katex)),
code {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
background: var(--code-bg) !important;
border-radius: 0.25rem;
font-size: 90%;
}
pre:not(:has(.math-inline, .math-display, .katex)) {
padding: 1rem;
line-height: 1.4;
overflow-x: auto;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-color);
}
code {
padding: 0.125rem 0.25rem;
}
/* Card Components */
.card {
display: grid;
grid-auto-flow: row;
gap: 1rem;
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0.5rem;
padding: 1.5rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
.title {
font-size: 1.25rem;
font-weight: 600;
color: var(--content-text);
}
.date {
font-size: 0.875rem;
color: var(--muted-text);
font-style: italic;
}
.description {
color: var(--content-text);
line-height: 1.6;
}
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border-color: var(--sidebar-accent);
}
}
.card-list {
display: grid;
gap: 1rem;
}
/* Jumbotron */
.jumbotron {
height: 60vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
background: linear-gradient(150deg, #f8f8f8 0%, #f0f0f0 100%);
border-bottom: 4px solid var(--sidebar-accent);
margin-bottom: 2rem;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 4));
font-weight: 300;
color: var(--sidebar-bg);
margin-bottom: 1rem;
letter-spacing: 0.02em;
}
p {
max-width: 45ch;
font-size: 1.125rem;
color: var(--muted-text);
line-height: 1.6;
}
@media (max-width: 768px) {
height: 40vh;
padding: 0 1rem;
}
}
/* Buttons */
.button {
display: inline-block;
padding: 0.25rem 1rem;
background: linear-gradient(135deg, var(--card-bg) 0%, #f8f8f8 100%);
color: var(--sidebar-bg);
border: 1px solid var(--border-color);
border-radius: 0.5rem;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: all 64ms ease-in;
letter-spacing: 0.025em;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
&:hover,
&:focus {
background: linear-gradient(135deg, #f0f0f0 0%, #e8e8e8 100%);
color: var(--sidebar-bg);
border-color: var(--sidebar-accent);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
}
/* Tags */
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
display: inline-block;
padding: 0rem 0.5rem;
background: var(--hover-bg);
color: var(--content-text);
font-size: 0.875rem;
font-weight: 500;
text-decoration: none;
border: 1px solid var(--border-color);
border-radius: 2rem;
transition: all 0.3s ease;
&:hover,
&:focus {
background: var(--sidebar-accent);
color: white;
border-color: var(--sidebar-accent);
transform: translateY(-1px);
}
}
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
background: var(--card-bg);
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
th,
td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--hover-bg);
font-weight: 600;
color: var(--sidebar-bg);
}
tr:hover {
background: var(--hover-bg);
}
/* Lists */
ul,
ol {
padding-left: 1.5rem;
}
li {
margin: 0.5rem 0;
}
/* Headings */
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--sidebar-bg);
font-weight: 600;
line-height: 1.3;
margin: 2rem 0 1rem 0;
}
h1 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 4));
border-bottom: 2px solid var(--sidebar-accent);
padding-bottom: 0.5rem;
}
h2 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 3));
border-bottom: 1px solid var(--border-color);
padding-bottom: 0.25rem;
}
h3 {
font-size: calc(var(--heading-base-size) * pow(var(--heading-scale-factor), 2));
}
h4 {
font-size: calc(var(--heading-base-size) * var(--heading-scale-factor));
}
h5 {
font-size: var(--heading-base-size);
}
h6 {
font-size: calc(var(--heading-base-size) * 0.9);
color: var(--muted-text);
}
}
Loading…
Cancel
Save