L.
  • Home
  • Blog
  • Projects
  • Portfolio
  • Lecture notes
    • Complexity and Information Theory 2024/2025
    • Deep Learning 2024/2025
    • Ricerca Operativa 2024/2025
    • Foundations of Neural Networks 2024/2025
    • Quantum Computing 2023/2024
    • Biologia Molecolare 2024/2025
    • Verification and Validation Techniques 2024/2025
    • Automated Reasoning 2024/2025
    • Advanced Algorithms 2023/2024
    • Artificial Intelligence 2023/2024
    • Applied Statistics 2024/2025

On this page

  • Punk Theme Implementation Plan
    • File Map
      • Task 1: Bootstrap — delete styles.css and wire custom.scss
      • Task 2: Google Fonts + Paper Grain Texture
      • Task 3: Navbar + Dropdown + Footer
      • Task 4: Title Block Banner (Hero)
      • Task 5: Headings + Body Typography (Article Pages)
      • Task 6: Listing Cards (Grid) + Tags + Bylines
      • Task 7: Table Listing (Projects Page)
      • Task 8: Callout Blocks + Code Fold Toggle
      • Task 9: Buttons + Final Polish
    • Notes for Implementer

Punk Theme Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Apply a Classic Punk / Zine aesthetic to the entire L’Underfitting Quarto blog via a single custom.scss file.

Architecture: Delete styles.css (conflicts with new theme), update _quarto.yml to load custom.scss via the Quarto SCSS theme system, then build the stylesheet component by component. No .qmd content files are touched.

Tech Stack: Quarto 1.x, SCSS (Quarto SCSS theming), Bootstrap 5 (Quarto’s base), Google Fonts (Courier Prime + Lora), system font Impact.


File Map

Action Path Responsibility
Delete styles.css Removed — conflicts with punk spec
Create custom.scss All punk styles — single source of truth
Modify _quarto.yml Point theme at custom.scss, remove css: styles.css

Task 1: Bootstrap — delete styles.css and wire custom.scss

Files: - Delete: styles.css - Create: custom.scss - Modify: _quarto.yml

Run from the project root (where _quarto.yml lives):

rm styles.css

Create custom.scss at the project root with this minimal content:

/*-- scss:defaults --*/
$body-bg: #F5F0E8;

/*-- scss:rules --*/
// Punk theme — L'Underfitting
// Rules are added in subsequent tasks.

The /*-- scss:defaults --*/ block overrides Bootstrap Sass variables (processed before Bootstrap compiles). The /*-- scss:rules --*/ block adds plain CSS rules after Bootstrap.

Find the format.html block (currently lines 71–74) and replace:

format:
  html:
    theme: cosmo
    css: styles.css
    toc: true

with:

format:
  html:
    theme: [cosmo, custom.scss]
    toc: true
quarto preview

Expected: site loads, background is #F5F0E8 (cream/newsprint). No build errors. If build fails, check that custom.scss has the correct /*-- scss:defaults --*/ section marker — Quarto requires it.


Task 2: Google Fonts + Paper Grain Texture

Files: - Modify: custom.scss

Add the Google Fonts @import as the first line of the /*-- scss:rules --*/ section (before any other rules — SCSS may warn if @import appears after other rules):

// ── Fonts ──────────────────────────────────────────────────────────────
@import url('https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400;0,600;1,400&display=swap');

// ── Paper grain texture ─────────────────────────────────────────────────
body {
  background-color: #F5F0E8;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
}
quarto preview

Expected: body still newsprint cream, fonts loading (check Network tab — fonts.googleapis.com requests). Paper grain is subtle — you may need to look closely.


Task 3: Navbar + Dropdown + Footer

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Navbar ──────────────────────────────────────────────────────────────
.navbar {
  background-color: #1A1A1A !important;
  border-bottom: 3px solid #CC2200;
}

.navbar-brand {
  font-family: Impact, 'Arial Black', sans-serif;
  font-size: 1.3rem;
  color: #F5C842 !important;
  text-transform: uppercase;
  text-shadow: 2px 2px 0 #CC2200;
  letter-spacing: 0.02em;
}

.navbar-nav .nav-link {
  font-family: 'Courier Prime', 'Courier New', monospace;
  font-size: 0.7rem;
  color: #888 !important;
  text-transform: uppercase;
  letter-spacing: 0.1em;

  &:hover {
    color: #F5C842 !important;
  }
}
// ── Navbar Dropdown ─────────────────────────────────────────────────────
.dropdown-menu {
  background-color: #1A1A1A;
  border: 1px solid #CC2200;
  border-radius: 0;

  .dropdown-item {
    font-family: 'Courier Prime', monospace;
    font-size: 0.75rem;
    color: #AAA;

    &:hover, &:focus {
      background-color: #CC2200;
      color: #fff;
    }
  }

  .dropdown-divider {
    border-top-color: #333;
  }
}
// ── Footer ──────────────────────────────────────────────────────────────
.nav-footer {
  background-color: #1A1A1A !important;
  border-top: 2px solid #CC2200;
  font-family: 'Courier Prime', monospace;
  font-size: 0.75rem;
  color: #888;

  a {
    color: #F5C842;
    text-decoration: none;

    &:hover { text-decoration: underline; }
  }
}
quarto preview

Expected: dark navbar with yellow logo and red bottom border, footer dark with red top border. Open the “Lecture notes” dropdown — should be dark panel with red border, items in Courier, hover turns red.


Task 4: Title Block Banner (Hero)

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Title Block Banner (Hero) ────────────────────────────────────────────
.quarto-title-banner {
  background: #1A1A1A !important;
  border-bottom: 3px dashed #333;
  padding: 2rem 1.5rem;
}

.quarto-title-banner .quarto-title h1 {
  font-family: Impact, 'Arial Black', sans-serif;
  font-size: 2.8rem;
  line-height: 0.95;
  color: #F5F0E8;
  text-transform: uppercase;
  letter-spacing: -0.02em;
}

.quarto-title-banner .quarto-title-meta,
.quarto-title-banner .quarto-title-meta-heading,
.quarto-title-banner .quarto-title-meta-contents {
  font-family: 'Courier Prime', monospace;
  font-size: 0.75rem;
  color: #888;
}

// Red left-border byline treatment
.quarto-title-banner .quarto-title-meta {
  border-left: 3px solid #CC2200;
  padding-left: 0.5rem;
  margin-top: 0.6rem;
}

// Category tags in hero
.quarto-title-banner .quarto-categories .quarto-category {
  font-family: Impact, sans-serif;
  font-size: 0.6rem;
  background: #CC2200;
  color: #fff;
  border: none;
  border-radius: 0;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 2px 8px;
}
quarto preview

Navigate to any blog post. Expected: dark banner with large Impact title in cream, red-bordered byline, red category tags.


Task 5: Headings + Body Typography (Article Pages)

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Headings ─────────────────────────────────────────────────────────────
h1, h2, h3, h4, h5, h6 {
  font-family: Impact, 'Arial Black', sans-serif;
  text-transform: uppercase;
  color: #1A1A1A;
}

h1 { font-size: 2.8rem; letter-spacing: -0.02em; line-height: 1; }
h2 { font-size: 1.8rem; border-bottom: 2px solid #1A1A1A; padding-bottom: 0.25rem; margin-bottom: 0.75rem; }
h3 { font-size: 1.1rem; }

// Override heading color inside the dark title banner (set in Task 4)
.quarto-title-banner h1,
.quarto-title-banner h2,
.quarto-title-banner h3 {
  color: #F5F0E8;
  border-bottom: none;
}
// ── Article body ──────────────────────────────────────────────────────────
// Target the article content column under page-layout: full.
// Quarto wraps article content in .page-body > .content (inspect rendered
// HTML to confirm the selector if styles don't apply — full layout removes
// the standard .container constraint).
.page-body .content,
article.content,
.quarto-section-identifier {
  font-family: 'Lora', Georgia, serif;
  font-size: 1rem;
  line-height: 1.75;
  color: #222;
  max-width: 680px;
  margin-left: auto;
  margin-right: auto;
}

// Links
.page-body .content a,
article.content a {
  color: #CC2200;
  text-decoration: underline;
  text-underline-offset: 2px;
}

// Blockquotes
blockquote {
  border-left: 3px solid #CC2200;
  padding-left: 0.8rem;
  font-family: 'Courier Prime', monospace;
  font-style: italic;
  color: #444;
  margin: 1rem 0;
}

// Inline code
code:not(pre code) {
  font-family: 'Courier Prime', monospace;
  background-color: #EDE8DF;
  color: #CC2200;
  padding: 0 3px;
  border-radius: 0;
}

// Code blocks
pre {
  background-color: #1A1A1A !important;
  border-left: 3px solid #CC2200;
  border-radius: 0;

  code {
    font-family: 'Courier Prime', monospace;
    color: #F5C842;
    font-size: 0.85rem;
  }
}
quarto preview

Navigate to a blog post. Expected: Impact section headings, Lora body at 1rem, Courier blockquotes with red left border, dark code blocks with yellow text. If max-width: 680px isn’t applying, open DevTools, inspect .page-body children, and identify the actual content wrapper selector — update the rule accordingly.


Task 6: Listing Cards (Grid) + Tags + Bylines

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Listing grid cards ────────────────────────────────────────────────────
.quarto-listing .list,
.quarto-listing-default {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 0;
}

.quarto-post,
.listing-item {
  border: 1px dashed #AAA;
  background: transparent;
  border-radius: 0;
  padding: 1rem;
  margin: 0;

  .listing-title a,
  h3 a {
    font-family: Impact, 'Arial Black', sans-serif;
    font-size: 1rem;
    text-transform: uppercase;
    color: #1A1A1A;
    text-decoration: none;
    line-height: 1.1;

    &:hover { color: #CC2200; }
  }

  .listing-description,
  .description {
    font-family: 'Courier Prime', monospace;
    font-size: 0.75rem;
    color: #555;
    line-height: 1.6;
    margin-top: 0.3rem;
  }
}

// Portfolio image treatment (grayscale + contrast for print feel)
.quarto-post img,
.listing-item img {
  filter: grayscale(30%) contrast(1.1);
  object-fit: cover;
}
// ── Category tags ────────────────────────────────────────────────────────
.quarto-category,
.listing-category {
  font-family: Impact, sans-serif;
  font-size: 0.6rem;
  background: #CC2200 !important;
  color: #fff !important;
  border: none;
  border-radius: 0;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 2px 8px;
}

// ── Bylines / post meta ──────────────────────────────────────────────────
.listing-date,
.listing-author,
.quarto-title-meta-contents p,
.post-metadata {
  font-family: 'Courier Prime', monospace;
  font-size: 0.72rem;
  color: #555;
  border-left: 3px solid #CC2200;
  padding-left: 0.5rem;
}
quarto preview

Navigate to blog listing and portfolio pages. Expected: dashed-border cards, Impact titles, Courier descriptions, red Impact tags, red-border bylines.


Task 7: Table Listing (Projects Page)

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Table-type listing (projects/index.qmd) ──────────────────────────────
.quarto-listing-table table {
  border-collapse: collapse;
  width: 100%;

  thead tr {
    background-color: #1A1A1A;

    th {
      font-family: Impact, sans-serif;
      font-size: 0.75rem;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      color: #F5C842;
      border: none;
      padding: 0.6rem 0.8rem;
    }
  }

  tbody tr {
    background-color: #F5F0E8;
    border-bottom: 1px dashed #AAA;

    &:hover { background-color: #EDE8DF; }

    td {
      font-family: 'Courier Prime', monospace;
      font-size: 0.8rem;
      color: #333;
      padding: 0.6rem 0.8rem;
      border: none;

      a {
        color: #CC2200;
        text-decoration: underline;
        text-underline-offset: 2px;
      }
    }
  }
}
quarto preview

Navigate to the Projects page. Expected: dark header row with yellow Impact column names, newsprint body rows with dashed separators, red links, hover darkens row.


Task 8: Callout Blocks + Code Fold Toggle

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Callout blocks ───────────────────────────────────────────────────────
.callout {
  border-left: 4px solid #CC2200 !important;
  border-right: none;
  border-top: none;
  border-bottom: none;
  border-radius: 0;
  background: #EDE8DF !important;

  .callout-title {
    font-family: Impact, sans-serif;
    font-size: 0.85rem;
    text-transform: uppercase;
    color: #1A1A1A;
    background: transparent;
  }

  .callout-icon::before {
    color: #CC2200;
  }

  // Remove per-type color backgrounds
  &.callout-note,
  &.callout-tip,
  &.callout-warning,
  &.callout-caution,
  &.callout-important {
    background: #EDE8DF !important;
    border-left-color: #CC2200 !important;
  }
}
// ── Code fold / code tools ───────────────────────────────────────────────
.code-fold-btn,
details summary {
  font-family: 'Courier Prime', monospace;
  font-size: 0.8rem;
  color: #CC2200;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
}

.code-tools-menu {
  background: #1A1A1A;
  border: 1px solid #333;

  .dropdown-item {
    color: #F5C842;
    font-family: 'Courier Prime', monospace;
    font-size: 0.75rem;

    &:hover { background-color: #CC2200; color: #fff; }
  }
}
quarto preview

Navigate to a post with a callout (e.g., any post using ::: {.callout-note}). Expected: warm beige background, red left border, Impact title. Check a post with code-fold: true — the toggle should be Courier in red.


Task 9: Buttons + Final Polish

Files: - Modify: custom.scss

Append to /*-- scss:rules --*/:

// ── Buttons ───────────────────────────────────────────────────────────────
.btn-primary {
  background-color: #CC2200;
  border-color: #CC2200;
  color: #fff;
  font-family: Impact, sans-serif;
  text-transform: uppercase;
  border-radius: 0;
  letter-spacing: 0.05em;

  &:hover {
    background-color: #A81C00;
    border-color: #A81C00;
  }
}

.btn-outline-secondary {
  border: 2px solid #1A1A1A;
  color: #1A1A1A;
  background: transparent;
  font-family: Impact, sans-serif;
  text-transform: uppercase;
  border-radius: 0;

  &:hover {
    background-color: #1A1A1A;
    color: #F5F0E8;
  }
}
// ── Table of Contents ────────────────────────────────────────────────────
#TOC {
  font-family: 'Courier Prime', monospace;
  font-size: 0.75rem;
  border-left: 3px solid #CC2200;
  padding-left: 0.8rem;

  .active {
    color: #CC2200;
    font-weight: bold;
  }

  a {
    color: #555;
    text-decoration: none;

    &:hover { color: #CC2200; }
  }
}
quarto preview

Visit each page type and verify:

Page Check
Homepage Newsprint bg, dark navbar, red border
Blog listing Dashed card borders, Impact titles, red tags
Blog post Dark hero, Lora body, Impact H2s, dark code blocks
Portfolio Card grid with image filter
Projects Dark table header, dashed rows
Any post with callout Warm beige, red left border
Any post with code-fold Courier toggle in red
Footer Dark bg, red top border
Navbar dropdown Dark panel, red border, hover red

If any rule isn’t applying, open DevTools, inspect the element, find the actual Quarto-generated class, and update custom.scss. Common issues: - !important needed to override Bootstrap specificity - Full page layout removing container — target .page-body .content children directly - Quarto version differences in class names (check rendered HTML source)


Notes for Implementer

  • SCSS section markers matter. /*-- scss:defaults --*/ = Bootstrap variable overrides (compiled before Bootstrap). /*-- scss:rules --*/ = plain CSS rules (appended after Bootstrap). Rules in defaults won’t work and vice versa.
  • !important is sometimes unavoidable against Bootstrap’s generated specificity. Use it deliberately, not everywhere.
  • The article body max-width: 680px selector is the most likely to need adjustment. Under page-layout: full, Quarto removes the standard .container column. Inspect the rendered HTML of a blog post and find the actual wrapper element around the prose content — target that.
  • Don’t touch .qmd files. All changes go in custom.scss and _quarto.yml only.
  • Quarto rebuilds the full _site/ directory. Deleting the source styles.css is enough — _site/styles.css is a build artifact that will be regenerated correctly without it.
 

Copyright 2025, Luca Simonetti