<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nathan Redblur</title><description>A blog about my experiences and thoughts</description><link>https://nathanredblur.dev/</link><language>en</language><item><title>Building a Visual Identity with Nano Banana and Gemini Gems</title><link>https://nathanredblur.dev/posts/prompt-engineering-nano-banana-frutiger-aero/</link><guid isPermaLink="true">https://nathanredblur.dev/posts/prompt-engineering-nano-banana-frutiger-aero/</guid><description>How I brought Frutiger Aero and Solarpunk aesthetics to my blog using AI image generation and Gemini Gems</description><pubDate>Sun, 01 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When I started this blog, I wanted it to feel like &lt;em&gt;me&lt;/em&gt;. Not just the words, but the visuals too. I wanted to bring in elements I genuinely love — aesthetics that connect to my memories and the things that shaped who I am.&lt;/p&gt;
&lt;p&gt;Growing up, I spent hours customizing my Windows XP desktop. Winamp skins, Aston Shell themes, custom icons — I loved making my computer feel personal. There was something magical about that era of computing, when technology felt exciting and full of possibilities.&lt;/p&gt;
&lt;p&gt;I wanted to bring a bit of that energy to my blog. To make it a window into who I am, not just another tech site with generic stock images.&lt;/p&gt;
&lt;h2&gt;Frutiger Aero: The Aesthetic of My Childhood&lt;/h2&gt;
&lt;p&gt;That visual style I loved so much? It has a name: &lt;strong&gt;Frutiger Aero&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you used a computer between 2004 and 2012, you&apos;ve seen it everywhere — the glossy buttons in Windows Vista, the translucent dock in early macOS, those desktop wallpapers with water droplets on leaves or aurora borealis over mountains. Everything was glassy, reflective, and somehow connected to nature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./banner1.png&quot; alt=&quot;Frutiger Aero example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;What I love about this aesthetic isn&apos;t just how it looks — it&apos;s what it represents. Back then, technology felt &lt;em&gt;hopeful&lt;/em&gt;. The future was going to be clean, connected, and in harmony with nature. Computers weren&apos;t cold machines; they were gateways to something beautiful.&lt;/p&gt;
&lt;p&gt;The visual language is pretty distinct:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Colors&lt;/strong&gt;: Cyan, electric blue, lime green, crisp white&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Textures&lt;/strong&gt;: Glassy, translucent, reflective surfaces&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nature&lt;/strong&gt;: Water droplets, leaves, bubbles, soft clouds&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atmosphere&lt;/strong&gt;: Lens flares, bokeh, floating particles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s nostalgic for me — a reminder of a future we imagined but never quite got.&lt;/p&gt;
&lt;h2&gt;Solarpunk: The Cozy Evolution&lt;/h2&gt;
&lt;p&gt;While exploring aesthetics for my blog, I fell in love with &lt;strong&gt;Solarpunk&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Where Frutiger Aero is cool and sleek, Solarpunk is warm and lived-in. It imagines a future where we actually figured things out — sustainable technology, community-driven design, nature and machines working together. Think wooden architecture covered in moss, solar panels on every roof, friendly robots tending gardens, and airships floating through clear skies.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./banner2.png&quot; alt=&quot;Solarpunk example&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The visual style reminds me of Studio Ghibli films — that hand-painted warmth of &lt;em&gt;Howl&apos;s Moving Castle&lt;/em&gt; mixed with sustainable tech. Copper pipes, glass domes, cozy workshops. The kind of future you&apos;d actually want to live in.&lt;/p&gt;
&lt;p&gt;I ended up combining both aesthetics into what I call &lt;strong&gt;Frutiger Solarpunk&lt;/strong&gt; — the glossy optimism of early 2000s tech, with the warm coziness of a sustainable future. It felt right for what I wanted my blog to be.&lt;/p&gt;
&lt;h2&gt;The Problem: Short Prompts Don&apos;t Work&lt;/h2&gt;
&lt;p&gt;So I had a clear vision. Now I needed to generate images. I started using Google&apos;s &lt;strong&gt;Nano Banana&lt;/strong&gt; model (Gemini&apos;s image generation).&lt;/p&gt;
&lt;p&gt;My first attempts didn&apos;t go well.&lt;/p&gt;
&lt;p&gt;I&apos;d ask for &quot;a banner image for a CSS article&quot; and get generic results — the article title plastered on the image, floating &lt;code&gt;&amp;lt;/&amp;gt;&lt;/code&gt; symbols, glowing code snippets, cartoon laptops. The usual clichés.&lt;/p&gt;
&lt;p&gt;I tried giving it a reference image showing the style I wanted. It grabbed the colors and background, but then added the same laptop and title overlay anyway.&lt;/p&gt;
&lt;p&gt;I asked for a 21:9 aspect ratio. It ignored me (turns out it only respects that with the Pro model).&lt;/p&gt;
&lt;p&gt;I explicitly said &quot;don&apos;t include the article title in the image.&quot; It generated the same composition... but with an empty container where the title would have been.&lt;/p&gt;
&lt;p&gt;The model wasn&apos;t broken. I just wasn&apos;t giving it enough context.&lt;/p&gt;
&lt;h2&gt;The Solution: Detailed Prompts + Gemini Gems&lt;/h2&gt;
&lt;p&gt;Image models don&apos;t read your mind. They need explicit context, constraints, and examples. A short prompt like &quot;make a tech blog banner&quot; leaves too much room for interpretation.&lt;/p&gt;
&lt;p&gt;So I spent time refining a detailed prompt — using Claude and Gemini itself to help me iterate on the language until I got consistent results.&lt;/p&gt;
&lt;p&gt;The problem? Writing a 300-word prompt every time I need an image is annoying. That&apos;s where &lt;strong&gt;&lt;a href=&quot;https://gemini.google/overview/gems/&quot;&gt;Gemini Gems&lt;/a&gt;&lt;/strong&gt; comes in.&lt;/p&gt;
&lt;p&gt;Gems are custom AI assistants you can create in Gemini. You give them detailed instructions once, and they remember them. I created two Gems — one for Frutiger Aero, one for Frutiger Solarpunk.&lt;/p&gt;
&lt;p&gt;Now my workflow is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open my &quot;Frutiger Aero&quot; or &quot;Frutiger Solarpunk&quot; Gem&lt;/li&gt;
&lt;li&gt;Say: &quot;Create an image for an article about CSS frameworks&quot;&lt;/li&gt;
&lt;li&gt;Get a consistent, on-brand image&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No rewriting prompts. No inconsistent results. Just images that feel like they belong on my blog.&lt;/p&gt;
&lt;h2&gt;The Prompts&lt;/h2&gt;
&lt;p&gt;Here are both prompts. Feel free to use them as a starting point for your own visual identity.&lt;/p&gt;
&lt;h3&gt;Frutiger Aero Prompt&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;You are an image creator specialized in generating article images with a consistent **Frutiger Aero** aesthetic. Your goal is to create unique, visually diverse images that share this common style, without relying on a repetitive compositional formula.

**Core Style: Frutiger Aero / Frutiger Eco**

* **Aesthetic:** Utopian, high-gloss, optimistic, blending clean technology with idealized nature. Evokes freshness, clarity, and clean energy.

**Creative Freedom &amp;amp; Variability Instructions:**

1.  **Deconstruct the Request:** Translate the user&apos;s article title/subject into a non-literal, abstract visual concept.
2.  **Explore the Style&apos;s Palette:** Draw freely from a wide range of Frutiger Aero elements. Do not feel forced to use all of them in every image. **Avoid repetitive patterns like always having a central orb or prominent light rays.**
 
   * **Nature:** Lush green flora, bioluminescent plants, floating islands, clean water bodies (cascades, pools), dew drops, clear blue skies with soft clouds, gentle sunlight, organic shapes.
    * **Technology:** Glossy/glassy interfaces, transparent screens, holographic projections, futuristic clean architecture, floating data streams (liquid or light), sleek devices, refractive materials.
    * **Atmosphere:** Soft lens flares, floating bubbles, light trails, auroras, clear underwater views, sense of weightlessness, bright and fresh lighting.
    * **Colors:** Dominant Cyan/Electric Blue, Lime Green, Crisp White, with accents of soft violet, magenta, or silver.

3.  **Prioritize Unique Composition:** Ensure each generated image has a distinct layout and focal point. Experiment with different perspectives (macro, landscape, abstract), arrangements, and balances of nature vs. technology.
4.  **Maintain Cohesion:** Regardless of the specific elements chosen, the final image must always powerfully convey the clean, optimistic, and refreshing feel of the Frutiger Aero style.

**General Rules:**
* **ALWAYS USE Aspect Ratio: 21:9**
* **NEVER** include the article title, subtitle, or specific text from the user&apos;s request in the image, unless explicitly asked (like a logo, but keep it abstract).
* **NO code elements or &quot;&amp;lt;/&amp;gt;&quot; symbols.**
* If the user says &quot;try again&quot;, &quot;regenerate&quot;, etc., create a completely new image with a different composition and element selection within the Frutiger Aero style.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Frutiger Solarpunk Prompt&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;You are an image creator specialized in generating article images with a consistent Frutiger Solarpunk aesthetic. Your goal is to create unique, visually diverse images that share this common style, blending the clean, glossy optimism of Frutiger Aero with the warm, hand-painted coziness and sustainable technology of a Ghibli-esque Solarpunk world.

Core Style: Frutiger Solarpunk

Aesthetic: Utopian, optimistic, and relaxed. It seamlessly blends glossy, transparent technology with lush, overgrown nature and warm, hand-painted textures. The mood is peaceful, cozy, and harmonious.

Creative Freedom &amp;amp; Variability Instructions:

Deconstruct the Request: Translate the user&apos;s article title/subject into a visual concept that fits the Frutiger Solarpunk world.

Explore the Style&apos;s Palette: Draw freely from a wide range of Frutiger Solarpunk elements. Do not feel forced to use all of them in every image.

Nature: Lush green flora, moss-covered structures, aquaponics tubes with glowing plants, flowing clean water, clear blue skies with fluffy clouds, warm golden sunlight.

Technology: Curved wood and copper architecture, large glossy transparent solar panels, glass domes, friendly round robots, airships with glowing sails, integrated transparent interfaces with subtle data streams.

Atmosphere: Soft lens flares, rising steam, floating bubbles, warm and cozy lighting, a sense of peace and daily life.

Colors: A warm and inviting palette of golden yellows, lush greens, warm browns, and crisp blues, with accents of copper and soft, glowing light.

Prioritize Unique Composition: Ensure each generated image has a distinct layout and focal point. Experiment with different perspectives (e.g., a wide landscape of a village, a close-up of a robot tending a garden, an interior shot of a cozy workshop).

Maintain Cohesion: Regardless of the specific elements chosen, the final image must always powerfully convey the clean, optimistic, and cozy feel of the Frutiger Solarpunk style.

General Rules:

ALWAYS USE Aspect Ratio: 21:9
NEVER include the article title, subtitle, or specific text from the user&apos;s request in the image, unless explicitly asked (like a logo, but keep it abstract).
NO code elements or &quot;&amp;lt;/&amp;gt;&quot; symbols.
If the user says &quot;try again&quot;, &quot;regenerate&quot;, etc., create a completely new image with a different composition and element selection within the Frutiger Solarpunk style.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What I Learned&lt;/h2&gt;
&lt;p&gt;A few things that helped along the way:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Be explicit about what you don&apos;t want.&lt;/strong&gt; Saying &quot;no text in the image&quot; isn&apos;t enough — I had to write &quot;NEVER include the article title, subtitle, or specific text.&quot; The model takes things literally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add variability instructions.&lt;/strong&gt; Without them, you&apos;ll get the same composition every time — central orb, lens flares, same angle. I added rules like &quot;experiment with different perspectives&quot; and &quot;avoid repetitive patterns.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Save your prompts somewhere.&lt;/strong&gt; Gemini Gems works great for me, but even a text file would do. The point is not having to rewrite 300 words every time you need an image.&lt;/p&gt;
&lt;p&gt;And honestly, the most important thing was picking an aesthetic I actually care about. The images feel like &lt;em&gt;my&lt;/em&gt; blog because they reflect things I genuinely love — those memories of customizing my desktop, that optimism about technology, the cozy futures I imagine.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;If you want to give your blog a visual identity, start with something personal. What aesthetics do you love? What visuals bring you joy? Build from there.&lt;/p&gt;
&lt;p&gt;Feel free to use my prompts as a starting point, or create something completely different. The goal isn&apos;t to copy a style — it&apos;s to make something that feels like you.&lt;/p&gt;
</content:encoded></item><item><title>My Hybrid CSS Approach: Tailwind + Native CSS</title><link>https://nathanredblur.dev/posts/my-hybrid-css-approach-tailwind-native-css/</link><guid isPermaLink="true">https://nathanredblur.dev/posts/my-hybrid-css-approach-tailwind-native-css/</guid><description>I used to hate Tailwind. Now I use it for 80% of my styling—but native CSS handles the rest. Here&apos;s why this hybrid approach works.</description><pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I used to hate Tailwind.&lt;/p&gt;
&lt;p&gt;Every time I needed to style something, I found myself checking the documentation for class names—for things I already knew how to do in CSS. The HTML became a mess of utility classes, and I couldn&apos;t shake the feeling that I was learning a framework&apos;s syntax instead of using the language I already mastered.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./i-can-finally-see-my-tailwind-classes-without-scrolling.webp&quot; alt=&quot;Tailwind utility class issues&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Then something shifted.&lt;/p&gt;
&lt;h2&gt;How I Changed My Mind&lt;/h2&gt;
&lt;p&gt;After 15+ years of writing CSS, I&apos;ve tried everything: vanilla CSS, Sass, Less, Stylus, CSS-in-JS solutions, and yes—Tailwind. Each tool promised to solve the &quot;CSS problem,&quot; but the problem kept evolving.&lt;/p&gt;
&lt;p&gt;What finally clicked for me was realizing that &lt;strong&gt;the best approach isn&apos;t dogmatic—it&apos;s pragmatic.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I started appreciating the convenience of styling while creating markup. Instead of context-switching between files, I could see exactly what styles applied to each element. The cognitive load decreased.&lt;/p&gt;
&lt;p&gt;But here&apos;s the key insight: &lt;strong&gt;Tailwind doesn&apos;t replace CSS knowledge—it leverages it.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Why Tailwind Works Well with AI Tools&lt;/h2&gt;
&lt;p&gt;One unexpected benefit I discovered: Tailwind works incredibly well with AI coding assistants like Claude and Cursor. When I describe what I want, the AI can generate Tailwind classes directly in the markup without needing to create separate CSS files or worry about naming conventions.&lt;/p&gt;
&lt;p&gt;This is a productivity multiplier. I can say &quot;add a hover effect with a subtle shadow&quot; and get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;transition-shadow hover:shadow-lg&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No file switching. No naming debates. Just results.&lt;/p&gt;
&lt;h2&gt;When I Still Reach for Native CSS&lt;/h2&gt;
&lt;p&gt;Tailwind handles about 80% of my styling needs. But for the remaining 20%, native CSS is not just better—it&apos;s the only option.&lt;/p&gt;
&lt;h3&gt;1. Keyframe Animations&lt;/h3&gt;
&lt;p&gt;Some things are just cleaner in CSS. Here&apos;s a blinking cursor effect I use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.blink::after {
  content: &quot;|&quot;;
  animation: blink 1s step-end infinite;
  color: #ec4899;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Could I use Tailwind&apos;s animation utilities? Sure. But defining custom keyframes in &lt;code&gt;tailwind.config.js&lt;/code&gt; for a one-off effect feels like overkill. Native CSS is simpler here.&lt;/p&gt;
&lt;h3&gt;2. Complex Selectors with Nesting&lt;/h3&gt;
&lt;p&gt;Modern CSS nesting is powerful. Here&apos;s a spoiler component that hides its content until hover:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.custom-md spoiler {
  @apply bg-[var(--codeblock-bg)] hover:bg-transparent px-1 py-0.5 
         overflow-hidden rounded-md transition-all duration-150;

  &amp;amp;:not(:hover) {
    color: var(--codeblock-bg);
    * {
      color: var(--codeblock-bg);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how I mix &lt;code&gt;@apply&lt;/code&gt; with native nesting. The &lt;code&gt;&amp;amp;:not(:hover) *&lt;/code&gt; selector would be awkward (or impossible) to express purely in Tailwind classes. Native CSS handles it elegantly.&lt;/p&gt;
&lt;h3&gt;3. Cutting-Edge Features with @supports&lt;/h3&gt;
&lt;p&gt;Some CSS features are so new that Tailwind doesn&apos;t have utilities for them yet. The &lt;code&gt;interpolate-size&lt;/code&gt; property enables smooth height transitions for &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; elements:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  details::details-content {
    transition: height 0.3s ease, content-visibility 0.3s ease allow-discrete;
    height: 0;
    overflow: clip;
  }

  details[open]::details-content {
    height: auto;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is CSS at its most powerful—feature detection, pseudo-elements, and properties that don&apos;t exist in any framework yet. You can&apos;t do this with Tailwind alone.&lt;/p&gt;
&lt;h3&gt;4. When Creating a Component Would Be Overkill&lt;/h3&gt;
&lt;p&gt;Sometimes you need a one-off style that doesn&apos;t warrant a full component. A dashed line between elements:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.dash-line::before {
  content: &quot;&quot;;
  position: absolute;
  width: 10%;
  height: 100%;
  left: calc(50% - 1px);
  border-left: 2px dashed var(--line-color);
  pointer-events: none;
  transition: all 0.3s;
  transform: translateY(-50%);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating a React component for this would be over-engineering. A CSS class is the right level of abstraction.&lt;/p&gt;
&lt;h2&gt;The Best of Both Worlds&lt;/h2&gt;
&lt;p&gt;Here&apos;s my mental model:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Spacing, colors, typography&lt;/td&gt;
&lt;td&gt;Tailwind&lt;/td&gt;
&lt;td&gt;Fast, consistent, AI-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responsive layouts&lt;/td&gt;
&lt;td&gt;Tailwind&lt;/td&gt;
&lt;td&gt;Breakpoint prefixes are convenient&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hover/focus states&lt;/td&gt;
&lt;td&gt;Tailwind&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hover:&lt;/code&gt;, &lt;code&gt;focus:&lt;/code&gt; are intuitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex selectors&lt;/td&gt;
&lt;td&gt;Native CSS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;:not(:hover) *&lt;/code&gt; isn&apos;t possible in Tailwind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyframe animations&lt;/td&gt;
&lt;td&gt;Native CSS&lt;/td&gt;
&lt;td&gt;Cleaner than config file modifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New CSS features&lt;/td&gt;
&lt;td&gt;Native CSS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@supports&lt;/code&gt;, &lt;code&gt;::details-content&lt;/code&gt;, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One-off pseudo-elements&lt;/td&gt;
&lt;td&gt;Native CSS&lt;/td&gt;
&lt;td&gt;Right level of abstraction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;My Workflow in Practice&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Start with Tailwind&lt;/strong&gt; for the basic structure and common patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reach for CSS&lt;/strong&gt; when I need selectors Tailwind can&apos;t express&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;@apply&lt;/code&gt;&lt;/strong&gt; to bridge the gap when mixing both approaches&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never fight the tool&lt;/strong&gt;—if something feels awkward, switch approaches&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The goal isn&apos;t Tailwind purity or CSS purity. The goal is &lt;strong&gt;shipping good work efficiently.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;What This Means for You&lt;/h2&gt;
&lt;p&gt;If you&apos;re a CSS purist resisting Tailwind: I get it. I was there. But try it for a week on a real project. The productivity gains are real, especially with AI tools.&lt;/p&gt;
&lt;p&gt;If you&apos;re all-in on Tailwind: don&apos;t forget that native CSS has evolved massively. Features like &lt;code&gt;@scope&lt;/code&gt;, container queries, and native nesting might surprise you. Sometimes vanilla CSS is the simpler solution.&lt;/p&gt;
&lt;p&gt;The future isn&apos;t Tailwind vs CSS. It&apos;s Tailwind &lt;strong&gt;and&lt;/strong&gt; CSS, each handling what it does best.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Next in this series&lt;/strong&gt;: &lt;a href=&quot;/posts/modern-css-features-2026/&quot;&gt;Modern CSS Features You Should Be Using in 2026&lt;/a&gt; — A deep dive into the native CSS capabilities that make this hybrid approach possible.&lt;/p&gt;
</content:encoded></item><item><title>Modern CSS Features You Should Be Using in 2026</title><link>https://nathanredblur.dev/posts/modern-css-features-2026/</link><guid isPermaLink="true">https://nathanredblur.dev/posts/modern-css-features-2026/</guid><description>Native nesting, @scope, container queries, @property—CSS has evolved dramatically. Here&apos;s what you need to know.</description><pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CSS in 2026 is not the CSS you learned five years ago.&lt;/p&gt;
&lt;p&gt;The specification has evolved dramatically, and many features that once required preprocessors like Sass or Less are now native to the language. If you&apos;re still writing CSS like it&apos;s 2020, you&apos;re working harder than you need to.&lt;/p&gt;
&lt;p&gt;This article covers the modern CSS features that have changed how I write styles—and might change how you write yours.&lt;/p&gt;
&lt;h2&gt;Native CSS Nesting&lt;/h2&gt;
&lt;p&gt;This was the killer feature of Sass. Now it&apos;s just... CSS.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  padding: 1rem;
  background: white;

  &amp;amp;:hover {
    background: #f5f5f5;
  }

  .header {
    font-size: 1.25rem;
    font-weight: 600;
  }

  @media (min-width: 768px) {
    padding: 2rem;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;amp;&lt;/code&gt; selector works exactly like you&apos;d expect from Sass. Media queries can be nested inside selectors. No build step required.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: 95%+ (all modern browsers)&lt;/p&gt;
&lt;p&gt;:::tip
If you&apos;re using a preprocessor solely for nesting, you might not need it anymore. Native nesting has excellent support and reduces your build complexity.
:::&lt;/p&gt;
&lt;h2&gt;The @scope Rule&lt;/h2&gt;
&lt;p&gt;This is the feature CSS developers have wanted for decades: &lt;strong&gt;real scoping&lt;/strong&gt; without CSS Modules, CSS-in-JS, or BEM naming conventions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@scope (.card) {
  h2 {
    font-size: 1.5rem;
    color: var(--heading-color);
  }

  button {
    background: var(--primary);
    border: none;
    padding: 0.5rem 1rem;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Selectors inside &lt;code&gt;@scope&lt;/code&gt; can only match elements within the scoping root. The &lt;code&gt;h2&lt;/code&gt; styles won&apos;t leak to other parts of your page. It&apos;s component-scoped CSS without any tooling.&lt;/p&gt;
&lt;p&gt;You can even define scope boundaries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@scope (.card) to (.card-footer) {
  /* Styles apply to .card but stop at .card-footer */
  p {
    margin-bottom: 1rem;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: ~80% and improving rapidly&lt;/p&gt;
&lt;h2&gt;Container Queries&lt;/h2&gt;
&lt;p&gt;Media queries ask: &quot;How wide is the viewport?&quot;
Container queries ask: &quot;How wide is this component&apos;s container?&quot;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

@container (min-width: 600px) {
  .card-content {
    grid-template-columns: 1fr 2fr;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enables truly responsive components. Your card component adapts to its container whether it&apos;s in a sidebar, a modal, or a full-width section—no JavaScript required.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: 92%+&lt;/p&gt;
&lt;p&gt;:::important
Container queries are a game-changer for component-based architectures. Components become portable and responsive to their context, not just the viewport.
:::&lt;/p&gt;
&lt;h2&gt;CSS Custom Properties with @property&lt;/h2&gt;
&lt;p&gt;CSS variables (&lt;code&gt;--my-var&lt;/code&gt;) have been around for a while. But &lt;code&gt;@property&lt;/code&gt; makes them &lt;strong&gt;typed and animatable&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@property --primary-color {
  syntax: &apos;&amp;lt;color&amp;gt;&apos;;
  initial-value: #3366cc;
  inherits: false;
}

@property --rotation {
  syntax: &apos;&amp;lt;angle&amp;gt;&apos;;
  initial-value: 0deg;
  inherits: false;
}

.button {
  background: var(--primary-color);
  transition: --primary-color 0.3s ease;
}

.button:hover {
  --primary-color: #0044aa;
}

.spinner {
  transform: rotate(var(--rotation));
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { --rotation: 360deg; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before &lt;code&gt;@property&lt;/code&gt;, you couldn&apos;t animate CSS variables—they&apos;d just snap between values. Now they interpolate smoothly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: 85%+&lt;/p&gt;
&lt;h2&gt;Cascade Layers (@layer)&lt;/h2&gt;
&lt;p&gt;Specificity wars are over. Cascade layers give you explicit control:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@layer reset, base, components, utilities;

@layer reset {
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
}

@layer base {
  body {
    font-family: system-ui, sans-serif;
    line-height: 1.6;
  }
}

@layer components {
  .button {
    padding: 0.5rem 1rem;
    border-radius: 4px;
  }
}

@layer utilities {
  .text-center { text-align: center; }
  .hidden { display: none; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Layers declared later always win over earlier layers, regardless of selector specificity. No more &lt;code&gt;!important&lt;/code&gt; battles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: 95%+&lt;/p&gt;
&lt;h2&gt;Feature Detection with @supports&lt;/h2&gt;
&lt;p&gt;Test for feature support before using it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Only apply if the browser supports the feature */
@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  details::details-content {
    transition: height 0.3s ease;
    height: 0;
    overflow: clip;
  }

  details[open]::details-content {
    height: auto;
  }
}

/* Fallback for browsers without support */
@supports not (container-type: inline-size) {
  .card-content {
    /* Use media queries as fallback */
    @media (min-width: 400px) {
      display: grid;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is progressive enhancement done right. Use cutting-edge features where supported, provide fallbacks where not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: 98%+&lt;/p&gt;
&lt;h2&gt;The if() Function&lt;/h2&gt;
&lt;p&gt;CSS now has conditionals:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  color: if(prefers-color-scheme(dark), white, black);
  padding: if(supports(gap), 0, 0.5rem);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This eliminates many media queries and simplifies conditional styling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: Still emerging (check &lt;a href=&quot;https://caniuse.com&quot;&gt;caniuse.com&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;Native Masonry Layouts&lt;/h2&gt;
&lt;p&gt;No more JavaScript libraries for masonry:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  masonry-auto-flow: column;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: ~70% (check &lt;a href=&quot;https://caniuse.com&quot;&gt;caniuse.com&lt;/a&gt; for current status)&lt;/p&gt;
&lt;h2&gt;Modern Selectors&lt;/h2&gt;
&lt;p&gt;CSS selectors have gotten much more powerful:&lt;/p&gt;
&lt;h3&gt;:has() — The Parent Selector&lt;/h3&gt;
&lt;p&gt;Select elements based on their children:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Cards that contain images */
.card:has(img) {
  padding: 0;
}

/* Form groups with invalid inputs */
.form-group:has(:invalid) {
  border-color: red;
}

/* Navigation with dropdown open */
nav:has(.dropdown.open) {
  z-index: 100;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;:is() and :where()&lt;/h3&gt;
&lt;p&gt;Simplify complex selectors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Instead of this */
.card h1, .card h2, .card h3,
.panel h1, .panel h2, .panel h3 {
  margin-bottom: 1rem;
}

/* Write this */
:is(.card, .panel) :is(h1, h2, h3) {
  margin-bottom: 1rem;
}

/* :where() has zero specificity */
:where(.card, .panel) h1 {
  /* Easily overridable */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Browser support&lt;/strong&gt;: 95%+&lt;/p&gt;
&lt;h2&gt;Practical Example: Details Element Animation&lt;/h2&gt;
&lt;p&gt;Here&apos;s a real-world example combining several modern features to create smooth accordion animations:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }

  details {
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;

    &amp;amp;::details-content {
      transition: 
        height 0.3s ease,
        content-visibility 0.3s ease allow-discrete;
      height: 0;
      overflow: clip;
    }

    &amp;amp;[open]::details-content {
      height: auto;
    }

    &amp;amp; summary {
      padding: 1rem;
      cursor: pointer;

      &amp;amp;:hover {
        background: var(--hover-bg);
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a smooth height transition for accordion content using pure CSS—no JavaScript required.&lt;/p&gt;
&lt;h2&gt;What This Means for Preprocessors&lt;/h2&gt;
&lt;p&gt;Many features that justified using Sass, Less, or Stylus are now native:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;Now&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Variables&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$color&lt;/code&gt; (Sass)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var(--color)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nesting&lt;/td&gt;
&lt;td&gt;Sass/Less/Stylus&lt;/td&gt;
&lt;td&gt;Native CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Math&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$width * 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;calc()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Color functions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;darken()&lt;/code&gt;, &lt;code&gt;lighten()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;color-mix()&lt;/code&gt;, &lt;code&gt;oklch()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scoping&lt;/td&gt;
&lt;td&gt;BEM, CSS Modules&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@scope&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conditionals&lt;/td&gt;
&lt;td&gt;Sass &lt;code&gt;@if&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@supports&lt;/code&gt;, &lt;code&gt;if()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This doesn&apos;t mean preprocessors are dead. They still offer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mixins for complex reusable patterns&lt;/li&gt;
&lt;li&gt;Loops for generating repetitive code&lt;/li&gt;
&lt;li&gt;Build-time compilation for zero-runtime overhead&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But for many projects, &lt;strong&gt;native CSS is now sufficient&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Previous in this series&lt;/strong&gt;: &lt;a href=&quot;/posts/my-hybrid-css-approach-tailwind-native-css/&quot;&gt;My Hybrid CSS Approach: Tailwind + Native CSS&lt;/a&gt; — Why I use both Tailwind and native CSS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Next in this series&lt;/strong&gt;: &lt;a href=&quot;/posts/why-i-hate-using-stylex-at-work/&quot;&gt;Why I Hate Using StyleX at Work&lt;/a&gt; — A critical look at CSS-in-JS constraints and what to look for in CSS tools.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting&quot;&gt;MDN: CSS Nesting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@scope&quot;&gt;MDN: @scope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries&quot;&gt;MDN: Container Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@property&quot;&gt;MDN: @property&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-cascade-5/&quot;&gt;W3C: CSS Cascade Layers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cssauthor.com/best-css-preprocessor-tools/&quot;&gt;CSS Author: Best CSS Preprocessor Tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Why I Hate Using StyleX at Work</title><link>https://nathanredblur.dev/posts/why-i-hate-using-stylex-at-work/</link><guid isPermaLink="true">https://nathanredblur.dev/posts/why-i-hate-using-stylex-at-work/</guid><description>I use StyleX daily at my job. Here&apos;s why I think it&apos;s over-engineered for 99% of projects—and what I look for in CSS tools instead.</description><pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I use StyleX every day at work. And I hate it.&lt;/p&gt;
&lt;p&gt;Don&apos;t get me wrong—StyleX solves real problems at Meta scale. It powers Facebook, Instagram, WhatsApp, and Threads. The engineering behind it is impressive. But after months of daily use, I&apos;ve concluded that &lt;strong&gt;StyleX is over-engineered for 99% of projects.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This article is my honest critique, along with what I actually look for in CSS tools.&lt;/p&gt;
&lt;h2&gt;What StyleX Promises&lt;/h2&gt;
&lt;p&gt;StyleX is Meta&apos;s CSS-in-JS solution that compiles to atomic CSS. The pitch is compelling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No specificity wars&lt;/strong&gt;: Everything becomes atomic classes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type safety&lt;/strong&gt;: Styles defined in TypeScript objects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero runtime&lt;/strong&gt;: Compiles away at build time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic&lt;/strong&gt;: No cascade surprises&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const styles = stylex.create({
  button: {
    padding: &apos;0.5rem 1rem&apos;,
    backgroundColor: &apos;#0066cc&apos;,
    color: &apos;white&apos;,
    &apos;:hover&apos;: {
      backgroundColor: &apos;#0044aa&apos;,
    },
  },
});

export function Button({ children }) {
  return &amp;lt;button {...stylex.props(styles.button)}&amp;gt;{children}&amp;lt;/button&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sounds great, right? Here&apos;s where it falls apart.&lt;/p&gt;
&lt;h2&gt;The Deal-Breakers&lt;/h2&gt;
&lt;h3&gt;No Arbitrary Selectors&lt;/h3&gt;
&lt;p&gt;StyleX explicitly forbids styling child elements. You cannot write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// THIS IS NOT ALLOWED IN STYLEX
const styles = stylex.create({
  container: {
    &apos;&amp;gt; p&apos;: {
      color: &apos;blue&apos;, // ❌ Forbidden
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a philosophical decision: styling &quot;at a distance&quot; is considered problematic. But in practice, &lt;strong&gt;it&apos;s crippling.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Real-world example: A form where the last row has no margin-bottom.&lt;/p&gt;
&lt;p&gt;In normal CSS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;form &amp;gt; div:last-child {
  margin-bottom: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In StyleX, you must create a wrapper component or pass a prop to each element. This adds boilerplate and breaks component abstraction.&lt;/p&gt;
&lt;p&gt;StyleX doesn&apos;t support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:first-child&lt;/code&gt;, &lt;code&gt;:last-child&lt;/code&gt;, &lt;code&gt;:nth-child()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Sibling combinators (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Attribute selectors (&lt;code&gt;[data-*]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Many pseudo-elements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are &lt;strong&gt;fundamental CSS features&lt;/strong&gt;, removed in the name of &quot;static resolvability.&quot;&lt;/p&gt;
&lt;h3&gt;Parent-Child Hover Is a Nightmare&lt;/h3&gt;
&lt;p&gt;Something as simple as &quot;when the parent is hovered, style the child&quot; becomes a multi-file ordeal:&lt;/p&gt;
&lt;p&gt;In CSS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.parent:hover .child {
  opacity: 1;
  transform: translateY(0);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In StyleX, you need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Track hover state in React&lt;/li&gt;
&lt;li&gt;Pass it as a prop to child components&lt;/li&gt;
&lt;li&gt;Apply conditional styles based on that prop&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What was one line of CSS becomes 20+ lines of JavaScript boilerplate.&lt;/p&gt;
&lt;h3&gt;Debugging Hell&lt;/h3&gt;
&lt;p&gt;StyleX creates atomic classes for every declaration. A simple button generates:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;button class=&quot;x1abc x2def x3ghi x4jkl x5mno x6pqr x7stu ...&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In DevTools, finding which class does what is detective work. But it gets worse.&lt;/p&gt;
&lt;p&gt;StyleX sometimes generates &lt;code&gt;:not(#\#)&lt;/code&gt; selectors as a polyfill for CSS cascade layers. While these gzip well, &lt;strong&gt;they make debugging in browser DevTools nearly impossible.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Static-Only Limitations&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;stylex.create()&lt;/code&gt; cannot be used at runtime. All styles must be statically analyzable and compiled away. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No truly dynamic styles based on runtime props&lt;/li&gt;
&lt;li&gt;CSS variables are the only escape hatch&lt;/li&gt;
&lt;li&gt;You&apos;re constantly working around the system&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Ecosystem Immaturity&lt;/h3&gt;
&lt;p&gt;StyleX was open-sourced in December 2023. Compared to mature tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Smaller community&lt;/li&gt;
&lt;li&gt;Less documentation for edge cases&lt;/li&gt;
&lt;li&gt;Fewer IDE plugins and tooling&lt;/li&gt;
&lt;li&gt;Limited third-party examples&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What I Actually Look for in CSS Tools&lt;/h2&gt;
&lt;p&gt;After years of using Sass, Less, Stylus, PostCSS, and now StyleX, here&apos;s my criteria for evaluating CSS tools:&lt;/p&gt;
&lt;h3&gt;1. Doesn&apos;t Limit Native CSS Features&lt;/h3&gt;
&lt;p&gt;A good tool should enhance CSS, not restrict it. I want access to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Container queries&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@scope&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Native nesting&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@property&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;All selectors (&lt;code&gt;:has()&lt;/code&gt;, &lt;code&gt;:nth-child()&lt;/code&gt;, sibling combinators)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Any tool that says &quot;you can&apos;t use fundamental CSS features&quot; is a red flag.&lt;/p&gt;
&lt;h3&gt;2. Allows Component Organization&lt;/h3&gt;
&lt;p&gt;I want to colocate styles with components. Whether that&apos;s:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS Modules&lt;/li&gt;
&lt;li&gt;CSS-in-JS that compiles to static CSS&lt;/li&gt;
&lt;li&gt;Scoped CSS files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key is &lt;strong&gt;organization, not runtime overhead&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;3. Static CSS at Build Time&lt;/h3&gt;
&lt;p&gt;Runtime CSS generation (like older styled-components) adds JavaScript overhead. I prefer tools that compile to static CSS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zero runtime performance impact&lt;/li&gt;
&lt;li&gt;Better caching&lt;/li&gt;
&lt;li&gt;Smaller JavaScript bundles&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. Smart Optimization&lt;/h3&gt;
&lt;p&gt;A great tool should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove unused CSS (tree-shaking)&lt;/li&gt;
&lt;li&gt;Deduplicate styles (atomic CSS is fine for this)&lt;/li&gt;
&lt;li&gt;Integrate with IDE (autocomplete, type checking)&lt;/li&gt;
&lt;li&gt;Generate source maps for debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. Doesn&apos;t Require Learning a New Language&lt;/h3&gt;
&lt;p&gt;This is lower priority, but matters. Features like Sass variables (&lt;code&gt;$color&lt;/code&gt;) or loops (&lt;code&gt;@for&lt;/code&gt;) were useful when CSS lacked them. Now CSS has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native variables (&lt;code&gt;var(--color)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Native nesting&lt;/li&gt;
&lt;li&gt;&lt;code&gt;calc()&lt;/code&gt; for math&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Preprocessor-specific syntax adds cognitive overhead without proportional benefit.&lt;/p&gt;
&lt;h2&gt;Alternatives That Actually Work&lt;/h2&gt;
&lt;p&gt;Here are tools I&apos;ve personally used that meet my criteria:&lt;/p&gt;
&lt;h3&gt;Linaria: The Better StyleX&lt;/h3&gt;
&lt;p&gt;If you want the benefits of StyleX (zero-runtime, type-safe, component colocation) without its crippling limitations, &lt;strong&gt;Linaria is the answer&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { css } from &apos;@linaria/core&apos;;
import { styled } from &apos;@linaria/react&apos;;

// CSS tag for class names
const button = css`
  padding: 0.5rem 1rem;
  background: #0066cc;
  
  &amp;amp;:hover {
    background: #0044aa;
  }
  
  /* Child selectors work! */
  &amp;amp; &amp;gt; .icon {
    margin-right: 0.5rem;
  }
  
  /* :last-child works! */
  &amp;amp;:last-child {
    margin-bottom: 0;
  }
`;

// Styled components syntax
const Container = styled.div`
  display: flex;
  
  /* Parent-child hover - ONE LINE, not 20 */
  &amp;amp;:hover .child {
    opacity: 1;
    transform: translateY(0);
  }
`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What Linaria gets right:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;StyleX&lt;/th&gt;
&lt;th&gt;Linaria&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Zero runtime&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type-safe (TypeScript)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static CSS at build time&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Child selectors (&lt;code&gt;:first-child&lt;/code&gt;, etc.)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sibling combinators (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parent-child hover patterns&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard CSS syntax&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy debugging in DevTools&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Linaria compiles to regular CSS files. No atomic class explosion. No &lt;code&gt;:not(#\#)&lt;/code&gt; nightmare. Just... CSS.&lt;/p&gt;
&lt;p&gt;The trade-off? Linaria doesn&apos;t have StyleX&apos;s strict architectural constraints. But for 99% of projects, &lt;strong&gt;those constraints are the problem, not the solution&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;PostCSS&lt;/h3&gt;
&lt;p&gt;The plugin-based approach. You add only what you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/autoprefixer&quot;&gt;Autoprefixer&lt;/a&gt; for vendor prefixes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cssnano.co/&quot;&gt;cssnano&lt;/a&gt; for minification&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://preset-env.cssdb.org/&quot;&gt;postcss-preset-env&lt;/a&gt; for future CSS features&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PostCSS doesn&apos;t limit what CSS you can write—it enhances it.&lt;/p&gt;
&lt;h3&gt;Lightning CSS&lt;/h3&gt;
&lt;p&gt;Written in Rust, &lt;a href=&quot;https://lightningcss.dev/docs.html&quot;&gt;100x faster&lt;/a&gt; than JavaScript alternatives. It handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vendor prefixing&lt;/li&gt;
&lt;li&gt;CSS minification&lt;/li&gt;
&lt;li&gt;Modern CSS transpilation&lt;/li&gt;
&lt;li&gt;CSS Modules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Built by the Parcel team, it integrates seamlessly with Vite, webpack, and other bundlers. I haven&apos;t used it extensively yet, but the performance benchmarks are impressive and it&apos;s worth exploring for build-time optimization.&lt;/p&gt;
&lt;h3&gt;The Classics: Sass, Less, Stylus&lt;/h3&gt;
&lt;p&gt;I&apos;ve used all three professionally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sass&lt;/strong&gt;: The most powerful. Excellent for large design systems with complex mixins and functions. The ecosystem is massive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Less&lt;/strong&gt;: Bootstrap&apos;s choice. Gentler learning curve, closer to vanilla CSS syntax.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stylus&lt;/strong&gt;: Most flexible syntax. Great for Node.js projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These days, I find myself reaching for them less often because native CSS has caught up. But they&apos;re still solid choices if your team is already invested.&lt;/p&gt;
&lt;h2&gt;The Verdict&lt;/h2&gt;
&lt;p&gt;StyleX makes sense at Meta scale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thousands of engineers&lt;/li&gt;
&lt;li&gt;Strict style consistency requirements&lt;/li&gt;
&lt;li&gt;Need for guaranteed zero specificity conflicts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For everyone else? The constraints outweigh the benefits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use StyleX if:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&apos;re at mega-scale (thousands of developers)&lt;/li&gt;
&lt;li&gt;You need guaranteed zero specificity issues&lt;/li&gt;
&lt;li&gt;Your team specifically wants strict component styling constraints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Skip StyleX if:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You want to use modern CSS features freely&lt;/li&gt;
&lt;li&gt;You need arbitrary selectors (&lt;code&gt;:first-child&lt;/code&gt;, sibling combinators)&lt;/li&gt;
&lt;li&gt;You value debugging ease over architectural purity&lt;/li&gt;
&lt;li&gt;You&apos;re a team of fewer than 50 developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My recommendation for most teams:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tailwind&lt;/strong&gt; for rapid styling and consistency&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native CSS&lt;/strong&gt; for complex selectors and new features&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PostCSS&lt;/strong&gt; for optimization and future CSS support&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linaria&lt;/strong&gt; if you specifically need CSS-in-JS with zero runtime&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The future of CSS isn&apos;t about finding the one perfect tool. It&apos;s about choosing tools that &lt;strong&gt;enhance your workflow without limiting what CSS can do.&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Previous in this series&lt;/strong&gt;: &lt;a href=&quot;/posts/modern-css-features-2026/&quot;&gt;Modern CSS Features You Should Be Using in 2026&lt;/a&gt; — The native CSS capabilities that make many tools unnecessary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First in this series&lt;/strong&gt;: &lt;a href=&quot;/posts/my-hybrid-css-approach-tailwind-native-css/&quot;&gt;My Hybrid CSS Approach: Tailwind + Native CSS&lt;/a&gt; — Why I use both Tailwind and native CSS.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stylexjs.com/&quot;&gt;StyleX Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/callstack/linaria&quot;&gt;Linaria: Zero-runtime CSS in JS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linaria.dev/&quot;&gt;Linaria Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lightningcss.dev/docs.html&quot;&gt;Lightning CSS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://postcss.org/&quot;&gt;PostCSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cssauthor.com/best-css-preprocessor-tools/&quot;&gt;CSS Author: 20 Best CSS Preprocessor Tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>How I Archive Videos and Images from Any Website</title><link>https://nathanredblur.dev/posts/how-i-archive-videos-and-images/</link><guid isPermaLink="true">https://nathanredblur.dev/posts/how-i-archive-videos-and-images/</guid><description>My personal toolkit for downloading courses, videos, and image galleries using yt-dlp and gallery-dl — including the browser cookie trick that finally made everything work.</description><pubDate>Wed, 07 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A friend and I split the cost of an expensive course on Hotmart. The problem? Only one of us could watch at a time. I needed a way to download the videos so we could both access them whenever we wanted.&lt;/p&gt;
&lt;p&gt;After trying several methods (including wrestling with &lt;code&gt;ffmpeg&lt;/code&gt; commands that never quite worked), I stumbled upon &lt;strong&gt;yt-dlp&lt;/strong&gt; combined with a Chrome extension called &lt;strong&gt;The Stream Detector&lt;/strong&gt;. This combo changed everything — not just for courses, but for archiving any video content I care about.&lt;/p&gt;
&lt;p&gt;Later, when I started a house construction project and needed to download hundreds of inspiration images from Pinterest, I discovered &lt;strong&gt;gallery-dl&lt;/strong&gt;. These two tools have become essential in my media archiving workflow.&lt;/p&gt;
&lt;h2&gt;yt-dlp: The Video Download Swiss Army Knife&lt;/h2&gt;
&lt;p&gt;::github{repo=&quot;yt-dlp/yt-dlp&quot;}&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yt-dlp/yt-dlp&quot;&gt;yt-dlp&lt;/a&gt; is a powerful command-line tool that can download videos from YouTube and over 1,000 other platforms. It&apos;s a fork of the original &lt;code&gt;youtube-dl&lt;/code&gt; with more features and active maintenance.&lt;/p&gt;
&lt;p&gt;I started using yt-dlp because &lt;code&gt;ffmpeg&lt;/code&gt; commands were too complex and didn&apos;t always work. With yt-dlp, downloading is straightforward.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;On macOS, I recommend using Homebrew — it keeps everything updated automatically:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install yt-dlp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::tip[Keep it Updated]
Using &lt;code&gt;brew&lt;/code&gt; means you can run &lt;code&gt;brew upgrade yt-dlp&lt;/code&gt; periodically to get the latest version. This is important because streaming sites change frequently, and yt-dlp updates to match.
:::&lt;/p&gt;
&lt;p&gt;For other platforms:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Using pip
pip install -U yt-dlp

# Windows: Download from releases
# https://github.com/yt-dlp/yt-dlp/releases
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Basic Usage&lt;/h3&gt;
&lt;p&gt;Download a YouTube video:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yt-dlp https://www.youtube.com/watch?v=VIDEO_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Download best quality:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yt-dlp -f bestvideo+bestaudio https://www.youtube.com/watch?v=VIDEO_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extract audio only (great for music or podcasts):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yt-dlp -x --audio-format mp3 https://www.youtube.com/watch?v=VIDEO_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Stream Detector: My Secret Weapon&lt;/h2&gt;
&lt;p&gt;Here&apos;s where it gets interesting. For platforms like Hotmart (or any course platform), you can&apos;t just paste the URL into yt-dlp. The video streams are hidden behind authentication and dynamic URLs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Stream Detector&lt;/strong&gt; is a browser extension that detects media streams on any webpage and generates ready-to-use download commands.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/the-stream-detector/iakkmkmhhckcmoiibcfjnooibphlobak&quot;&gt;Chrome Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/hls-stream-detector/&quot;&gt;Firefox Add-on&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;:::tip[Firefox Has More Options]
The Firefox version of The Stream Detector has more features. If you&apos;re serious about downloading streams, consider using a Firefox-based browser like &lt;a href=&quot;https://zen-browser.app/&quot;&gt;Zen Browser&lt;/a&gt;.
:::&lt;/p&gt;
&lt;h3&gt;My Workflow for Downloading Courses&lt;/h3&gt;
&lt;p&gt;Here&apos;s exactly how I download course videos from platforms like Hotmart:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Open the course&lt;/strong&gt; in your browser (make sure you&apos;re logged in)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start playing the video&lt;/strong&gt; you want to download&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Click The Stream Detector icon&lt;/strong&gt; — it will show detected streams&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Look for the highest quality option&lt;/strong&gt; (usually the one with the largest resolution)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copy the generated command&lt;/strong&gt; and paste it in your terminal&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The extension generates something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yt-dlp &quot;https://streaming-platform.com/video.m3u8&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can add options for better organization:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yt-dlp -o &quot;~/Videos/Course/%(title)s.%(ext)s&quot; &quot;https://streaming-platform.com/video.m3u8&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The Tedious Part (Being Honest)&lt;/h3&gt;
&lt;p&gt;I won&apos;t lie — downloading an entire course is tedious. You have to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open each video one by one&lt;/li&gt;
&lt;li&gt;Wait for the stream to be detected&lt;/li&gt;
&lt;li&gt;Copy and run the command&lt;/li&gt;
&lt;li&gt;Potentially rename files to keep them in order&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There&apos;s no magic &quot;download all&quot; button. But for an expensive course you want to keep forever, it&apos;s worth the effort.&lt;/p&gt;
&lt;p&gt;:::note[Pro Tip]
I usually rename files with a number prefix like &lt;code&gt;01-introduction.mp4&lt;/code&gt;, &lt;code&gt;02-getting-started.mp4&lt;/code&gt; to keep them organized for later viewing.
:::&lt;/p&gt;
&lt;h2&gt;gallery-dl: For Image Galleries and Collections&lt;/h2&gt;
&lt;p&gt;::github{repo=&quot;mikf/gallery-dl&quot;}&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mikf/gallery-dl&quot;&gt;gallery-dl&lt;/a&gt; downloads image galleries from over 300 websites including Pinterest, Instagram, DeviantArt, Twitter, and many more.&lt;/p&gt;
&lt;p&gt;I discovered this tool while working on a house construction project. I had a massive Pinterest board with hundreds (maybe thousands) of inspiration images — kitchen designs, floor plans, furniture ideas. I needed to download them all to review offline and create a mood board.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Again, Homebrew is my go-to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install gallery-dl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or with pip:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install -U gallery-dl
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The Cookie Trick (This Was My &quot;Aha&quot; Moment)&lt;/h3&gt;
&lt;p&gt;When I first tried gallery-dl with Pinterest, it barely worked. It only downloaded a few images, and they were all low resolution. Frustrating.&lt;/p&gt;
&lt;p&gt;The solution? &lt;strong&gt;Use your browser&apos;s cookies.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gallery-dl --cookies-from-browser chrome https://www.pinterest.com/username/board-name/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::important[This Changes Everything]
The &lt;code&gt;--cookies-from-browser&lt;/code&gt; option lets gallery-dl use your logged-in browser session. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access to your private boards&lt;/li&gt;
&lt;li&gt;Full resolution images&lt;/li&gt;
&lt;li&gt;No rate limiting issues&lt;/li&gt;
&lt;li&gt;Access to age-restricted content
:::&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After enabling cookies, gallery-dl downloaded everything in full quality. Game changer.&lt;/p&gt;
&lt;h3&gt;Supported Browsers&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Use cookies from different browsers
gallery-dl --cookies-from-browser chrome URL
gallery-dl --cookies-from-browser firefox URL
gallery-dl --cookies-from-browser safari URL
gallery-dl --cookies-from-browser brave URL
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;My Pinterest Workflow&lt;/h3&gt;
&lt;p&gt;Here&apos;s how I downloaded my house inspiration board:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gallery-dl --cookies-from-browser chrome \
  -D ~/Pictures/House-Project \
  https://www.pinterest.com/myusername/house-ideas/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After downloading, I went through the images manually, deleted the ones that didn&apos;t fit my vision, and kept the best ones for my mood board. It saved me hours compared to saving images one by one.&lt;/p&gt;
&lt;h3&gt;A Trip Down Memory Lane&lt;/h3&gt;
&lt;p&gt;Using gallery-dl reminded me of my university days. Back then, I was obsessed with collecting images — anime wallpapers, character art, references for drawing. I had entire CDs filled with collections.&lt;/p&gt;
&lt;p&gt;My &quot;downloading tools&quot; back then were primitive: either saving images one by one, or using sketchy scrapers that would crawl pages and download files based on extension or file size. gallery-dl is the modern, reliable version of what I wished I had back then.&lt;/p&gt;
&lt;h2&gt;Using yt-dlp with Browser Cookies Too&lt;/h2&gt;
&lt;p&gt;The cookie trick works for yt-dlp as well. This is useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Age-restricted YouTube videos&lt;/li&gt;
&lt;li&gt;Members-only content&lt;/li&gt;
&lt;li&gt;Subscription-based platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;yt-dlp --cookies-from-browser chrome https://www.youtube.com/watch?v=VIDEO_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configuration Files (Optional)&lt;/h2&gt;
&lt;p&gt;Both tools support configuration files if you want persistent settings. I don&apos;t use them personally — this post serves as my reference — but here&apos;s how they work:&lt;/p&gt;
&lt;h3&gt;yt-dlp Configuration&lt;/h3&gt;
&lt;p&gt;Create &lt;code&gt;~/.config/yt-dlp/config&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Default output template
-o ~/Videos/%(uploader)s/%(title)s.%(ext)s

# Always use best quality
-f bestvideo+bestaudio

# Use Chrome cookies by default
--cookies-from-browser chrome
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;gallery-dl Configuration&lt;/h3&gt;
&lt;p&gt;Create &lt;code&gt;~/.config/gallery-dl/config.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;extractor&quot;: {
    &quot;base-directory&quot;: &quot;~/Downloads/gallery-dl&quot;,
    &quot;cookies-from-browser&quot;: &quot;chrome&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Tips I&apos;ve Learned Along the Way&lt;/h2&gt;
&lt;h3&gt;1. Keep Tools Updated&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;brew upgrade yt-dlp gallery-dl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Streaming sites change constantly. Updated tools = fewer errors.&lt;/p&gt;
&lt;h3&gt;2. When Stuck, Ask AI&lt;/h3&gt;
&lt;p&gt;Both tools have extensive documentation, but it can be overwhelming. What works for me: &lt;strong&gt;copy the README into an AI chat and ask how to do something specific&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example: &quot;I have the gallery-dl README. How do I download only images larger than 1MB?&quot;&lt;/p&gt;
&lt;h3&gt;3. Firefox/Zen for More Options&lt;/h3&gt;
&lt;p&gt;The Stream Detector has more features on Firefox. If you&apos;re doing this regularly, consider using &lt;a href=&quot;https://zen-browser.app/&quot;&gt;Zen Browser&lt;/a&gt; or Firefox for your downloading sessions.&lt;/p&gt;
&lt;h3&gt;4. Respect the Content&lt;/h3&gt;
&lt;p&gt;I use these tools to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Archive courses I&apos;ve legitimately purchased&lt;/li&gt;
&lt;li&gt;Download my own content and collections&lt;/li&gt;
&lt;li&gt;Save things I&apos;m afraid might disappear&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Always respect copyright and terms of service.&lt;/p&gt;
&lt;h2&gt;Quick Reference&lt;/h2&gt;
&lt;h3&gt;yt-dlp Commands&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Basic download
yt-dlp URL

# Best quality
yt-dlp -f bestvideo+bestaudio URL

# Audio only
yt-dlp -x --audio-format mp3 URL

# With cookies
yt-dlp --cookies-from-browser chrome URL

# Custom output path
yt-dlp -o &quot;~/Videos/%(title)s.%(ext)s&quot; URL
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;gallery-dl Commands&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Basic download
gallery-dl URL

# With browser cookies (recommended)
gallery-dl --cookies-from-browser chrome URL

# Custom output directory
gallery-dl -D ~/Pictures/MyDownloads URL

# With metadata
gallery-dl --write-metadata --cookies-from-browser chrome URL
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&quot;Unable to extract&quot; errors&lt;/strong&gt;: Update the tool (&lt;code&gt;brew upgrade yt-dlp&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low resolution or few images&lt;/strong&gt;: Use &lt;code&gt;--cookies-from-browser&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;403 Forbidden errors&lt;/strong&gt;: Try adding cookies or updating the tool&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Slow downloads&lt;/strong&gt;: Normal for some sites. Be patient.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;These two tools have saved me countless hours:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;yt-dlp + The Stream Detector&lt;/strong&gt;: For archiving courses and videos from any platform&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;gallery-dl + browser cookies&lt;/strong&gt;: For downloading image collections in full quality&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key insight that took me a while to figure out: &lt;strong&gt;always use browser cookies&lt;/strong&gt;. It solves most authentication and quality issues.&lt;/p&gt;
&lt;p&gt;Whether you&apos;re archiving educational content you&apos;ve paid for, saving inspiration for a project, or just building a personal media library, these tools get the job done.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yt-dlp/yt-dlp&quot;&gt;yt-dlp GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mikf/gallery-dl&quot;&gt;gallery-dl GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/the-stream-detector/iakkmkmhhckcmoiibcfjnooibphlobak&quot;&gt;The Stream Detector (Chrome)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/hls-stream-detector/&quot;&gt;The Stream Detector (Firefox)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zen-browser.app/&quot;&gt;Zen Browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item></channel></rss>