48b6d920c4
Key changes merged from svemagie/blog-eleventy-indiekit: - feat: /updated.xml feed for recently edited posts - feat: sitemap.xml generation in eleventy.after hook - feat: excludePostTypes filter for homepage section config - feat: view mode toggle (repo/type) for changelog page - feat: replyTargets config for platform-to-syndicator mapping - feat: syndication badge + linked timestamp on owner replies - perf: memoize aiPosts/aiStats/hash filters; batch unfurl pre-fetch - perf: clear eleventy-img in-memory cache between builds (OOM fix) - perf: memory profiler (logMemory) at build phases - perf: OG batch tracking (totalGenerated/batch counters) - fix: h-entry u-url absolute for IndieNews compatibility - fix: webmention platform detection in build-time templates - fix: deduplicate interactions via interactionKey - fix: reply form syndication via replyTargets (not hardcoded platforms) - fix: remove skeleton loader CSS (CLS fix) - fix: avatar dimensions 96→128 to match CSS classes - css: remove unused skeleton loader rules Local customisations preserved: - Gitea-based data files (githubActivity, githubRepos, githubStarred) - Funkwhale cover image cache copy in eleventy.after - URL fallback arrays in funkwhale/lastfm data fetchers - CONFIGURABLE cache durations (FUNKWHALE_FETCH_CACHE_DURATION etc.) - OG_CACHE_DIR naming (not cacheDir) - Our ogSlug format (plain slug, not date-prefixed) - Gruvbox design tokens (link colours, selection colours) - Unfurl manifest optimisation (skip re-fetching known URLs) - CLAUDE.md, README.md, .github/workflows (ours) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
90 lines
4.6 KiB
CSS
90 lines
4.6 KiB
CSS
/* Critical CSS — inlined in <head> for first paint */
|
|
/* Covers: layout shell, header, dark mode toggle, font display, basic typography */
|
|
|
|
*,*::before,*::after{box-sizing:border-box}
|
|
body{margin:0;font-family:"Lora","Iowan Old Style","Palatino Linotype","URW Palladio L",P052,serif;line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
|
|
|
|
/* Dark mode base — Gruvbox-inspired warm palette */
|
|
body{background-color:#fffef5;color:#282828}
|
|
.dark body{background-color:#1d2021;color:#fbf1c7}
|
|
|
|
/* Container */
|
|
.container{max-width:64rem;margin-left:auto;margin-right:auto;padding-left:1rem;padding-right:1rem}
|
|
|
|
/* Header — sticky, visible immediately */
|
|
.site-header{background-color:#fffef5;border-bottom:1px solid #d5c4a1;padding-top:1rem;padding-bottom:1rem;position:sticky;top:0;z-index:50}
|
|
.dark .site-header{background-color:#282828;border-bottom-color:#504945}
|
|
.header-container{display:flex;align-items:center;justify-content:space-between}
|
|
.site-title{font-size:1.25rem;font-weight:700;color:#282828;text-decoration:none}
|
|
.dark .site-title{color:#fbf1c7}
|
|
|
|
/* Header actions — hidden on mobile */
|
|
.header-actions{display:none}
|
|
@media(min-width:768px){.header-actions{display:flex;align-items:center;gap:1rem}}
|
|
|
|
/* Mobile menu toggle */
|
|
.menu-toggle{display:block;padding:0.5rem;border-radius:0.5rem;background:none;border:none;color:#665c54;cursor:pointer}
|
|
@media(min-width:768px){.menu-toggle{display:none}}
|
|
.dark .menu-toggle{color:#a89984}
|
|
|
|
/* Hidden utility */
|
|
.hidden{display:none!important}
|
|
[x-cloak]{display:none!important}
|
|
|
|
/* Dark mode theme toggle icons */
|
|
.theme-toggle .sun-icon{display:none}
|
|
.theme-toggle .moon-icon{display:block}
|
|
.dark .theme-toggle .sun-icon{display:block}
|
|
.dark .theme-toggle .moon-icon{display:none}
|
|
|
|
/* Main content padding */
|
|
main.container{padding-top:1.5rem;padding-bottom:1.5rem}
|
|
@media(min-width:768px){main.container{padding-top:2rem;padding-bottom:2rem}}
|
|
|
|
/* Layout with sidebar — must match Tailwind's compiled output exactly to prevent CLS */
|
|
.layout-with-sidebar{display:grid;grid-template-columns:repeat(1,minmax(0,1fr));gap:1.5rem}
|
|
@media(min-width:768px){.layout-with-sidebar{gap:2rem}}
|
|
@media(min-width:1024px){.layout-with-sidebar{grid-template-columns:repeat(3,minmax(0,1fr))}}
|
|
.main-content{min-width:0;overflow-x:hidden}
|
|
@media(min-width:1024px){.main-content{grid-column:span 2/span 2}}
|
|
/* Reserve sidebar space on desktop to prevent CLS when Alpine.js hydrates collapsible widgets */
|
|
@media(min-width:1024px){.sidebar{min-height:600px}}
|
|
|
|
/* Font faces — in critical CSS so fonts begin downloading immediately.
|
|
font-display:optional prevents FOUT/CLS: font either loads in time or fallback is kept. */
|
|
@font-face{font-family:'Inter';font-style:normal;font-display:optional;font-weight:400;src:url(/fonts/inter-latin-400-normal.woff2) format('woff2')}
|
|
@font-face{font-family:'Inter';font-style:normal;font-display:optional;font-weight:600;src:url(/fonts/inter-latin-600-normal.woff2) format('woff2')}
|
|
@font-face{font-family:'Inter';font-style:normal;font-display:optional;font-weight:700;src:url(/fonts/inter-latin-700-normal.woff2) format('woff2')}
|
|
|
|
/* Basic typography — prevent FOUT */
|
|
h1,h2,h3,h4{margin:0;line-height:1.25;font-weight:900}
|
|
a{color:#076678}
|
|
.dark a{color:#83a598}
|
|
|
|
/* Prevent flash of unstyled content for nav */
|
|
.site-nav{display:flex;align-items:center;gap:1rem}
|
|
.site-nav>a,.site-nav .nav-dropdown-trigger{color:#665c54;text-decoration:none;padding-top:0.5rem;padding-bottom:0.5rem}
|
|
.dark .site-nav>a,.dark .site-nav .nav-dropdown-trigger{color:#a89984}
|
|
|
|
/* Prevent FOUC — constrain images and SVG icons before Tailwind loads */
|
|
img{max-width:100%;height:auto}
|
|
svg:not(:root):not([width]){width:1.25rem;height:1.25rem}
|
|
|
|
/* Focus indicators — visible in critical CSS before Tailwind loads */
|
|
a:focus-visible{outline:2px solid #076678;outline-offset:2px;border-radius:2px}
|
|
.dark a:focus-visible{outline-color:#83a598}
|
|
button:focus-visible,[type="button"]:focus-visible{outline:2px solid #076678;outline-offset:2px;border-radius:4px}
|
|
.dark button:focus-visible,.dark [type="button"]:focus-visible{outline-color:#83a598}
|
|
|
|
/* Skip link */
|
|
.skip-link{position:absolute;top:-100%;left:0;z-index:100;background:#076678;color:#fbf1c7;padding:0.5rem 1rem;font-weight:600;text-decoration:none}
|
|
.skip-link:focus{top:0;outline:none}
|
|
|
|
/* Selection colors — Gruvbox orange highlight */
|
|
::selection{background:#d65d0e;color:#fbf1c7}
|
|
.dark ::selection{background:#fe8019;color:#1d2021}
|
|
|
|
|
|
/* Reduced motion — disable animations for users who prefer it */
|
|
@media(prefers-reduced-motion:reduce){*{transition-duration:0.01ms!important;animation-duration:0.01ms!important}}
|