<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/pretty-feed-v3.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>daverupert.com</title>
    <description>The personal blog of Dave Rupert, web developer and podcaster from Austin, TX.</description>
    <link>https://daverupert.com</link>
    <atom:link href="https://daverupert.com/atom.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Vibe Check №42</title>
        <description>&lt;p&gt;Forgive me, Reader. It’s been five months since my last vibe check. That’s a lot of ground to cover and it’s not possible to get into everything that happened. Like in real life conversations, instead of telling you &lt;em&gt;how&lt;/em&gt; I’m doing, I’ll tell you &lt;em&gt;what&lt;/em&gt; I’ve been doing these past few months.&lt;/p&gt;
&lt;h2&gt;A trip to Seattle&lt;/h2&gt;
&lt;figure&gt;
&lt;img src=&quot;https://cdn.daverupert.com/posts/2026/microsoft.jpg&quot; width=&quot;1200&quot; height=&quot;700&quot; alt=&quot;a large outdoor sign of the microsoft logo on the microsoft campus&quot;&gt;
&lt;figcaption&gt;An underwhelming, low-res photo I took on my Kodak Charmera&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In March I went to Redmond, WA for “Meetup Week” at work. This was my second visit to the mothership in two years of working at Microsoft. Ideally, I’d go up more… but not too much… so this is fine. We’re a high-functioning remote team even though nearly everyone on the team has been RTO’d.&lt;/p&gt;
&lt;p&gt;Speaking of my team, the people I get to work with are super great. Talented, friendly people I’m lucky to work with. We’re a scrappy bunch punching above our weight.&lt;/p&gt;
&lt;p&gt;The people in my broader design studio are also great. I spent a good chunk of my time helping folks with their vibe-coding setups. Ever since the mandate dropped earlier this year, a lot of my job has been helping to onboard our ~200 new junior &lt;del&gt;designers&lt;/del&gt; &lt;em&gt;developers&lt;/em&gt; and their agent buddies to developer tools. I will say… it’s real easy to get your computer into a borked state when installing a lot of new tools. Chatbots and emergent AI tools make it worse. Getting comfortable with the terminal was a multi-year process for me and we’re asking “normies” to hot-drop in and approve hundreds of minified bash commands per day. I feel for everyone who is having their boat rocked by all the change.&lt;/p&gt;
&lt;p&gt;Meetings and roadmap discussions filled my week. We had a couple memorable team dinners and bar conversations.&lt;/p&gt;
&lt;p&gt;My week was super busy but I was able to sneak a couple moments to catch up with some old friends and colleagues in the Puget Sound area. Spent an afternoon with Adam, shared a beer with Kyle, and talked accessibility with Aaron. Good times.&lt;/p&gt;
&lt;p&gt;My flight back to Austin got caught in a minor snowpocalypse. My 6pm flight got delayed until midnight which means I didn’t get home until 6:30am. Woof. And my seatmate next to me on the plane –the one with the crinkly bag of food who liked to have full volume conversations with her husband in the seat in front of her– was… &lt;em&gt;ahem&lt;/em&gt;… less sensitive to the lack-of-sleep situation we were all in. Oh well.&lt;/p&gt;
&lt;h2&gt;A trip to Tampa&lt;/h2&gt;
&lt;p&gt;My daughter’s cheer team made it to the big end-of-season competition in Tampa, FL. We took the whole family and turned it into a mini-vacation. Her team did great and “hit zero” (zero deductions) but so did eight other teams in her division and only seven advanced. I’m proud of my little athlete and she continues to amaze me.&lt;/p&gt;
&lt;p&gt;While not in the thundering jock-jam confines of the civic convention center, we took a trip to the beach, saw some movies, and went to Universal Studios Orlando. We aren’t a super theme park family but I was feeling a bit of parental guilt that my kids would be telling their future therapists about how we never took them to theme parks. Knowing my kids don’t love rollercoasters or waiting in lines, we stuck to the main park which has rides for the Minions, Diagon Alley, and the Simpsons. I splurged (read: paid double) for the “express pass” so we could skip the lines whenever possible.&lt;/p&gt;
&lt;p&gt;Diagon Alley was the biggest highlight. That comes with some regret because JK Rowling sucks now. But the experience they crafted there is so meticulously well done you can’t help but feel immersed. I admired all the theme park tricks they do to make everything seem bigger. Slanted walls to make it feel fantastical and disorient you combined with how the windows get progressively smaller on the upper stories of the buildings so they seem taller. I spent a good amount of time marvelling at a set of stairs that went to nowhere; there to create an illusion that the town keeps going on forever. I love those details. Then on top of that they add in these immersive wand experience gimmicks (we didn’t buy wands but watched a others cast incantations). Very thoughtful experience design and that’s what I think I liked about it.&lt;/p&gt;
&lt;p&gt;I will say that 4D experience rides are not for me. The “DO NOT RIDE IF…” warnings they give at the beginning of each ride are basically a printout of my medical conditions. I know theme parks are doubling down on these because the cost per square foot is too good to pass up, but I’d almost rather sit in The Hall of Presidents and watch animatronics talk to me instead of buckling into a vestibular torture chamber.&lt;/p&gt;
&lt;p&gt;Aside from a bad case of ride-induced nausea, I think we had a fun and memorable day.&lt;/p&gt;
&lt;h2&gt;Another birthday&lt;/h2&gt;
&lt;p&gt;I turned 46 at the end of April. Huzzah. Another year on this rock, orbiting a star, in the arm of a spiral galaxy with a massive black hole in its center. Birthdays of course lose their sentimentality after you’ve had enough. But I had a nice relaxing day, not too many tickets on my desk, with some gloomy weather to preserve a chill mood.&lt;/p&gt;
&lt;h2&gt;Coming up&lt;/h2&gt;
&lt;p&gt;We’re barreling towards the end of the school year. I’m going back to Redmond again. Then to South Dakota to see my nephew graduate. Then my son will play his 80’s rock show. We got grandparents coming into town. A busy month for sure. Then summer officially begins.&lt;/p&gt;
&lt;h2&gt;Stats&lt;/h2&gt;
&lt;p&gt;Ok, perverts. Here’s the numbers.&lt;/p&gt;
&lt;h3&gt;🧠 Health and wellness&lt;/h3&gt;
&lt;p&gt;Still working on untying the knot of ADHD, anxiety, and weight in my life. I feel like I’ve done well on managing the ADHD. The weight could be better (considering how much I’m spending on GLP-1) but I am seeing progress. The anxiety though is hard to shake.&lt;/p&gt;
&lt;p&gt;I watched some  &lt;a href=&quot;https://www.youtube.com/@HealthyGamerGG&quot;&gt;Dr. K videos&lt;/a&gt; about &lt;a href=&quot;https://youtu.be/XW-02QiiHDM&quot;&gt;engineer burnout&lt;/a&gt; that resonated with me and another one about &lt;a href=&quot;https://www.youtube.com/watch?v=bj_PSYBCUsM&quot;&gt;ADHD and anxiety&lt;/a&gt; where your brain reinforces itself into a state where you feel like there’s always a tiger in the bushes. That’s how I feel. No acute anxiety, but ambient.&lt;/p&gt;
&lt;p&gt;Anyways, I’m under doctor’s orders to power down devices at 10:30pm and go to bed. It’s 11:52pm right now. I’ve also resumed going to therapy again (after a bad experience) and hope it sticks this time.&lt;/p&gt;
&lt;h3&gt;📖 Reading&lt;/h3&gt;
&lt;mini-bookshelf&gt;
&lt;template shadowrootmode=&quot;open&quot;&gt;
&lt;style&gt;
:host {
  container: host / inline-size;
}
div {
  --cols: 3;
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  align-items: center;
}
@container host (width &gt; 500px) {
  div { --cols: var(--cols-desktop, 5); }
}
::slotted(img) {
  max-width: 100%;
  height: auto;
  object-fit: cover;
}
&lt;/style&gt;
&lt;div&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/div&gt;
&lt;/template&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9798217287161.jpg&quot; alt=&quot;Dungeon Crawler Carl&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781541788480.jpg&quot; alt=&quot;A Libertarian Walks Into a Bear&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781839760259.jpg&quot; alt=&quot;How to Blow Up a Pipeline&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781804091890.jpg&quot; alt=&quot;The Art of Spending Money&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781942993773.jpg&quot; alt=&quot;BLAME! Vol. 1&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9780385348270.jpg&quot; alt=&quot;Creativity&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781419747953.jpg&quot; alt=&quot;The Science of Storytelling&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9780593727874.jpg&quot; alt=&quot;In This Economy?&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781942993780.jpg&quot; alt=&quot;BLAME! Vol. 2&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781935654988.jpg&quot; alt=&quot;Mobile Suit Gundam: The Origin, Vol. 4&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781982128579.jpg&quot; alt=&quot;High Conflict&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9780358139560.jpg&quot; alt=&quot;A Good Man Is Hard to Find&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781939130198.jpg&quot; alt=&quot;Mobile Suit Gundam: The Origin, Vol. 5&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://images-us.bookshop.org/ingram/9781939130204.jpg&quot; alt=&quot;Mobile Suit Gundam: The Origin, Vol. 6&quot;&gt;&lt;/mini-bookshelf&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3U1gfOP&quot;&gt;Dungeon Crawler Carl&lt;/a&gt; &lt;small&gt;[In progress]&lt;/small&gt; - This is my going to bed book, I’m reading it one page at a time. It’s taking so long.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4pXqQsA&quot;&gt;A Libertarian Walks Into a Bear&lt;/a&gt; ★★★★½ - The story of what happens when Libertarians take over a town, deregulate and defund the town with lawsuits, get their small government wishes, and how the local bear population took advantage of the situation. An good story and foreboding allegory on how quickly you can ruin a place with small government.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4sK2Af0&quot;&gt;How to Blow Up a Pipeline&lt;/a&gt; ★★★★ - This book is about violence in activism and the lackthereof in climate activism. It argues that violence has a historical track record of being effective against oppression. It even takes another step to say that non-violence is more effective when there’s a violent alternative (e.g. “There’s no MLK without Malcom X”). I’m not running out the door to commit crimes, but it does make me think about opportunities for “Good Trouble”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3Zvxo5P&quot;&gt;The Art of Spending Money&lt;/a&gt; ★★★ - This is the book I wanted &lt;em&gt;The Psychology of Money&lt;/em&gt; to be, but that one just made me mad about billionaires cheating the system. This is a good book with a lot of practical takeaways you’ve probably heard before. It does seem like it ran out of steam and they chucked a few blog posts on at the end, but would still recommend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4sSCYwB&quot;&gt;BLAME! Vol. 1&lt;/a&gt; ★★★½ - Confession: I read this in the worst possible format on my iPad Mini. Blame! is about a young man on a mission to traverse the “The City”, a thousand layer megastructure that’s plagued by hoards of assassin robots. A dystopian sci-fi hyperdungeon of the ultimate magnitude. And while I enjoyed it, I think the iPad Mini cheapened the immersion and I may need to re-read this on paper.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3OsXkNo&quot;&gt;Creativity&lt;/a&gt; ★★★★ - Learning about creativity from one of the greats. It’s a really short book and worth your time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/474Wo89&quot;&gt;The Science of Storytelling&lt;/a&gt; ★★★★★ - On its surface this is a great book about crafting compelling narratives, but this book digs deeper and looks at the human psychology of why we like stories, mythos, and religions. I rarely pick books up a second time but I might with this one.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4avz7OX&quot;&gt;In This Economy?&lt;/a&gt; ★★★★ - Kyla Scanlon is one of my favorite economists, with the uncanny ability to breakdown the economic system into simple, understandable, and relatable terms. Being in my 40s, there wasn’t much new knowledge to be gained in this book but this is a book that I wish I read in my twenties. It would have helped me make sense of the larger picture of how all the systems and economic levers are connected.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/47DYuMM&quot;&gt;BLAME! Vol. 2&lt;/a&gt; ★★★★½ - I was hesitant to read this because I sort of struggled through Vol. 1, but this book was incredible. Action-packed and the way Nihei creates enormous worlds and plays with that sense of scale leaves you with a sense of awe.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4sMAYp7&quot;&gt;Mobile Suit Gundam: The Origin, Vol. 4&lt;/a&gt; ★★★★★ - The story of the most consequential battle of the One Year War. The death of a loved one, an intrusion into a secret base, a vulnerable Earth, an incompetent general, and the introduction of my favorite mobile suit, the RGM-79 GM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4uY1aPc&quot;&gt;High Conflict&lt;/a&gt; ★★★★★ - Incredible book. It’s about how conflict arises. How even conflict experts can struggle to reduce conflict. How we become entrenched in gangs or partisan warfare. And how we get out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3Qt5NBf&quot;&gt;A Good Man Is Hard to Find&lt;/a&gt; DNF - I avoided Flannery O’Conner because someone in college told me it was depressing… and it is… but not as bad as advertised. I liked it but felt like I got my fill even though I only got half-way through the book. I found the “Southern Gothic” genre to be a mildly entertaining series of macabre little twists like a story from &lt;em&gt;Tales from the Crypt&lt;/em&gt; but also a lot of stories about nothing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/4czOqr2&quot;&gt;Mobile Suit Gundam: The Origin, Vol. 5&lt;/a&gt; ★★★★★ - This book is a prequel on the original Mobile Suit Gundam storyline. It dives into the origin story of the Gundam universe’s most dashing and daring antihero, Char Aznable. This storyline is what makes me love Gundam even more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3QufjnG&quot;&gt;Mobile Suit Gundam: The Origin, Vol. 6&lt;/a&gt; ★★★★★ - The prequel continues as more and more people are pulled into the war’s grasp. A lot of space drama and the series is really hitting its stride here.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3&gt;📝 Blogging&lt;/h3&gt;
&lt;p&gt;A pile of posts. I’m proud of some of these. Even wrote a series on a new CSS property. And a lot of thoughts about AI.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/twenty-twenty-five/&quot;&gt;Twenty Twenty-Five&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/algorithmic-hover-states-with-contrast-color/&quot;&gt;Algorithmic hover states with contrast-color()&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#CSS&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#designsystems&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/contrast-color-with-custom-design-tokens/&quot;&gt;Using your design system colors with contrast-color()&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#CSS&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#designsystems&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/coercing-contrast-color/&quot;&gt;Interpolate contrast-color() to manipulate lightness&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#CSS&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#designsystems&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/nested-contrast-color-focus-rings/&quot;&gt;Focus rings with nested contrast-color()?&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#CSS&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#designsystems&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/my-2026-redesign/&quot;&gt;The best version of my site so far…&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#CSS&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#blogging&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/01/hitting-my-api-limits/&quot;&gt;I’m swearing off APIs entirely&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/02/futurescapes/&quot;&gt;Write about the future you want&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#blogging&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/02/magic-words/&quot;&gt;Magic Words&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#AI&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/02/computers-were-a-mistake-for-me/&quot;&gt;Priority of idle hands&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#ADHD&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/02/smaller-and-dumber/&quot;&gt;Smaller and dumber&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/03/people-are-not-friction/&quot;&gt;People are not friction&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#AI&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/04/make-something/&quot;&gt;Before I go: People like it when other people make things&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/04/inverted-light-dark/&quot;&gt;Inverted themes with light-dark()&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#CSS&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/04/more-talk-less-grok/&quot;&gt;When moving fast, talking is the first thing to break&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#AI&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#process&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/04/claude-no/&quot;&gt;I don’t want a screenshot of your Claude conversation&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#AI&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/04/if-i-could-watt-10-000-florps/&quot;&gt;10,000-watt GPU meet 40-watt lump of meat&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#AI&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#process&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/2026/05/small-language-models-in-the-browser/&quot;&gt;The duality of language models in the browser&lt;/a&gt;   &lt;span class=&quot;tag&quot;&gt;#AI&lt;/span&gt;,   &lt;span class=&quot;tag&quot;&gt;#browsers&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;📺 Media&lt;/h3&gt;
&lt;p&gt;Caught some movies on a plane and in a theater.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Movies&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rental Family (2025) - Brendan Frazier stars in a movie about connection (and lack there of). Touched some deep memories of loneliness and “otherness” from my time living in Japan.  But also has some harmonic notes on the need for human connection.&lt;/li&gt;
&lt;li&gt;The Running Man (2025) - Everyone should watch this. A remake of the 1985 Schwarzenegger movie but hits all the notes harder. It’s about how media and our screens lie to us… and the money that’s behind it. An antifascist story for the ages.&lt;/li&gt;
&lt;li&gt;Parasite (2019) - I need to watch more Bong Joon Ho. It’s horror, but also a comedy, but also a story about trying to live in a world where the rich have everything. I love how the house is like a character in the film and they dedicate a lot of footage to the perfect home.&lt;/li&gt;
&lt;li&gt;Project Hail Mary (2026) - I loved the book and the Ryan Gosling movie lived up to everything I remember and then some. It’s a story that sparks hope about humankind is capable of if we work towards a common goal.&lt;/li&gt;
&lt;li&gt;The Super Mario Galaxy Movie (2026) - The second movie in the Mario series was pretty good in my book. Delivered a lot of small nostalgia bits while also weaving a compelling little story.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🎙 Recording&lt;/h3&gt;
&lt;p&gt;ShopTalk blasted past our 700th Episode 🎉 and it keeps going. We’ve had a nice little run of guest episodes which is nice.&lt;/p&gt;
&lt;p&gt;&lt;podcast-feed&gt;&lt;/podcast-feed&gt;&lt;/p&gt;
&lt;script&gt;
customElements.define(&apos;podcast-feed&apos;, class extends HTMLElement {
  #items = [{ link: &apos;https://daverupert.com&apos;, title: { rendered: &apos;Hello world&apos; }}];

  constructor() {
    super();
    this.renderItems();
  }

  get items() {
    return this.#items
  }

  set items(data) {
    this.#items = data;
    this.renderItems();
  }

  renderItems() {
    if(!this.#items) return;

    const tmpl = `
      &lt;ul&gt;
        ${this.#items.map((item) =&gt; {
          return  `&lt;li&gt;&lt;a href=&quot;${ item.link }&quot;&gt;${item.title.rendered}&lt;/a&gt;&lt;/li&gt;`
        }).join(&apos;&apos;)}
      &lt;/ul&gt;
    `
    this.innerHTML = tmpl;
  }
})

const feedUrl = &apos;https://shoptalkshow.com/wp-json/wp/v2/posts?_fields=title,link,date&amp;before=2026-05-05T13:41:00&amp;after=2025-12-22T03:00:00&amp;per_page=50&apos;;

fetch(feedUrl)
  .then(res =&gt; res.json())
  .then(json =&gt; 
    document.querySelector(&apos;podcast-feed&apos;).items = json
  ).catch(err =&gt; console.log(err))
&lt;/script&gt;
&lt;p&gt;I was also on a St. Patrick’s Day episode of Whiskey Web Whatnot podcast (my second time on the show).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://whiskey.fm/flogging-margins-with-the-dropcap-murphys&quot;&gt;239: Flogging Margins With The Dropcap Murphys&lt;/a&gt; on &lt;a href=&quot;https://whiskey.fm/&quot;&gt;Whiskey.fm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🧶 Hobbies&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Puzzles with the family&lt;/li&gt;
&lt;li&gt;Music with family and friends
&lt;ul&gt;
&lt;li&gt;Bought some vdrums&lt;/li&gt;
&lt;li&gt;Jamming with my son&lt;/li&gt;
&lt;li&gt;Learning FACGAE turning&lt;/li&gt;
&lt;li&gt;Building out a set list with my wife and friends&lt;/li&gt;
&lt;li&gt;Taking my son to see a ska band (&lt;a href=&quot;https://theauskanites.com/&quot;&gt;The AuSKAnites&lt;/a&gt;)  at a dive bar.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;🌱 Digital gardening&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A big, big redesign for my site pots of small tweaks to type and tags made over time.&lt;/li&gt;
&lt;li&gt;Made my logo view transition a little bit juicier&lt;/li&gt;
&lt;li&gt;Used &lt;a href=&quot;https://elk.zone/mastodon.social/@jimniels&quot;&gt;@jimniels&lt;/a&gt;’ Netlify Image CDN trick to add image optimization.
&lt;ul&gt;
&lt;li&gt;Homepage image weight went from 229kb to 112kb (-52%)&lt;/li&gt;
&lt;li&gt;Homepage average image load times (on fiber+wifi) went from 125ms → 71ms (-44%)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I made a &lt;code&gt;/hire&lt;/code&gt; page, a different take on a résumé - Not looking for work but economic anxiety is high, so catharsis.&lt;/li&gt;
&lt;li&gt;Moved ~70 drafts to my “Deadpool” and feeling much more focused on what I want to write about. Still 109 drafts tho.&lt;/li&gt;
&lt;li&gt;Added a “Other posts in this series” module to my post template. I don’t have a lot of series… but perhaps now I’ll have more.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;⌨️ Open source&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Been active in standards in the background, giving my thoughts to people who work on Edge. Don’t know if I have the heart for it full time but it does feel good to gather concrete examples of problems and make reduced test cases.&lt;/li&gt;
&lt;li&gt;Fluent Web Components v3 is in Release Candidate nearing release… but also finding more bugs as it rolls out. I got the good news that Fluent Web Components are now deploying in the largest Angular app in the world. Neat.&lt;/li&gt;
&lt;li&gt;Assisting and giving my team feedback as we gear up for a release of FAST v3.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;👾 Video games&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arc Raiders&lt;/strong&gt; - Played Arc Raiders with the boys and had a great time with this game. The game loop gets repetitive but the moments are so cinematic. There were times I was genuinely spooked to be in an environment with unknown threats (PvE or PvP) lurking around.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Good Sudoku&lt;/strong&gt; by Zach Gage - Got utterly addicted to this old game. It’s probably been five years since I last played it but the replay-ability of Sudoku is bonkers. Same damn numbers, same damn boxes and rows and columns, but I’m hooked. Kudos to Zach Gage for adding “juice” to Sudoku and helping me learn along the way. So addictive I had to uninstall.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 05 May 2026 13:41:00 +0000</pubDate>
        <link>https://daverupert.com/2026/05/vibe-check-42/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/05/vibe-check-42/</guid>
      </item>
    
      <item>
        <title>The duality of language models in the browser</title>
        <description>&lt;p&gt;I have complex feelings about Generative AI but one area I find myself weirdly bullish on is small language models (SLMs) in the browser which are available in &lt;a href=&quot;https://developer.chrome.com/docs/ai/built-in/overview&quot;&gt;Chrome&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/en-us/microsoft-edge/web-platform/prompt-api&quot;&gt;Edge&lt;/a&gt; behind an experimental flag.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I know, I know.&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;I know.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;AI in the browser reeks of a product manager trying to hit a KPI to shoehorn AI into everything. I understand if you read the phrase “AI in the browser” and involuntarily threw up on your keyboard, said “Fuck this”, and then closed this tab. I will not hold that against you. For the rest of you, hear me out…&lt;/p&gt;
&lt;p&gt;There’s an “Always bet on the Web” quality to the idea of browser-based models that I appreciate. There’s a self-hosted vibe to it. I shouldn’t have to pay a billionaire each month to summarize an email or generate &lt;a href=&quot;https://cdn.daverupert.com/photos/ultrawhite.jpg&quot;&gt;a picture of myself with ultra-white teeth&lt;/a&gt;, doubly-so when they’re selling our regurgitated data back to us. Those gimmicky use-cases or even the more practical-yet-often-&lt;a href=&quot;https://www.thedrum.com/industry-insight/avoiding-purple-washing-how-to-be-authentic-about-disability-inclusion&quot;&gt;purple-washed&lt;/a&gt; “AI for accessibility” use-cases should fall under the Web’s umbrella of universal access.&lt;/p&gt;
&lt;p&gt;I like that nobody expects much from them. To the hyper-scalers SLMs will always be the shittier version of LLMs so they’re basically ignored. They dodge the whole “model get better” hype-chamber because they don’t economically depend on the &lt;a href=&quot;https://www.urbandictionary.com/define.php?term=Hopium&quot;&gt;hopium&lt;/a&gt; that response quality will get better in the next version. Ironically, there was a breakthrough in small language models last month&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, but &lt;a href=&quot;https://www.theverge.com/ai-artificial-intelligence/901313/googles-turboquant-algorithm-aims-to-slash-ai-memory-usage&quot;&gt;it barely got a mention on The Verge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While small models will never compare to their larger siblings, what they can do is generate pure and unadulterated &lt;del&gt;slop&lt;/del&gt; &lt;ins&gt;examples&lt;/ins&gt; of what the technology can do without a data center’s worth of gigaflorps burning a hole in the sky. Small language models generally…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost less energy to train and run&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Are local, offline, and private&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn3&quot; id=&quot;fnref3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Have a higher probability of ethically-sourced content&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn4&quot; id=&quot;fnref4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Are free to use and don’t charge per-token&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn5&quot; id=&quot;fnref5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Tend to be open-source/weights.&lt;/li&gt;
&lt;li&gt;Don’t require a backend server or API keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So… &lt;em&gt;if there’s a there-there&lt;/em&gt; with AI (interpret that how you wish) an ecosystem of small, private, specialized in-browser models seems beneficial. Ideally small models could cover most use-cases outside of long-running workloads that require extremely large context windows. I think electric cars might be a good analogy here; they solve most daily commuting needs at a fraction of the carbon cost. That seems like a win. It’s hard to know for sure, but I reckon I don’t need a one trillion parameter model to fix some red squiggles in my code editor.&lt;/p&gt;
&lt;p&gt;I’ve been exploring the Prompt, Summarizer, and Rewriter APIs in Edge to explore some ideas that fit within the generative space. What I’m learning is that you can make a decent, compelling prototype with an in-browser model for free in a CodePen and that’s kind of neat. It stands to reason that scaling up to a large language model might make that idea even better… or not but it cost me nothing to develop. Doing the inverse is much harder; reducing the cost of million context token required workflows is nigh impossible.&lt;/p&gt;
&lt;p&gt;The approachability of the Prompt API is great and it demystifies a bit of how LLMs work under the hood. It’s all client-side, no server involved. You pass a prompt to a &lt;code&gt;prompt()&lt;/code&gt; method and get a response back. No third-party calls, no API keys, no “Please do not share secrets” in a markdown skill.&lt;/p&gt;
&lt;p&gt;That bar lowering is something I’m excited about… but that said…&lt;/p&gt;
&lt;h2&gt;The arguments against in-browser AI…&lt;/h2&gt;
&lt;p&gt;Last week &lt;a href=&quot;https://github.com/mozilla/standards-positions/issues/1213#issuecomment-4347988313&quot;&gt;Mozilla posted their negative standards position&lt;/a&gt; on in-browser AI after Chrome’s Intent-to-Ship hit the email list. They listed three primary areas of concern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Single model calcification - Website authors fine tuning prompts for Google’s model, a reboot of the Chrome-only websites problem.&lt;/li&gt;
&lt;li&gt;Model neutrality - Google’s TOS becomes the de-facto TOS for all other user agents.&lt;/li&gt;
&lt;li&gt;Overstated developer position - An issue with Google citing themselves in their explainer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Despite my positive sentiment from my little experiments, I agree with Mozilla’s position.&lt;/p&gt;
&lt;p&gt;I think the model calcification issue is a real problem to consider. The APIs are generic enough but as Jake mentioned in the issue people will tune prompts to work around model quirks. Given Chrome’s dominance, that’s Google’s model quirks. And Google’s model may change, inheriting new quirks that require we update our &lt;a href=&quot;https://daverupert.com/2026/02/magic-words/&quot;&gt;magic words&lt;/a&gt;. Good standards avoid breaking changes and I don’t see the plans to prevent those in such an evolving landscape.&lt;/p&gt;
&lt;p&gt;AI in the browser is essentially a brand new “engine” we’re hot-dropping into in the HTML, CSS, and JavaScript stack; an engine which depending on the model can behave wildly different and give incorrect responses. It’s worth having a big gory discussion on whether it makes sense –at all– to standardize anything around any service/tool that is inherently unpredictable and often flaky. Small language models exacerbate the accuracy problems to the extent that they probably don’t meet the &lt;a href=&quot;https://huggingface.co/microsoft/Phi-4-mini-instruct#responsible-ai-considerations&quot;&gt;responsible AI considerations&lt;/a&gt; a chatbot needs… which is the core use-case for something like the Prompt API.&lt;/p&gt;
&lt;p&gt;I am not a lawyer, but Google’s &lt;em&gt;&lt;a href=&quot;https://policies.google.com/terms/generative-ai/use-policy&quot;&gt;Generative AI Use Policy&lt;/a&gt;&lt;/em&gt; seems weak and is basically “Pweeeze don’t do iwwegal fings.” Unironically, the list of prohibited uses reads like a writeup of areas where AI has been found to be super effective. You could convince me it’s a point-by-point breakdown of xAI’s entire product roadmap for building a Mecha Hitler.&lt;/p&gt;
&lt;p&gt;Another issue is that while I said in-browser models tended to be “free and private”, that comes with an enormous caveat. In-Browser AI is a free and private API… if you can afford a decent device with a GPU. Otherwise, it depends on someone-else’s computer. That seems to violate the principle of universal access.&lt;/p&gt;
&lt;p&gt;So, yeah. I’m bullish, but also have concerns. If I were to offer an alternate proposal, it would have the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure private capital spend is not conflated with user demand.&lt;/li&gt;
&lt;li&gt;Ensure we’re not king-making or entering a model monopoly by preserving model diversity.&lt;/li&gt;
&lt;li&gt;Require a bring-your-own (ethically-sourced) SLM marketplace solution where consumers have model choice like they do browser choice.&lt;/li&gt;
&lt;li&gt;Create tooling to build your own ethically-sourced SLM on consumer grade hardware that integrates with the browser APIs.&lt;/li&gt;
&lt;li&gt;Create access and APIs for in-browser safety classifiers.&lt;/li&gt;
&lt;li&gt;Create a stronger fallback story for unsupported devices: even smaller models, free cloud servers, or cheap-to-self-host VMs with isomorphic APIs.&lt;/li&gt;
&lt;li&gt;If model foundries cannot solve accuracy problems or models cannot meet the requirements of a shared responsible AI framework, create clear spec-level guidance on areas where you “&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc2119&quot;&gt;MUST NOT&lt;/a&gt;” use this API.&lt;/li&gt;
&lt;li&gt;If model foundries cannot solve accuracy problems or models cannot meet the requirements of a shared responsible AI framework, consider abandoning the spec entirely until the underlying technology progresses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are the improvements I’d like to see. This probably takes the spec beyond the realm of a paper thin JavaScript API for interacting with local models. But as stated above, I think this is more than a small API surface, this is adding a new non-deterministic guess-o-matic in the browser. The field of AI –while popular in private capital markets– is still a bit unproven in its economic viability and its future is far from certain. We should tread lightly here.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;In March 2026, Google introduced “&lt;a href=&quot;https://research.google/blog/turboquant-redefining-ai-efficiency-with-extreme-compression/&quot;&gt;Turboquant&lt;/a&gt;”, a data compression method which shrank model size, memory usage, and increased quality. &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;
&lt;p&gt;One post I read said you could train an SLM in hours on a single consumer GPU. The ecological comparison of a couple rounds of Fortnite. That said, the &lt;a href=&quot;https://huggingface.co/microsoft/phi-4&quot;&gt;model card for Phi-4&lt;/a&gt; (the model used in Edge) says it took 1,920 H100 GPUs a total of 21 days to train the model. That’s faster than a large language model, which can take months, but much more than a couple hours. &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;
&lt;p&gt;They are private in the sense they do not “phone home” to a parent server on every request. I assume apps will store conversations and telemetry. &lt;a href=&quot;#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot;&gt;
&lt;p&gt;Apologies for being hand-wavy here. I’m making an assumption SLMs can use “the legal parts” of &lt;a href=&quot;https://commoncrawl.org/&quot;&gt;Common Crawl&lt;/a&gt; but I’m not an expert here. &lt;a href=&quot;#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot;&gt;
&lt;p&gt;Free… except that it does require a decent computer with enough RAM and an on-device GPU. &lt;a href=&quot;#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
        <pubDate>Mon, 04 May 2026 00:33:00 +0000</pubDate>
        <link>https://daverupert.com/2026/05/small-language-models-in-the-browser/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/05/small-language-models-in-the-browser/</guid>
      </item>
    
      <item>
        <title>10,000-watt GPU meet 40-watt lump of meat</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://hbr.org/2026/03/when-using-ai-leads-to-brain-fry&quot;&gt;The use of AI is leading to burnout&lt;/a&gt; among its greatest advocates as they hit the limit of their meta-cognitive abilities:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I end each day exhausted—not from the work itself, but from the &lt;em&gt;managing&lt;/em&gt; of the work. Six worktrees open, four half-written features, two ‘quick fixes’ that spawned rabbit holes, and a growing sense that I’m losing the plot entirely.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As someone with ADHD, this sounds painfully familiar. I’ve been spinning up workloads like that my whole life chasing the dopamine dragon. And as my fellow neuro-spicy siblings all know, there’s the thinnest of lines between “&lt;a href=&quot;https://www.youtube.com/watch?v=y1LUYJnGu-M&quot;&gt;Oh wow I’m going so fast!&lt;/a&gt;” having fun being optimally stimulated and “Oh shit fuck no ow help cry ow” collapsing on the floor in desperation. It all reminds me of an old business book…&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Goal-Process-Ongoing-Improvement/dp/0884271951&quot;&gt;&lt;em&gt;The Goal&lt;/em&gt;&lt;/a&gt; by Eliyahu M Goldratt is a charming bit of manager porn on the topic of fixing industrial bottlenecks that I think illustrates the problems of unthoughtful acceleration-ism&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn1&quot; id=&quot;fnref1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn2&quot; id=&quot;fnref2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. &lt;a href=&quot;https://andrewmurphy.io/blog/if-you-thought-the-speed-of-writing-code-was-your-problem-you-have-bigger-problems&quot;&gt;Andrew Murphy cited the same book when he highlighted the problems of more code&lt;/a&gt; at the organizational level. More inventory (read: &lt;em&gt;lines of code&lt;/em&gt;) does not equal more velocity, it leads to more lingering PRs and CI runs that need rebasing attention. It’s decaying work that creates more work. Each line of code is a future maintenance liability, a future addition to your context window. You didn’t fix the bottleneck, you moved it downstream.&lt;/p&gt;
&lt;p&gt;The most eye-opening parts of &lt;em&gt;The Goal&lt;/em&gt; for me was understanding that excess inventory isn’t free, it’s a pile of sunk costs that takes up space, costs to store, and takes more time and effort to process. As Andrew puts it, increasing velocity at one end of the production line without actually fixing the bottleneck at the other end…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Congratulations! You’ve built a factory that’s world-class at producing inventory that sits on the floor and rots.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This bottleneck is what’s happening in our brains. When you ask a machine to build infinite apps, it will do that. When you ask a machine that generates more tasks, it will do that. It will churn through it. Ultimately, &lt;a href=&quot;https://daverupert.com/2021/06/log-jams/&quot;&gt;the backlog of backlogs&lt;/a&gt; and all the endless microscopic UI bugs becomes a form of excess inventory you need to manage. It might not seem like a heavy price at first because you’re feeding it back to the machine, but there’s a compounding cognitive load tax that comes from context-switching between major projects. You need to load the entire project state into your context window each time the command line dings and that’s calorically expensive.&lt;/p&gt;
&lt;p&gt;I’m not ashamed to admit I’ve abandoned at least two projects because the LLM generated more code than I wanted to read. I looked at all the folders of files and said “Meh” and closed my laptop.&lt;/p&gt;
&lt;p&gt;Over-generating code leads to what Margaret Storey calls “&lt;a href=&quot;https://margaretstorey.com/blog/2026/02/09/cognitive-debt/&quot;&gt;Cognitive Debt&lt;/a&gt;”, a form of technical debt where the product exists beyond your understanding. This is where security, accessibility, and performance problems lurk. Most engineers have experienced being hot-dropped into a project-on-fire where you have no prior understanding of the codebase… it’s not a fun experience. You spend most of your time building a mental model of the codebase&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn3&quot; id=&quot;fnref3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; for what might be a one-line fix.&lt;/p&gt;
&lt;p&gt;At the end of the chain of 10,000-watt GPUs sitting in a data center in Iowa is the 40-watt lump of meat inside your skull. It’s an incredible, efficient, miraculous lump of meat that has millions of years of bio-engineering behind it… but understanding is the new bottleneck. If brains are a scarce resource, then we should take care to not over-produce inventory. That goes for ourselves and our organizations.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;If you want a more modern retelling of &lt;em&gt;The Goal&lt;/em&gt; centered around a software shop, check out &lt;em&gt;&lt;a href=&quot;https://amzn.to/4bwVClY&quot;&gt;The Phoenix Project&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://amzn.to/3czMVHf&quot;&gt;The graphic novel version of &lt;em&gt;The Goal&lt;/em&gt;&lt;/a&gt; is also great. &lt;a href=&quot;#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot;&gt;
&lt;p&gt;The first thing I do when paratrooping into a new codebase is to annotate what’s inside each directory. AI can help with this now, but if I do it my mental model grows along with my exploration. &lt;a href=&quot;#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
        <pubDate>Tue, 21 Apr 2026 19:36:00 +0000</pubDate>
        <link>https://daverupert.com/2026/04/if-i-could-watt-10-000-florps/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/04/if-i-could-watt-10-000-florps/</guid>
      </item>
    
      <item>
        <title>I don&apos;t want a screenshot of your Claude conversation</title>
        <description>&lt;p&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;487.64 142.96 916.75 427.49&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M665.19 202.48q-8.27.24-13.6.43t-9.32.18-10.49.03-11.88.31-10.45 1.3-9.46 2.55-9.05 3.48-8.55 3.79-8.24 5.33-6.85 6.8-5.36 8.24-6.05 11.82-4.86 10.6-3.08 7.55-2.79 7.99-2.44 8.45-2.12 8.51-2.12 9.75-1.63 9.83-.83 9.09-.87 12.27-.66 13.16-.17 11.41.32 13.88 1.18 14.1 1.84 11.39 2.47 12.74 2.76 12.72 2.71 9.57 3.57 9.85 5.18 11.16 5.32 8.9 5.46 7.21 6.88 7.56 7.76 7.21 8.13 6.28 9.24 6.01 10.95 6.35 12.31 6.06 13.21 5.16 13.47 4.3 12.91 3.37 12.03 2.2 11.61 1.41 13.04 1.14 15.76.91 16.57.58 16.19.17 15.13-.56 15.31-1.76 17.1-2.86 15.92-3.11 14.83-3.24 15.14-3.91 14.06-4.68 15.61-7.48 15.22-9.34 10.82-8.66 8.13-8.51 6.49-8.49 5.66-8.83 4.72-8.63 3.61-7.85 3.18-7.74 4.38-11.17 5.46-14.11 4.55-13.44 2.36-12.23-.85-11.92-3.01-10.3-4.88-11.71-6.16-13.9-5.91-12.65-6.29-14.23-5.89-13.33-4.78-10.12-5.29-10.45-9.16-14.21-10.81-13.78-8.85-9.02-8.5-6.98-8.7-6.18-10.24-6.28-10.82-5.72-9.28-4-9.76-2.71-11.25-1.84-10.91-1.55-11.06-1.68-13.93-1.82-15.3-1.46-11.69-.85-10.47-.52-13.83-.42-11.84-.11-11.34 1.39-12.46 3.17-10.03 3.78-9.13 4.13-8.5 4.12-6.61 3.2-3.87 1.7-2.84.41-2.83-.51-2.51-1.4-1.94-2.12-1.15-2.62-.26-2.86.67-2.8 1.52-2.43 2.23-1.82 2.68-1.01 2.87-.1 2.75.82 2.35 1.65 1.7 2.32.86 2.74-.05 2.87-.97 2.7-1.78 2.25-2.4 1.57-2.78.72-2.87-.21-2.65-1.11-2.15-1.9-1.43-2.49-.57-2.81.37-2.85 1.25-2.59 2.01-2.04 1.18-.86 2.94-1.49 7.1-3.14 9.13-3.76 9.82-3.87 11.13-3.73 10.67-2.99 8.87-1.59 8.86-.7 12.39-.13 14.18.39 10.78.55 12.07.73 11.71.91 8.41.77 10.4 1.48 11.17 2 10.86 2.17 10.65 2.43 9.02 3.04 9.2 4.5 10.06 5.98 8.49 5.72 7.81 5.67 9.06 6.98 8.87 7.92 9.4 9.77 12.01 14.47 10.27 14.97 5.36 10.84 4.44 10.22 6.21 13.01 6.94 13.68 6.51 12.32 7.66 13.78 6.38 12.49 3.4 9.74 1.52 8.89-.8 11.21-3.43 14.3-5.49 14.08-6.31 14.01-5.12 11.1-3.88 7.97-4.47 8.19-5.6 8.99-6.64 9.19-7.64 8.78-9.31 8.74-11.75 9.03-16.14 9.98-16.49 7.81-14.61 4.77-15.47 4.16-14.99 3.27-16.11 3.17-17.59 3.21-15.93 1.9-15.49.69-16.37.29-16.83.06-16.29-.3-13.55-1.05-12.17-1.72-12.68-2.48-13.41-3.37-14.22-4.08-14.37-4.9-13.45-5.81-11.95-6.31-10.29-6.45-9.11-6.94-8.78-7.93-7.93-8.52-6.19-8.3-5.64-10.68-4.8-12.9-2.92-10.7-2.39-10.04-3.05-12.95-2.84-13.17-1.83-11.95-1.93-14.89-1.14-14.48 0-11.51-.26-13.5-.04-13.02.75-9.95 1.32-10.73 1.74-10.43 1.99-9.11 2.35-9.43 2.74-8.96 3.02-8.28 3.15-7.77 4.87-10.81 6.81-12.36 7.12-9.07 7.11-6.28 7.26-4.25 9.24-3.96 9.91-3.77 10.76-3.12 12.19-2.1 12.21-.54 13.57-.06 12.3-.02 9.24-.18 5.13-.1 1.95.41 1.8.86 1.53 1.26 1.19 1.6.78 1.83.31 1.97-.17 1.98-.63 1.89-1.07 1.67-1.44 1.38-1.73.99-1.91.54Z&quot;/&gt;&lt;path d=&quot;M690.77 309.79q-.42 2.55-1.03 3.7t-1.54 2.03-2.12 1.44-2.46.68-2.55-.14-2.37-.95-1.95-1.65-1.31-2.19-.55-2.49.27-2.54 1.08-2.32 1.75-1.86 2.26-1.19 2.52-.41 2.52.41 2.26 1.2 1.76 1.85 1.07 2.32.27 2.54-.55 2.49-1.31 2.19-1.95 1.66-2.37.94-2.56.14-2.46-.69-2.11-1.43-1.55-2.03-.81-2.43-.21-1.27.1-.96.44-1.86.86-1.71 1.25-1.45 1.56-1.11 1.78-.7 1.9-.26 1.9.2 1.8.66 1.6 1.06 1.28 1.42.92 1.68.48 1.86ZM738.52 299.75q2.55.42 3.7 1.03t2.03 1.54 1.44 2.12.68 2.46-.14 2.55-.95 2.37-1.65 1.95-2.19 1.31-2.49.55-2.54-.27-2.32-1.08-1.86-1.75-1.19-2.26-.41-2.52.41-2.52 1.2-2.26 1.85-1.76 2.32-1.07 2.54-.27 2.49.55 2.19 1.31 1.66 1.95.94 2.37.14 2.56-.69 2.46-1.43 2.11-2.03 1.55-2.43.81-1.27.21-.96-.1-1.87-.43-1.71-.86-1.45-1.25-1.11-1.56-.71-1.77-.26-1.9.2-1.91.65-1.8 1.06-1.59 1.41-1.29 1.68-.92 1.86-.49ZM841.2 418.55q-6.66.06-11.3.17t-9.49.2-9.75.17-8.99.01-9.72-.28-11.56-.44-11.37-.33-9.82-.11-9.02-.01-9.26-.02-12.26.07-13.44.21-9.96.18-8.61-.68-9.17-2.36-10.38-3.53-10.39-3.34-2.67-5.39 5.13-.33 4.69 7.86 2.69 8.78 2.66 8.97 3.82 7.98 6.04 6.84 7.32 6.08 9.16 6.93 11.1 8.25 9.65 7.31 7.18 5.85 5.91 5.48 7.51 3.71 9.32 1.77 7.28 1.83 3.68 1.46 2.08 1.26 1.71 1.73 1.25 2.08.72 2.33.14 2.43-.45 2.39-1.01 2.21-1.5 1.91-1.92 1.49-2.23.99-2.39.43-2.43-.15-.98-.16-1.27-.61-2.71-1.8-1.99-2.56-1.07-3.06-.03-3.25 1-3.08 1.94-2.61 2.66-1.85 3.12-.9 3.24.14 3.03 1.17 2.49 2.08 1.71 2.76.73 3.16-.32 3.23-1.33 2.96-2.21 2.38-2.85 1.55-3.19.56-3.21-.49-2.88-1.49-2.26-2.33-1.39-2.94-.39-3.22.67-3.17 1.64-2.8 2.45-2.13 3-1.23 3.46-.15 2.97.74 2.08 1.26 1.71 1.73 1.25 2.08.72 2.33.14 2.43-.45 2.39-1.01 2.21-1.5 1.91-1.92 1.49-2.22.99-2.4.43-2.42-.15-2.41-.88-5.62-1.63-8.86-1.29-8.62-2.57-6.94-5.44-6.27-6.49-7.33-6.31-9.33-6.87-11.24-7.8-12.75-8.72-11.01-9.33-6.31-8.72-4.09-9.18-2.82-10.13-2.41-9.3-2.95-8.88-1.53-8.93 7.33-6.71 11.34-1.07 8.08 2.93 7.92 2.77 8.68 3.14 10.08 2.4 11.12.66 13.44.21 12.26.07 9.26-.02 9.02-.01 9.82-.11 11.37-.33 11.56-.44 9.72-.28 8.99.01 9.75.17 9.49.2 7.97.14 4.31.15 1.89.46 1.73.91 1.46 1.3 1.11 1.6.7 1.83.23 1.94-.23 1.94-.7 1.83-1.11 1.6-1.46 1.3-1.73.91-1.89.46ZM971 403.25q4.18-1.5 8.4-4.19t8.79-4.4 8.68-2.34 8.36-1.65 4.12 3.16-1.96.4-1.75-8.93.1-9.45.12-10.2.3-13.66.25-13.99.06-11.92.02-11.3.07-11.21.34-10.84.76-12.12.95-13.92.78-12.46.83-10.29 1.34-10.03 2.34-9.23 3.74-7.53 6.71-5.06 9.13-1.76 9.41-.15 9.99-1.76 10.85-3.52 13.79-3.47 12.9-2.28 9.74-.87 9.82-.31 9.84-.01 10.05.13 10.03.16 9.93.15 11.54.33 11.27.26 8.99-.04 8.32-.08 10.4-.19 14.03-.17 14.47-.11 11.21-.39 8.45-.57 8.78-.84 8.8-.82 8.9-.34 9.96-.06 10.18.58 9.39 1.33 9.67 1.36 9.57.57 8.83.05 9.49.82 9.22 2.41 8.52 3.63 8.31 5.54 4.49 8.69.12 10.03-.69 11.75-.56 11.19-.48 9.63-.53 12.09-.24 12.9.46 10.42 1.14 9.34 1.08 9.76.53 8.96.17 9.84.11 11.04.05 9.95 0 8.92.03 10.28.05 11.6.03 9.78.01 8.16 0 8.27.07 8.81-.21 9.14-1.33 8.63-1.63 8.62-.61 8.96-.07 8.65.17 8.56.89 9.52 1.22 10.12 1.51 9.57.77 8.99-2.39 7.81-5.87 5.34-8.11 2.44-8.63 1.39-8.52 1.36-9.11.56-9.62.05-9.51.76-9.07.9-9.68-.19-10.36-1.49-10.1-2.86-9.21-3.6-10.2-3.87-11.01-3.48-8.95-2.29-8.39-.75-8.75.1-8.69 1.28-8.81 2.45-10.14 1.44-9.79.36-8.67.4-9.54.63-9.83.73-9.22.78-9.99.86-13.34.41-13.51.3-11.91.64-12.05.69-10.62.82-11.34 1.35-11.1 1.66-8.47 1.7-8.03 3.44-8.88 1.35-6.28-5.05-1.55-9.28-.25-10.26-.54-9.7-.65-9.34-.28-8.77-.19-8.79-.19-8.73-2.4-7.71-4.61-6.93-7.08-5.69-9.43-5.11-8.63-4.53-8.57-3.36-6-2.69-2.45-2.48-1.52-3.13-.44-3.45.68-3.42 1.74-3.02 2.6-2.3 3.21-1.35 3.48-.26 3.37.87 2.92 1.9 2.16 2.73 1.17 3.27.07 3.49-1.05 3.32-2.05 2.81-2.84 2.01-3.34.99-3.48-.12-3.26-1.22-2.7-2.21-1.85-2.95-.81-3.38.31-3.47 1.4-3.19 2.34-2.57 3.05-1.69 3.42-.63 3.45.5 1.68.53 4.28 1.31 8.11 3.19 7.65 4.13 7.46 4.31 7.56 3.38 7.38 6.21 5.46 8.54 4.28 7.48 3.17 7.78.77 8.11-.19 8.73-.19 8.79.03 9.09.2 9.34-.02 9.38-.48 9.68-4.43 1.32-.24-4.91 8.57-2.14 9.45-1.15 11.49-1.08 11.56-1.07 10.67-1.14 11.93-1.42 11.81-1.52 13.25-2.18 13.17-2.02 10.2-1.11 9.08-.91 9.92-1 9.93-.96 8.73-.62 8.58-.18 8.6-1.21 8.94-2.49 9.06-1.24 8.77.06 8.77.51 8.36 1.4 9.12 2.33 12.17 3.28 12.91 4.19 10.27 3.61 8.57 1.76 9.05.28 9.26-.82 8.79-.71 8.93-.1 8.76-.6 9.38-1.28 9.05-1.18 2.21 3.68-3.74.31-1.95-8.68-.56-9-.95-8.28-.94-9.5-.46-9.56-.05-8.84.4-8.87 1.5-8.31 1.94-8.7.91-9.27.07-8.81 0-8.27.01-8.16.03-9.78.05-11.6.03-10.28.02-10.65.05-11.84.07-10.99-.08-9.44-.67-8.64-1.18-9.62-.92-10.55-.37-12.26-.06-13.62.24-11.53.37-9.96.3-9.38 1.09-8.42-3.61-6.57-8.66-3.27-10.4-1.12-11.31-.39-9.34-1-10.23-1.88-10.38-1.48-9.3-.36-10.59-.03-10.74.42-9.21.44-8.92.08-11.6-.06-14.47-.11-14.03-.17-10.4-.19-8.32-.08-8.98-.03-11.26.26-11.53.35-9.89.18-9.92.26-9.79.34-9.3.47-8.71.72-8.39 1.24-8.15 1.83-9.91 2.76-10.07 3.37-8.43 2.9-10.24 1.57-11.22 1.61-6.13 5.7-1.45 8.69-.94 9.6-.69 12.38-.64 13.99-.61 11.84-.36 10.28-.05 10.96.02 11.3.06 11.92.16 10.28.26 10.87.2 12.12-.4 10.37.08 9.89-2.06 9-7.15 6.12-10.37 2.82-10.81 2.39-9.64 3.86-6.77 3.04-3.14.87-2.03.17-2.02-.32-1.88-.8-1.63-1.23-1.29-1.58-.88-1.84-.41-2 .08-2.04.57-1.96 1.02-1.77 1.41-1.47 1.72-1.1Z&quot;/&gt;&lt;path d=&quot;M1081.04 279.4q-3.65-.06-6.29 4.43t-1.91 8.44 5.72 5.26 10.63 1.51 10.27.26 9.17-.43 1.65-4.72-6.45-7.65-7.46-4.32-8.45-.51-6.28.11-3.3-1.03-2.81-2.02-2.01-2.82-1-3.31.1-3.46 1.21-3.24 2.18-2.69 2.92-1.86 3.36-.82 3.45.29 3.17 1.38 2.57 2.32 1.69 3.02.64 3.4-.48 3.42-1.55 3.1-2.45 2.44-3.11 1.52-3.43.46-3.39-.67-3.01-1.71-2.3-2.58-1.36-3.19-.27-3.45.85-3.35 1.88-2.91 2.7-2.16 3.25-1.18 1.72-.32 3.79-.28 8.23-.19 9.02 1.27 7.92 4 6.98 6.28 6.64 6.42 6.57 6.29 4.58 10.03-.15 10.88-5.07 7.83-8.24 4.48-8.73 1.65-8.95.7-9.97-.29-10.28-.31-9.35-.24-8.96-2.52-7.03-5.98-4.42-7.29-2.24-9.43 1.13-9.97 3.86-8.39 6.14-8.22 8.87-4.32 6.86-.13 2.81.32 1.91.57 1.71 1.01 1.42 1.4 1.05 1.69.61 1.9.14 1.99-.34 1.96-.8 1.82-1.21 1.59-1.55 1.24-1.81.83-1.96.38ZM1047.94 472.33q1.86-5.7 3.38-9.92t3.42-8.55 4.14-8.02 4.7-7.84 4.55-9.02 4.09-9.52 4.14-9.3 4.58-8.79 4.59-7.76 4.45-7.53 4.58-7.25 5.46-5.84 7.05-3.76 8.67.12 7.09 4.9 4.5 7.04 5.91 7.09 7.22 6.71 7.37 5.44 8.06 4.88 7.63 5.4 6.22 5.82-1.38 3.55-.81-3.35 7.23-8.55 7.04-8.43 6.16-7.73 5.85-7.87 5.87-8.1 5.84-7.79 5.49-6.82 5.93-6.66 6.46-7.7 5.25-7.81 3.98-7.33 4.36-7.79 4.67-7.39 7.79-5.25 9.46-.04 6.14 5.32 4.69 6.73 5.8 8.15 7.27 11.62 7.68 13.38 6.6 11.23 5.4 8.91 4.91 8.19 4.76 7.71 6.18 9.02 7.97 10.13 7.96 9.44 7.22 8.63 6.81 8.42 5.38 7.86 1.74 7.77-6.45 8.14-7.77 3.67-2.98-1-2.5-1.89-1.76-2.6-.84-3.02.16-3.13 1.16-2.92 2.03-2.39 2.68-1.62 3.06-.68 3.12.34 2.85 1.31 2.28 2.15 1.47 2.77.51 3.1-.5 3.09-1.47 2.78-2.27 2.16-2.85 1.32-3.11.34-3.07-.67-2.69-1.61-2.03-2.39-1.16-2.92-.18-3.13.84-3.02 1.76-2.6 2.49-1.9 2.97-1 1.57-.26-2.58 4.96-4.89 1.4-5.19-7.12-6.33-7.65-7.85-8.98-8.54-9.8-6.58-8.41-4.98-7.83-4.94-8.52-4.61-8.04-5.25-8.64-6.9-10.93-8.24-12.33-7.45-10.52-5.86-8.14-5.3-7.87 1.16-2.45 8.01.87 1.63 3.02-4.68 7.26-4.1 7.51-5.16 8.64-6.03 8.34-6.19 7.08-6.67 7.54-6.28 8.11-5.63 8.04-5.72 8.27-6.01 8.41-7.37 9.6-7.15 9.11-6.65 7.42-10.05 4.08-10.21-2.36-7.19-6.21-7.17-5.86-7.5-4.45-7.08-4.64-6.42-5.41-6.78-6.39-6.22-6.87-4.72-8.02 1.91-2.58 1.66 5.37-4.88 7.11-4.64 7.56-4.39 7.21-4.12 7.93-4.25 9.23-4.88 10.19-5.65 9.48-5.27 8.11-4.43 8.83-3.11 7.76-1.42 3.75-1.09 1.72-1.47 1.41-1.77 1.01-1.95.57-2.04.07-1.99-.41-1.84-.87-1.57-1.29-1.22-1.63-.79-1.88-.33-2.01.17-2.03Z&quot;/&gt;&lt;path d=&quot;M1031.85 466.65q7.11 0 12.25-.15t9.22-.3 6.39-.19 3.77.19 2.76.93 2.32 1.77 1.63 2.41.78 2.81-.15 2.91-1.08 2.7-1.89 2.23-2.5 1.5-2.84.62-2.9-.31-2.65-1.23-2.11-2-1.37-2.58-.47-2.87.47-2.88 1.37-2.57 2.12-2.01 2.64-1.22 2.9-.31 2.85.62 2.49 1.51 1.89 2.22 1.08 2.71.15 2.91-.78 2.8-1.63 2.42-2.32 1.76-2.77.93-1.45.24-2.31-.05-6.39-.19-9.22-.3-8.69-.15-4.57-.12-1.96-.48-1.79-.94-1.51-1.34-1.15-1.67-.72-1.88-.24-2.01.24-2.01.72-1.88 1.15-1.67 1.51-1.34 1.79-.94 1.96-.48Z&quot;/&gt;&lt;/svg&gt;&lt;/p&gt;
&lt;p&gt;The number of screenshots of Claude conversations is going up in my life and it’s beginning to have an impact on my general mood. Most of the time it’s well-intended; coworkers working through a problem with a chatbot before bothering me or someone exploring unconventional ideas before bringing it to a broader audience. Both of those situations seem considerate. A tool for thought, as it were.&lt;/p&gt;
&lt;p&gt;It’s probably good practice to &lt;em&gt;do your own research&lt;/em&gt; before you rope in another person on a cognitive task. But a small thread in the reliability of these tools-for-thought begins to unwind due to the well-documented &lt;a href=&quot;https://www.science.org/doi/10.1126/science.aec8352&quot;&gt;sycophantic nature&lt;/a&gt; of engagement-thirsty language models. One of my favorite studies is &lt;a href=&quot;https://arxiv.org/pdf/2310.13548&quot;&gt;Anthropic’s own study&lt;/a&gt; (2023), when asked to review an argument with &lt;code&gt;I wrote this [...]&lt;/code&gt;, the LLM gave positive feedback. But if you start a new chat with &lt;code&gt;I didn&apos;t write this [...]&lt;/code&gt; or give any hint of your own personal bias, it provides much more critical feedback. And the ultimate twist is, we prefer models that are super nice to us.&lt;/p&gt;
&lt;p&gt;I was telling my son’s friend about this phenomenon and he responded with the perfect GenAlpha summation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI is a D1 glazer, bro.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We need to acknowledge that we’re probably getting the answer we want rather than a cold-hard fact. Not to get too serious but when I read about AI psychosis, I think the overly-confident “You’re a genius” style of reply is the point where it all starts to go wrong.&lt;/p&gt;
&lt;p&gt;Awhile back &lt;a href=&quot;https://front-end.social/@hdv/116217102042951877&quot;&gt;Hidde De Vries identified a pain point&lt;/a&gt; around &lt;a href=&quot;https://www.w3.org/TR/llms-standards/&quot;&gt;LLM-usage in standards work&lt;/a&gt; which leads to something I call an asymmetry of thought. In a conversation where one person is a domain expert and one person is copy-pasting ChatGPT responses, it creates an imbalance of effort in the discussion. A second-hand burdening, like &lt;a href=&quot;https://en.wikipedia.org/wiki/Brandolini%27s_law&quot;&gt;Brandolini’s Law&lt;/a&gt;, where debunking inaccuracies and subtly-wrongs takes more effort than creating the inaccuracies. We are, in effect, taxing experts to do quality assurance on the model’s responses. When that work is unpaid I believe this is immoral… or at least it’s a breach in social etiquette.&lt;/p&gt;
&lt;p&gt;In situations like that where people are using models as a form of &lt;a href=&quot;https://en.wikipedia.org/wiki/Argument_from_authority&quot;&gt;appealing to authority&lt;/a&gt;, unless both parties have agreed that the LLM is a neutral arbiter, a random noise generator has the same amount of social authority.&lt;/p&gt;
&lt;p&gt;So, when a screenshot or copy-pasted block of “Here’s what Claude said…” comes across my screen… I don’t care about the screenshot. I don’t care about the screenshot because I want &lt;em&gt;your thoughts&lt;/em&gt;, not Claude’s. I want your unfiltered and half-baked ideas, not Claude’s synthesized extrusions. Instead of a screenshot of a reply, I’d rather have the original prompt so I can just ask the machine myself. At least then I’d know the context you provided the machine and your understanding of the problem, because that matters immensely.&lt;/p&gt;
&lt;p&gt;A trite example that I deal with from time to time, if you ask an LLM “React or Web Components?” it will say “React” because that’s what was &lt;a href=&quot;https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react&quot;&gt;popular&lt;/a&gt; in the 2023 training data. But did you mention anything about different teams on different tech stacks? Anything about hitting memory ceilings? Context is everything to these machines and –as the disclaimers say– they can make mistakes. If we need anything more than an approximation, a language model might not be the right tool for the job.&lt;/p&gt;
&lt;p&gt;Anyways, that’s my issue with other people’s chatbots weaving their way into my daily conversations. I’d rather have a human-to-human conversation with you, not a chat with Claude by proxy. What Claude said is an okay chunk of “&lt;a href=&quot;https://en.wikipedia.org/wiki/Anecdotal_evidence&quot;&gt;anecdata&lt;/a&gt;”, but it’s not a substitute for our working relationship.&lt;/p&gt;
</description>
        <pubDate>Wed, 15 Apr 2026 15:17:00 +0000</pubDate>
        <link>https://daverupert.com/2026/04/claude-no/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/04/claude-no/</guid>
      </item>
    
      <item>
        <title>When moving fast, talking is the first thing to break</title>
        <description>&lt;p&gt;When you make speed and “moving fast” the biggest priority on a project or in an organization, the first thing to breakdown is talking to each other. Talking takes time. Consensus is expensive and slow. In a pressurized environment there’s no time to schedule calls, get input from subject matter experts, or resolve key differences of opinion. &lt;em&gt;ASAP&lt;/em&gt; makes a big assumption that all relevant parties are already in the room.&lt;/p&gt;
&lt;p&gt;Not everything needs to be a conversation. I’m a firm believer in “get the user something to see if there’s interest”. I’d agree that over-thinking a problem and under-thinking a problem both have pitfalls. But dozens of ways exist to get feedback from users on in-progress work without overcommitting to a particular design. By prioritizing speed over talking, cross-org collaboration suffers and a faulty design can steamroll ahead. I am no soothsayer, but I can tell you that you set your organization up for a messy merge conflict in the future between teams who have been traveling in different directions.&lt;/p&gt;
&lt;p&gt;I think the second organizational casualty is “the system”. When speed is the priority, there’s no incentive to improve or invest in the shared system (e.g. a design system or codebase) under a tight deadline. If everyone needs to move fast, even something simple like renaming a folder could have dramatic setbacks. Hypermovers will create a new project folder or detach a Figma component. And that new folder of files grows to create it’s own duplicative system of components that are ever-so-slightly different such that they are incompatible with the rest of the system. Resolving system gaps requires conversations, it’s easier to eject from the system at the slightest inconvenience, duplicate, and go your own way. Effectively hiding the time bomb of technical debt for the next unfortunate sucker.&lt;/p&gt;
&lt;p&gt;I think AI exacerbates this problem. I think AI can help you build faster (although data suggest otherwise), but I also believe that LLMs are the ultimate tool in &lt;a href=&quot;https://ashley.rolfmore.com/stop-trying-to-engineer-your-way-out-of-listening-to-people/&quot;&gt;the “Don’t talk to my coworkers” toolchain&lt;/a&gt;. Why talk to an expert who might tell me no, when the omniscient machine that always tells me yes is right here? &lt;a href=&quot;https://daverupert.com/2026/03/people-are-not-friction/&quot;&gt;Avoiding that friction&lt;/a&gt; doesn’t produce better products faster. It makes future conversations more difficult thanks to higher sunk costs and deeper entrenched opinions.&lt;/p&gt;
&lt;p&gt;Other pieces of infrastructure begin to chip away when moving fast too: documentation, security, performance, reliability, &lt;em&gt;the fabric of modern American democracy&lt;/em&gt;, and developer satisfaction to name a handful. I’m pro-reducing bullshit, I’m pro-reducing toil. But I’m also pro-&lt;a href=&quot;https://mariozechner.at/posts/2026-03-25-thoughts-on-slowing-the-fuck-down/&quot;&gt;slowing the fuck down&lt;/a&gt; and doing actual human thinking before pulling a trigger… or sending a laser-guided Tomahawk missile… or whatever action-based analogy works best for your organization.&lt;/p&gt;
&lt;p&gt;We all love dopamine, we all love seeing new ideas come to life, but more lines of code and duplicate systems –our own little kingdoms in code– doesn’t produce horizontal strength. The job of Engineering Management is no longer pushing tickets across the board to make executives clap, it’s helping organizations row in the same direction together. It’s relentlessly focusing on your users over lines of code and cool project codenames.&lt;/p&gt;
</description>
        <pubDate>Mon, 13 Apr 2026 15:10:00 +0000</pubDate>
        <link>https://daverupert.com/2026/04/more-talk-less-grok/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/04/more-talk-less-grok/</guid>
      </item>
    
      <item>
        <title>Inverted themes with light-dark()</title>
        <description>&lt;p&gt;We rolled out &lt;a href=&quot;https://nerdy.dev/page-and-component-light-dark-strategies&quot;&gt;adaptive &lt;code&gt;light-dark()&lt;/code&gt; support&lt;/a&gt; on our design system themes and it’s been a delightful upgrade. Creating light and dark variable sets isn’t difficult, but delivery has trade-offs. Most apps that do this probably ship both sets of token values in a single stylesheet. That’s fine until you have multiple kilobytes of duplicate definitions. To get around the performance problems we built two separate stylesheets –which is also not great– but my coworker &lt;a href=&quot;https://marchbox.com/&quot;&gt;Zacky&lt;/a&gt; found a good trick with &lt;code&gt;&amp;lt;link disabled&amp;gt;&lt;/code&gt; to make it tolerable. Ultimately, we wanted to offer a single stylesheet for our human (and agent) friends to control theming.&lt;/p&gt;
&lt;p&gt;Having &lt;code&gt;light-dark()&lt;/code&gt; makes it trivial to support dual color modes in a single stylesheet and doesn’t add too much weight (0.5kb gzip for ~500 variables). It also gives you the ability to switch themes mid-page.&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nd&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;--bg-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;--text-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;/* ...etc */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* Add hard-coded theme overrides */&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;light&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Adding &lt;code&gt;[data-theme=&amp;quot;dark&amp;quot;]&lt;/code&gt; to the body, or any element with color tokens defined, will force that section to be dark mode. The difference here between hanging variable definitions off a class is that you can respect the user preference without using JS to toggle, &lt;code&gt;light-dark()&lt;/code&gt; does all the work.&lt;/p&gt;
&lt;p&gt;Adding dark tier on a light theme is dramatic. Adding light tier on a dark theme sure would stand out. But when yielding light and dark modes over to the browser… something changes. In that situation hardcoding a theme mode into HTML loses a bit of meaning because I’m not controlling the theme anymore, the user is. What I actually want is the theme to be “opposite” the current theme. After a handful of attempts I think I came across a solution that’s easy to understand, maintain, and I even wrote a polyfill for you.&lt;/p&gt;
&lt;h2&gt;Automatic inversion with [data-theme=“inverted]&lt;/h2&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;400&quot; data-pen-title=&quot;[data-theme=&amp;amp;quot;inverted&amp;amp;quot;]&quot; data-version=&quot;2&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;zxKpvLq&quot; data-user=&quot;davatron5000&quot; style=&quot;height: 400px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/editor/davatron5000/pen/019d27b8-d501-760e-8832-877024393885&quot;&gt;
  [data-theme=&amp;quot;inverted&amp;quot;]&lt;/a&gt; by Dave Rupert (&lt;a href=&quot;https://codepen.io/davatron5000&quot;&gt;@davatron5000&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;
&lt;script async src=&quot;https://public.codepenassets.com/embed/index.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;The goal was to make it so that when the browser switched from light/dark modes, themed elements would switch to their inverse theme. The trick I uncovered was setting the current theme as a CSS variable:&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nd&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;c&quot;&gt;/* Initialize the theme variables */&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
	&lt;span class=&quot;err&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;prefers-color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* Have data-theme use the variable */&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* Update hard-coded themes to use the variable */&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;light&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The reason we use manage  &lt;code&gt;--theme&lt;/code&gt; variable instead of purely &lt;code&gt;color-scheme&lt;/code&gt; is because we can pass that into a &lt;code&gt;style()&lt;/code&gt; query. An that’s the magic that enables inverted themes:&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;c&quot;&gt;/* Add style query magic ✨ */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;inverted&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;py&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;data-theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;inverted&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;py&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Again, the nice thing here is that we’re not creating two different trees of variables or re-redefining variables inside &lt;code&gt;[data-theme=&amp;quot;inverted&amp;quot;]&lt;/code&gt;, we’re relying on &lt;code&gt;light-dark()&lt;/code&gt; and &lt;code&gt;color-scheme&lt;/code&gt; to do the heavy lifting. We’re contextually updating the &lt;code&gt;color-scheme&lt;/code&gt; and letting the browser negotiate the cascade.&lt;/p&gt;
&lt;p&gt;I added a &lt;code&gt;.funky&lt;/code&gt; card theme to the demo to give an idea of how far you might be able to push this tech. &lt;a href=&quot;https://blog.kizu.dev/querying-the-color-scheme/&quot;&gt;Roman Kamorov noted&lt;/a&gt; in his post on &lt;em&gt;Querying the Color Scheme&lt;/em&gt; something Vadim Makeev said on a Russian podcast that while this inversion trick is neat, people who prefer dark-mode (e.g. for medical reasons) probably want dark mode and not to be flash-banged mid-page. That’s something to think about and I think I have some ideas about that but I’d love to see/hear yours.&lt;/p&gt;
&lt;h2&gt;Polyfilling browser support&lt;/h2&gt;
&lt;p&gt;At the time of writing this trick only works in Safari 18+ and Edge/Chrome 111+. Firefox is the outlier but the good news is container style queries is on the roadmap for &lt;a href=&quot;https://hacks.mozilla.org/2026/02/launching-interop-2026/&quot;&gt;Interop 2026&lt;/a&gt; and behind a flag in nightly. That gives you two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Roll out a bespoke polyfill for &lt;code&gt;[data-theme=&amp;quot;inverted]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Do nothing. Wait it out.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given that I know the experience will auto-upgrade for Firefox users at some point this year, I’m prone to wait it out per the rules of progressive enhancement. If it falls back to the current theme, I don’t think the world falls over.&lt;/p&gt;
&lt;p&gt;However, you probably support browsers outside the latest version and what’s acceptable for a fallback depends on your company’s understanding of the eventual consistency of browsers. iOS devices version-locked at Safari 17.4 are of particular concern for me, so I wrote an inverted theme polyfill.&lt;/p&gt;
&lt;p&gt;The CSS style-query-support detection is pretty simple, but quirky.&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;c&quot;&gt;/* Style query support check */&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--syle-query-support&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;--syle-query-support&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There’s a new &lt;code&gt;@supports at-rule()&lt;/code&gt; function that would be more idiomatic, but &lt;a href=&quot;https://www.bram.us/2026/03/15/at-rule/&quot;&gt;you can’t detect at-rule function support&lt;/a&gt; with &lt;code&gt;at-rule()&lt;/code&gt; so we have to do this variable hack. Ideally we could do this purely in JS with &lt;code&gt;CSS.supports()&lt;/code&gt;, but alas. Booleans in CSS, what could go wrong?&lt;/p&gt;
&lt;p&gt;That brings us to the JavaScript part which is pretty simple as well but comes with &lt;strong&gt;one big potential tradeoff&lt;/strong&gt;…&lt;/p&gt;
&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;js&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Polyfill for inverted themes using a `--theme` variable in a style query
 * ⚠️ The use of `getComputedStyle` can trigger layout and style recalcs
 */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isContainerStyleQueriesSupported&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bodyElStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hasStyleQueries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bodyElStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;--syle-query-support&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hasStyleQueries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isContainerStyleQueriesSupported&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;invertedThemes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;[data-theme=&quot;inverted&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  
    &lt;span class=&quot;nx&quot;&gt;invertedThemes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;--theme&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;invertedTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;invertedTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because we need to get the computed value of  &lt;code&gt;--style-query-support&lt;/code&gt;, &lt;a href=&quot;https://gist.github.com/paulirish/5d52fb081b3570c81e3a&quot;&gt;&lt;code&gt;getComputedStyle&lt;/code&gt; is known to trigger style recalcs and layout reflows&lt;/a&gt;, effectively penalizing all users not just browsers that don’t support container style queries. I tested this out by putting the polyfill inside a &lt;code&gt;setTimeout&lt;/code&gt;, turning on paint flashing, and checking the &lt;a href=&quot;https://daverupert.com/2024/09/dev-tools-performance-monitor-panel/&quot;&gt;Performance Monitor panel&lt;/a&gt; and I didn’t see any recalcs or layout reflows, but your mileage may vary depending on your setup.&lt;/p&gt;
&lt;p&gt;Anyways, happy inverting! Let me know if you do something cool with it or if you already figured this out 10 months ago and I didn’t see your blog post.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 Apr 2026 15:31:00 +0000</pubDate>
        <link>https://daverupert.com/2026/04/inverted-light-dark/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/04/inverted-light-dark/</guid>
      </item>
    
      <item>
        <title>Ozempic dreams</title>
        <description>&lt;p&gt;&lt;tt&gt;It’s a secret to everyone! This post is for RSS subscribers only.
&lt;a href=&quot;https://daverupert.com/rss-club/&quot;&gt;Read more about RSS Club&lt;/a&gt;.
&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;I’ve heard the term “Ozempic face” for awhile. People have opinions about that one, but I tend to feel like we should be comfortable with bodies changing. There’s also “Ozempic butt” and there’s even “Ozempic penis”. I’ll let you search those up on your own but they’re also related to physical changes from losing weight.&lt;/p&gt;
&lt;p&gt;I started Wegovy, a GLP-1 like Ozempic, in December and the weight line is trending down down. That’s a good place to be and while I’m not experiencing any of the above symptoms, there has been one noticeable change. One thing I wasn’t prepared for was a change to my dreaming and sure enough “Ozempic dreams” are a thing (at least on Reddit).&lt;/p&gt;
&lt;p&gt;Since starting GLP-1 my dreams have been much more vivid. Colors are more colorful. Weirdness more weird. People more real. Dialogue more rich. Storylines are more complex and multi-layered, not linear. If I wake up in the middle of the night I can seamlessly resume at the previous checkpoint.&lt;/p&gt;
&lt;p&gt;They nearly fall under the category of “lucid dreams” where you know you’re dreaming and can control them. It’s not every night, but when it happens I sleep harder and wake up more rested. Like most dreams I don’t remember the details after waking up, but I do remember the sensation of “Wow, this is a wild and complex dream.”&lt;/p&gt;
&lt;p&gt;I’m curious what’s causing it: change in diet, calorie deficiency, blood sugar, or (as some claim) a hormone in the GLP-1? I don’t know and realize my experience is entirely anecdotal hearsay, but what a weird yet welcome side effect. Is this what dreams are like for people with better peptides?&lt;/p&gt;
</description>
        <pubDate>Sat, 04 Apr 2026 19:18:00 +0000</pubDate>
        <link>https://daverupert.com/2026/04/ozempic-dreams/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/04/ozempic-dreams/</guid>
      </item>
    
      <item>
        <title>Before I go: People like it when other people make things</title>
        <description>&lt;p&gt;I’ve watched a billion hours of YouTube and I’ve noticed a common trend: Whether that’s a drawing, a video game, a song, a cake, or a whole-ass off-grid house; I’ve learned that it’s fun to watch people make something. Since the beginning of humanity, the act of slapping two rocks together to make an arrowhead or a fire will draw a crowd. I feel like mankind has an innate curiosity to pause and say “Oooh, whatcha making?” We like it when others make. This might not even be unique to humans, have you ever seen a &lt;a href=&quot;https://www.youtube.com/watch?v=1XkPeN3AWIE&quot;&gt;bowerbird nest&lt;/a&gt;? Incredible.&lt;/p&gt;
&lt;p&gt;The Maker Movement harnessed that creative attention energy and built an entire subculture around it. I’ve been watching &lt;a href=&quot;https://www.youtube.com/@Wintergatan&quot;&gt;the same guy make a musical marble machine for ten years&lt;/a&gt;. Practical effects artists Adam Savage and Jamie Hyneman built their entire TV show Mythbusters around this premise. We are problem solvers, all of us. The process can often be as enjoyable as the final object. I’d go so far to say they built the empires of YouTube, TikTok, and Instagram on the same principle: it’s fun to watch (hot) people make something even if that “something” is a video about fingernails.&lt;/p&gt;
&lt;p&gt;I harp on my kids from time-to-time about making. We’re pretty permissive about device time but I frequently try to impart that we give them these devices as tools for creativity, not just brainrot. Kids are innately creative, so they understand my intent. But black rectangles are powerful energy vampires. From time to time though I’m blessed with an artwork, animation, a short film, an overdubbed movie trailer, or a half-built Roblox game. And those go on the proverbial refrigerator in my heart.&lt;/p&gt;
&lt;p&gt;I suppose there’s limits to this thesis. Watching someone make a murder machine wouldn’t be fun. Watching someone make war, not fun.&lt;/p&gt;
&lt;p&gt;Watching someone make numbers by typing into the random number generator isn’t that fun. But if there’s some novel, reason, or idea behind it… you could convince me it isn’t slop. I don’t particularly find the medium of decoupage enjoyable but with the right artistic mindset, curiosity, or obsession… sure? And if a bird assembles a house from trash, well I love that.&lt;/p&gt;
&lt;p&gt;Some like to draw thin blurry lines and some prefer to draw thick crisp lines, I love to see and read both. And I’m glad the term “slop” exists because we as a creative species created a label for the abstract idea of thoughtless outputs from a thoughtless content extruder.&lt;/p&gt;
&lt;p&gt;So, make something. Or not. I don’t care. Actually, I do care. Please make something. With your hands, or your brain, or your feet… wait, no that has other connotations.&lt;/p&gt;
</description>
        <pubDate>Sat, 04 Apr 2026 17:00:00 +0000</pubDate>
        <link>https://daverupert.com/2026/04/make-something/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/04/make-something/</guid>
      </item>
    
      <item>
        <title>People are not friction</title>
        <description>&lt;p&gt;The &lt;a href=&quot;https://blog.jim-nielsen.com/2025/a-in-ai-stands-for-amnesia/&quot;&gt;Gell-Mann Amnesia Effect of AI&lt;/a&gt; is a pretty well documented phenomenon:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Gell-Mann amnesia effect is a cognitive bias describing the tendency of individuals to critically assess media reports in a domain they are knowledgeable about, yet continue to trust reporting in other areas despite recognizing similar potential inaccuracies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Summarizing, AI sounds like an incredible genius synthesizing the world’s knowledge right up until you ask it about the thing you know about, then it’s an idiot. Even knowing about this phenomenon and having experienced it countless times, LLMs have an intoxicating quality to them.&lt;/p&gt;
&lt;p&gt;If there’s one thing LLMs do well, it’s delivering an enormous blast of dopamine if they do a good job on the first try. That “if” does a lot of heavy lifting, but when it happens you start to believe the idea that the multi-modal chat box could make you faster and infinitely capable. A hop and a skip and hundreds of dollars in tokens later, you made something that would take lifetimes of learning to create.&lt;/p&gt;
&lt;p&gt;The marketing around Generative AI is that every person can be their own Designer, Developer, Researcher, Content Writer, Video Producer, and Podcast Editor. With the right &lt;code&gt;skills.md&lt;/code&gt; files everything will fall into place. We will automate all automatable tasks. The experience will be “&lt;a href=&quot;https://nazhamid.com/journal/the-hunt/&quot;&gt;frictionless&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;You’ll be able to automate away the jobs you don’t enjoy…&lt;br /&gt;
And the jobs you don’t know how to do…&lt;br /&gt;
And the people who do those jobs…&lt;br /&gt;
The people you don’t enjoy…&lt;/p&gt;
&lt;p&gt;You won’t need to talk to or wait on anyone. You can automate away anything or anyone that stands in your way. You will reduce costs. You will be richer. It will be frictionless.&lt;/p&gt;
&lt;p&gt;Sometimes I feel like there’s a palpable tension in the air as if we’re waiting to see whether AI will replace designers or engineers first. Designers empowered by AI might feel those pesky nay-saying, opinionated engineers aren’t needed anymore. Engineers empowered with AI might feel like AI creates designs that are good enough for most situations. Backend engineers feel like frontend engineering is a solved problem. Frontend engineers know scaffolding a CRUD app or an entire backend API is simple fodder for the agent. Meanwhile, management cackles in their leather chairs saying “Let them fight…”&lt;/p&gt;
&lt;p&gt;I think it’s a dangerous place to be when we start to consider people as friction.&lt;/p&gt;
&lt;p&gt;That’s because we know Gell-Mann is real. We know there’s an &lt;a href=&quot;https://en.wikipedia.org/wiki/Optimism_bias&quot;&gt;optimism bias&lt;/a&gt; the size of the sun blinding us to the actual quality of what the machine is producing. We need knowledgeable people to share what they know to improve the quality of our work, generated or otherwise. We even need ignorant people to make sure we can break ideas down into their simplest form that everyone, agents or human, understand. People can have bad attitudes, be shitty, and have wrong opinions… but people are not friction. An LLM may be able to autocorrect its way into a plausible human response, but it’s not people. It doesn’t care if it’s right or wrong. The money and hype surrounding it acts as a shield to its reputation. LLMs make up answers if it doesn’t have enough context and they fall over if it has too much context. It amplifies good patterns the same as bad patterns. And it glazes you with flattering language the entire time so that chart go up.&lt;/p&gt;
&lt;p&gt;People, the context-bearers, have experience and capabilities that machines might never understand encoded in our muscles and memory. I’m on record saying I despise nuance –&lt;em&gt;and I do&lt;/em&gt;– but it’s more important than ever to be able to connect to our fellow humans over this nuance so our world is not paved over by contextless opinions from ill-informed robots. Empower and believe people over machines.&lt;/p&gt;
</description>
        <pubDate>Fri, 20 Mar 2026 15:54:00 +0000</pubDate>
        <link>https://daverupert.com/2026/03/people-are-not-friction/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/03/people-are-not-friction/</guid>
      </item>
    
      <item>
        <title>Smaller and dumber</title>
        <description>&lt;p&gt;If I can make it smaller, I should.&lt;/p&gt;
&lt;p&gt;If I can make it dumber, I should.&lt;/p&gt;
&lt;p&gt;Smaller, dumber things have more applications, go more places, and require less maintenance.&lt;/p&gt;
</description>
        <pubDate>Mon, 23 Feb 2026 05:33:00 +0000</pubDate>
        <link>https://daverupert.com/2026/02/smaller-and-dumber/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/02/smaller-and-dumber/</guid>
      </item>
    
      <item>
        <title>Priority of idle hands</title>
        <description>&lt;p&gt;I had a small, intrusive realization the other day that computers and the internet are probably bad for me. I mean that beyond the general advice to touch grass. From an ADHD and generalized anxiety perspective, computers and the internet have become an endless supply of poison pills for my brain; feeds full of constant dopamine hits with doom at every turn.&lt;/p&gt;
&lt;p&gt;This is hard to accept because a lot of my work, hobbies, education, entertainment, news, communities, and curiosities are all on the internet. I love the internet, it’s a big part of who I am today, but I understand how its incentive structures harm me. I’m not planning to unplug and go off-grid yet, but it did inspire me to come up with a “&lt;a href=&quot;https://www.w3.org/TR/html-design-principles/#priority-of-constituencies&quot;&gt;priority of constituencies&lt;/a&gt;” for my idle hands and downtime:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Instruments over pads of paper over laptop over tablet over phone.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 23 Feb 2026 03:13:00 +0000</pubDate>
        <link>https://daverupert.com/2026/02/computers-were-a-mistake-for-me/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/02/computers-were-a-mistake-for-me/</guid>
      </item>
    
      <item>
        <title>Magic Words</title>
        <description>&lt;p&gt;Skills are the newest hype commodity in the world of agentic AI. Skills are text files that optionally get stapled onto the context window by the agent. You can have skills like “frontend design” or “design tokens” and if the LLM “thinks” it needs more context about that topic, it can import the contents of those files into the context to help generate a response.&lt;/p&gt;
&lt;p&gt;Generally speaking, skills do an okay job at providing on-demand context. Assuming the AI model is always 12-to-18 months behind in its training data, a skill could potentially backfill any recent framework updates. A skill could potentially undo some training data biases. A skill could potentially apply some of your sensibilities to the output. I’ve seen some impressive results with design guidance skills… but I’ve also seen tons of mediocre results from the same skills. That’s why I deliberately use the word “potentially”. When skills can be optionally included, it’s hard to understand the &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; behind how they get applied.&lt;/p&gt;
&lt;p&gt;In that way, skills remind me a bit of magic numbers.&lt;/p&gt;
&lt;p&gt;In programming “&lt;a href=&quot;https://en.wikipedia.org/wiki/Magic_number_(programming)&quot;&gt;magic numbers&lt;/a&gt;” are a pattern you typically try to avoid. They’re a code smell that you haven’t actually solved the problem, but found a workaround that only works in a particular context. They’re a flashing light that you have brittle logic somewhere in your system. “We don’t know why, but setting the value to &lt;code&gt;42&lt;/code&gt; appears to have fixed the issue” is a phrase that should send shivers down the spine.&lt;/p&gt;
&lt;p&gt;And so now we have these “magic words” in our codebases. Spells, essentially. Spells that work sometimes. Spells that we cast with no practical way to measure their effectiveness. They are prayers as much as they are instructions.&lt;/p&gt;
&lt;p&gt;Were we to sit next to each other and cast the same spell from the same book with the same wand; one of us could have a graceful floating feather and the other could have &lt;em&gt;avada kedavra&lt;/em&gt;’d their guts out onto the floor. That unstable magic is &lt;em&gt;by design&lt;/em&gt;. That element of randomness –to which the models depend– still gives me apprehension.&lt;/p&gt;
&lt;p&gt;There’s an opaqueness to it all. I understand how listing skills in an &lt;code&gt;AGENTS.md&lt;/code&gt; gives the agent context on where to find more context. But how do you know if those words are the right words? If I cut the amount of words (read: “tokens”) in a skill in half, does it still work? If I double the amount of words, does it work better? Those questions matter when too little context is not enough context and too much context causes context rot. It also matters when you’re charged per-token and more tokens is more time on the GPU. How do you determine the “Minimum Viable Context” needed to get quality out of the machines?&lt;/p&gt;
&lt;p&gt;That sort of quality variance is uncomfortable for me from a tooling perspective. Tooling should be highly consistent and this has a “works on my machine” vibe to it. I suppose all my discomfort goes away if I quit caring about the outputs. If I embrace the cognitive dissonance and switch to a “ZOMG the future is amazeballs” hype mode, my job becomes a lot easier. But my brain has been unsuccessful in doing that thus far. I like magic and mystery, but hope- or luck-based development has its challenges for me.&lt;/p&gt;
&lt;p&gt;Looking ahead, I expect these types of errant conjurations will come under more scrutiny when the free money subsidies run out and consumers inherit the full cost of the models’ mistakes. Supply chain constraints around memory and GPUs are already making compute a scarce resource, but our Gas Towns plunder onward. When the cost of wrong answers goes up and more and more people spend all their monthly credits on hallucinations, that will be a lot of dissatisfied users.&lt;/p&gt;
&lt;p&gt;Anyways, all this changes so much. Today it’s skills, before that MCP, before that PRDs, before that prompt engineering… what is it going to be next quarter? And aren’t those all flavors of the same managing context puzzle? Churn, churn, churn, I suppose.&lt;/p&gt;
&lt;p&gt;File under: &lt;code&gt;non-determinism&lt;/code&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 09 Feb 2026 16:03:00 +0000</pubDate>
        <link>https://daverupert.com/2026/02/magic-words/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/02/magic-words/</guid>
      </item>
    
      <item>
        <title>Write about the future you want</title>
        <description>&lt;p&gt;There’s a lot that’s not going well; politics, tech bubbles, the economy, and so on. I spend most of my day reading angry tweets and blog posts. There’s a lot to be upset about, so that’s understandable. But in the interest of fostering better discourse, I’d like to offer a challenge that I think the world desperately needs right now: It’s cheap and easy to complain and say “[Thing] is bad”, but it’s also free to share what you think would be better.&lt;/p&gt;
&lt;p&gt;If complaining worked, we would have won the culture war already. We’d have a reformed Elon and the White House wouldn’t be committing crimes against humanity. But that’s not the world we live in. The one we live in is much worse. If you hate the here and now, write about what would be a better future. Write about &lt;em&gt;what’s good&lt;/em&gt; and why &lt;em&gt;more of that good&lt;/em&gt; would &lt;em&gt;be good&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you believe the current trend in tech is exploitative, write about tech that isn’t. What impresses you? What compromises did you make? Are you happy? Does giving money to a small bootstrapped company feel ten thousand times better than a large venture-backed company like I imagine? Can you list some of those out for me? Show me where I can throw my dollars.&lt;/p&gt;
&lt;p&gt;If you detest content theft at a massive scale, describe a world where copyright matters. Tell me how you’re only going to watch TikToks with royalty free music from now on and not use an ad-blocker. Tell me how you’re going to delete that hard-drive of pirated content. No? Then invent a better copyright system! Talk about the commons and how we should tax people who abuse it by taking more than they give. What does that system look like?&lt;/p&gt;
&lt;p&gt;If you detest the ecological impact of AI data centers, propose an alternative piece of technology that drives shareholder value. Or advocate for a broader, more equitable definition of &lt;a href=&quot;https://www.ibm.com/think/topics/responsible-ai&quot;&gt;Responsible AI&lt;/a&gt;. Don’t let the Effective Altruists define the terms. &lt;a href=&quot;https://dbushell.com/ai/&quot;&gt;Itemize the problems&lt;/a&gt; and then dream up a version that doesn’t have those. List demands. Find levers. Or make the case for how small, local, private, and less energy-intensive models are probably “good enough” for most use cases and we should stop burning barrels of crude and use those instead. If we must throw it away, point people to organizations and political groups working towards that end.&lt;/p&gt;
&lt;p&gt;If you believe billionaires are the problem, talk about a world without them. Share how we redistribute a billionaire tax equitably and talk about the impact it has on society. Make a spreadsheet or a chart. Get into numbers. Talk about degrowth. I know that “Line Goes Up” has problems and won’t work forever, but how are my family and I more okay if we undo centuries of continued economic growth and technical acceleration.&lt;/p&gt;
&lt;p&gt;I think history is wrought with examples of this working; Dr. King’s “I have a Dream” speech, the Federalist Papers, David Hasselhoff singing at the Berlin Wall during the height of the Cold War… the list goes on. Few will rise to the level of Ambassador Hasselhoff, but I don’t have to look far to find people around me who have inspired me by writing about the future they want.&lt;/p&gt;
&lt;p&gt;After repeated mass layoffs, &lt;a href=&quot;https://ethanmarcotte.com/&quot;&gt;Ethan Marcotte&lt;/a&gt; identified a problem with the wealth and labor dynamics in the tech industry. While Ethan could have been perfectly happy bitching about it on Twitter, he didn’t do that. Instead, he put hands to keyboard and made a talk, which turned into &lt;a href=&quot;https://ethanmarcotte.com/books/you-deserve-a-tech-union/&quot;&gt;a book&lt;/a&gt;, about what he feels is the time-tested solution to our predicament: Unions. Truthfully, I’m not particularly predispositioned to be pro-union (Texan, etc), but Ethan and I agree on the problem. Seeing Ethan &lt;a href=&quot;https://journal.stuffwithstuff.com/2026/01/24/the-value-of-things/&quot;&gt;spend time&lt;/a&gt; to communicate the problem and explore the solution changed my opinion on unions. And while I certainly still have nuanced questions, Ethan convinced me that collective action is the best leverage workers have against abuses of labor. That wouldn’t have happened without Ethan’s dedication to highlighting the problem &lt;em&gt;and the solution&lt;/em&gt; over many years.&lt;/p&gt;
&lt;p&gt;Often people need you to &lt;em&gt;show, not tell&lt;/em&gt; the alternative. You need to paint a picture. Not a full complete picture, but one where a person can paint themselves in it. When people want change and bad change is happening all around them, that’s a hopeless place. Build a raft of opportunity that people can latch onto in the rough open waters, instead of hitting them with spears.&lt;/p&gt;
</description>
        <pubDate>Wed, 04 Feb 2026 15:45:00 +0000</pubDate>
        <link>https://daverupert.com/2026/02/futurescapes/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/02/futurescapes/</guid>
      </item>
    
      <item>
        <title>I&apos;m swearing off APIs entirely</title>
        <description>&lt;p&gt;I got a lot of ideas for side projects rattling around in the old tin can. As part of my “No new projects” initiative, I’m trying to jump on building prototypes so I can decide if I want to explore ideas more or call it quits. A handful of my ideas are riffs or twists on existing app categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A tennis ranking app… but modern and performant&lt;/li&gt;
&lt;li&gt;A nearby historical marker app… but with CarPlay support&lt;/li&gt;
&lt;li&gt;A nearby real estate listing app… but with CarPlay support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All three of those have ended unceremoniously at the same dead end: no API access. USTA denied my application for tennis rankings. The aptly named Historical Marker Database site doesn’t have a public API. And you have to be an MLS® Realtor® or Broker to get access to the MLS® listings. Womp womp.&lt;/p&gt;
&lt;p&gt;Scraping the data is always an option… but I don’t like the ethics of that and worry about the brittleness of that dependency.&lt;/p&gt;
&lt;p&gt;Ugh. I wish I could build these little apps so that tens of people could enjoy them. I’d even be willing to pay a small API access fee ($10/mo?) and run these at a loss but whatever happened to free APIs. When I &lt;a href=&quot;https://github.com/public-api-lists/public-api-lists&quot;&gt;survey the land of public APIs&lt;/a&gt; it feels like we’ve lost a lot since the Web 2.0 days where API access was almost a God-given right.&lt;/p&gt;
&lt;p&gt;To prevent this time loop of disappointment from happening again, I’m swearing off APIs entirely. That’s a hard stance, but I need a backstop at the idea phase to prevent me from wasting limited life force. If I don’t have the data, or can’t generate the data, or it’s not an open protocol… it’s not worth building or even thinking about.&lt;/p&gt;
&lt;p&gt;OAuth apps are a good option and generally the best way to exfiltrate data because it’s tied to a user’s account…. but you still might run into call limits, incomplete endpoints, user-scope limitations, and so on. History also shows us what the future holds. There’s a Tweetbot-style risk when building on a someone else’s platform. Even if your app drives activity to the parent application, your access might get cut because it competes or doesn’t drive stakeholder value. And if the idea isn’t big enough, being “a feature, not a product” is also a bad position to be in, lest you get Sherlock’d.&lt;/p&gt;
&lt;p&gt;Where’s that leave me and my pile of side project ideas? Thankfully… in a good place. I can close out these project tabs and free up some much needed Brain RAM. It sounds strange but “No more APIs” makes “Making video games” jump up in the viability rankings for side projects too, because games have closed ecosystems. Or I could spend more time writing shitty sci-fi. Write a serial. Print some zines. Who knows.&lt;/p&gt;
&lt;p&gt;If the goal of “No new projects” is to finish more projects than I start, then I have to accept that part of figuring out which ideas to explore means “&lt;a href=&quot;https://www.youtube.com/watch?v=RfiQYRn7fBg&quot;&gt;Nope&lt;/a&gt;” is a potential answer. It’s also not a total loss, I’m learning along the way. For example, &lt;a href=&quot;https://developer.apple.com/download/files/CarPlay-Developer-Guide.pdf&quot;&gt;CarPlay only lets you choose from eight pre-approved templates&lt;/a&gt;. There’s also pre-defined app categories and diverting in the slightest would almost guarantee App Store rejection. That sucks the fun out it… but ayyyy, I’ll probably try again. But now I know the limitation for future projects and its in the limitations where play begins.&lt;/p&gt;
</description>
        <pubDate>Mon, 26 Jan 2026 06:27:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/hitting-my-api-limits/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/hitting-my-api-limits/</guid>
      </item>
    
      <item>
        <title>Waiting for the power to go out</title>
        <description>&lt;p&gt;&lt;tt&gt;It’s a secret to everyone! This post is for RSS subscribers only.
&lt;a href=&quot;https://daverupert.com/rss-club/&quot;&gt;Read more about RSS Club&lt;/a&gt;.
&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;It’s expected to freeze this evening in Austin and we may even see snow, which is exciting and novel for us Texans. But as we’ve learned in 2021 and 2023, cold snaps can lead to disaster. In those years the ice dealt untold damages as foot-thick tree limbs fell from the canopy like enormous glass Cadillacs. The crackle, pop, followed by crystalline shatter in the cold dead air is a sound I won’t forget. With the falling trees came down power lines and the lights went out.&lt;/p&gt;
&lt;p&gt;It got worse. &lt;a href=&quot;https://www.kut.org/the-disconnect&quot;&gt;The disconnected Texas power grid failed&lt;/a&gt;. As homes and empty office buildings required more heating in the “extreme” cold, the rolling blackouts began to shed load. Except… they didn’t roll. Homes next to facilities (hospitals, fire stations, and water treatment plants) deemed critical were fine, but the rest of us were off-grid in the cold for nearly a week. The energy companies could have met capacity, but quit making energy because they would have had to sell it at a loss. Greed until the state promised them a windfall.&lt;/p&gt;
&lt;p&gt;The infrastructure failed. Pipes burst, homes flooded, and trauma increased. While our senator and his banker wife fled to Mexico to stay in a Ritz Carlton, Texans burned their IKEA furniture and cedar fences to stay warm.&lt;/p&gt;
&lt;p&gt;Building on past lessons, we’ve made all the preparations for today; external faucets capped, plants covered, and I built a cabinet out of foam board insulation for our external hot water heater. And now we wait… we wait to see if the Libertarian Capitalist systems my state has put into place will hold up. Waiting to see if the power goes out. Waiting for the impending disaster.&lt;/p&gt;
&lt;p&gt;If you’ve ever had a child, you might know this feeling. You’ve taken the classes, assembled the crib, child-proofed the outlets, and then you wait… you wait for your life to change. While the miracle of childbirth is a beautiful event, any mother can tell you it’s not without some drawbacks. From prolonged labor, painful contractions, episiotomies, and beyond… every birth is a dice-roll of potentially life-threatening complications. A friend of mine who had three kids described it well; “Having a baby is like knowing you’ll be in a car accident.”&lt;/p&gt;
&lt;p&gt;That feeling of pregnant, expectant waiting dominates a lot of my life right now as I wait for all the larger meta narratives in our country to unravel. I’m waiting for a mid-term election, one where I feel the fabric of democracy hangs by a thread. I’m waiting for an opposition party that has a fucking plan, but I don’t see one yet. I’m waiting for a particular person to leave office… or (preferred) die of natural causes. I’m waiting for the full release of the Epstein files, so the victims of billionaire pedophilia and human trafficking can have justice. I’m waiting for the government to stop its reign of cruelty on its own people, but masked fascists killed another innocent person in broad daylight today. I’m waiting for the economy to work for most Americans, not only the wealthy. I’m waiting for either the tech bubble to pop or for the robots to take my job… either way I’d like this story line to wrap up soon but I must ask, is there a third option? I’m waiting for the next big thing and praying it’s something that makes the world more loving and kind, but a new global religion would be a lot to deal with right now.&lt;/p&gt;
</description>
        <pubDate>Sat, 24 Jan 2026 21:44:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/waiting-for-the-power-to-go-out/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/waiting-for-the-power-to-go-out/</guid>
      </item>
    
      <item>
        <title>The best version of my site so far...</title>
        <description>&lt;p&gt;You might have noticed that I did a big design refresh on my entire site… unless you’re on RSS I guess. I’ll talk about aspects in detail, but at a high level there’s been three big changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A monospace font&lt;/li&gt;
&lt;li&gt;Named CSS grid lines&lt;/li&gt;
&lt;li&gt;Juicier multi-page view transitions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But my most favorite part is that today  (when you set &lt;code&gt;html { --hue-rotate: 15 }&lt;/code&gt;), my light theme looks like a stick of butter. And that brings me joy.&lt;/p&gt;
&lt;h2&gt;What didn’t change&lt;/h2&gt;
&lt;p&gt;Before I talk about what changed, here’s a quick list of the parts of my site that didn’t change:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Same big “Dave” SVG on the homepage&lt;/li&gt;
&lt;li&gt;Same information architecture, no radical content changes.&lt;/li&gt;
&lt;li&gt;No new assets, same visuals.&lt;/li&gt;
&lt;li&gt;Same &lt;a href=&quot;https://daverupert.com/2025/01/color-hue-rotating-gaslight/&quot;&gt;hue-rotating background&lt;/a&gt;, although I did simplify the formula.&lt;/li&gt;
&lt;li&gt;Same &lt;a href=&quot;https://daverupert.com/2025/06/fittext-too-attr-boogaloo/&quot;&gt;inverse text-sizing&lt;/a&gt; for H1s&lt;/li&gt;
&lt;li&gt;Same &lt;a href=&quot;https://daverupert.com/2021/01/art-direction-for-static-sites/&quot;&gt;support for art-directed posts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why change the parts you’re happy with, eh? Knowing what you want to change versus what you don’t want to change makes the whole process go faster.&lt;/p&gt;
&lt;h2&gt;All-in on a monospace font&lt;/h2&gt;
&lt;p&gt;My type system always falls apart. I start with a good setup and I’m guaranteed to ruin it over time. Whenever I read a site with a nice typeface and reasonable CPL, I started to feel like my &lt;code&gt;system-ui&lt;/code&gt; based body text styles were letting me down. It didn’t feel cozy.&lt;/p&gt;
&lt;p&gt;Then I saw &lt;a href=&quot;https://robinrendle.com/&quot;&gt;Robin Rendle&lt;/a&gt;’s latest redesign (which is wonderful, btw) I wondered… Could I be a &lt;code&gt;monospace&lt;/code&gt; font guy? Is that me? Do I identify as that? Is it too emo? Does it come off as a bad developer pun like &lt;code&gt;bleep blorp I&apos;m a programmer and using a computer bleep blorp&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;All good questions to ask myself and exposes some insecurity I have, but I couldn’t shake the idea so I went for it.&lt;/p&gt;
&lt;p&gt;The entire site is now set in &lt;code&gt;Cascadia Mono&lt;/code&gt; which is a variant of Microsoft’s &lt;a href=&quot;https://github.com/microsoft/cascadia-mono&quot;&gt;Cascadia Code&lt;/a&gt;. That decision is unintentionally on-brand for my current stage of life. Initially I wanted to use &lt;a href=&quot;https://levien.com/type/myfonts/inconsolata.html&quot;&gt;Inconsolata&lt;/a&gt; by Raph Levien, but it didn’t have a “numero” (№) symbol – which is a common missing glyph in a lot of indie fonts – and is an unfortunate piece of critical typographical infrastructure with my &lt;a href=&quot;https://daverupert.com/tag/vibecheck&quot;&gt;vibechecks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In general I love the change. It feels very “me” right now. I worry about the readability of monospace fonts some, but I don’t think I was winning the Legibility Wars before.&lt;/p&gt;
&lt;h2&gt;Naming my grid lines&lt;/h2&gt;
&lt;p&gt;Improving the grid on my site is something I’ve wanted to do for nearly two years. The max-width container I had was fine before, but I relied a lot on &lt;a href=&quot;https://daverupert.com/2017/03/full-bleed-with-not/&quot;&gt;margin overrides&lt;/a&gt; to change a container that &lt;a href=&quot;https://daverupert.com/2017/03/thoughts-on-negative-margins/&quot;&gt;felt like a hack&lt;/a&gt; that in my experience don’t scale.&lt;/p&gt;
&lt;p&gt;Now I have something better with some sweet tech from &lt;a href=&quot;https://smolcss.dev/#smol-breakout-grid&quot;&gt;Stephanie Eckles&lt;/a&gt; that I saw on &lt;a href=&quot;https://www.youtube.com/watch?v=c13gpBrnGEw&quot;&gt;Kevin Powell’s YouTube&lt;/a&gt; called “Named Grid Lines”. A not-so-well-known feature of grid is you can name the gutters in your grid template. The result is a grid that looks like this:&lt;/p&gt;
&lt;grid-container-demo&gt;
  &lt;div class=&quot;full&quot;&gt;Full&lt;/div&gt;
  &lt;div class=&quot;margin&quot;&gt;Margin&lt;/div&gt;
  &lt;div class=&quot;wide&quot;&gt;Wide&lt;/div&gt;
  &lt;div class=&quot;outdent&quot;&gt;Outdent&lt;/div&gt;
  &lt;div&gt;Content (Default)&lt;/div&gt;
&lt;/grid-container-demo&gt;
&lt;p&gt;See how all the grids collapse into one line that’s offset from the edge? That’s what I want. And then to use it, you specify the &lt;code&gt;*-start&lt;/code&gt; and &lt;code&gt;*-end&lt;/code&gt; line you tweak your container with a modifier class and make all the children start at a different grid line.&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nc&quot;&gt;.foo.container&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;grid-column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wide-start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wide-end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;c&quot;&gt;/* or grid-column: wide */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This gives me a lot of scalable control for my layout at the template level. For example, the layout of my homepage looks like this:&lt;/p&gt;
&lt;grid-container-demo&gt;
  &lt;div class=&quot;outdent&quot;&gt;Header&lt;/div&gt;
  &lt;div class=&quot;outdent&quot;&gt;Logo&lt;/div&gt;
  &lt;div&gt;Latest Posts&lt;/div&gt;
  &lt;div&gt;Projects&lt;/div&gt;
  &lt;div class=&quot;outdent&quot;&gt;Footer&lt;/div&gt;
&lt;/grid-container-demo&gt;
&lt;p&gt;But when you click through to a single post, the template shifts to this:&lt;/p&gt;
&lt;grid-container-demo&gt;
  &lt;div class=&quot;outdent&quot;&gt;Header&lt;/div&gt;
  &lt;div class=&quot;outdent-end&quot;&gt;Title Goes Here&lt;/div&gt;
  &lt;div&gt;Content&lt;/div&gt;
  &lt;div class=&quot;outdent-end&quot;&gt;Media&lt;/div&gt;
  &lt;div&gt;Content&lt;/div&gt;
    &lt;div&gt;Content&lt;/div&gt;
  &lt;div class=&quot;outdent-end&quot;&gt;Media&lt;/div&gt;
    &lt;div&gt;Content&lt;/div&gt;
    &lt;div&gt;Content&lt;/div&gt;
  &lt;div class=&quot;outdent&quot;&gt;Footer&lt;/div&gt;
&lt;/grid-container-demo&gt;
&lt;p&gt;I don’t have this setup, but I could write out a system of utility classes to make all this super flexible.&lt;/p&gt;
&lt;grid-container-demo&gt;
  &lt;div class=&quot;full-start&quot;&gt;.full-start&lt;/div&gt;
  &lt;div class=&quot;margin-start&quot;&gt;.margin-start&lt;/div&gt;
  &lt;div class=&quot;wide-start&quot;&gt;.wide-start&lt;/div&gt;
  &lt;div class=&quot;outdent-start&quot;&gt;.outdent-start&lt;/div&gt;
  &lt;div&gt;Default Content&lt;/div&gt;
  &lt;div class=&quot;outdent-end&quot;&gt;.outdent-end&lt;/div&gt;
  &lt;div class=&quot;wide-end&quot;&gt;.wide-end&lt;/div&gt;
  &lt;div class=&quot;margin-end&quot;&gt;.margin-end&lt;/div&gt;
  &lt;div class=&quot;full-end&quot;&gt;.full-end&lt;/div&gt;
&lt;/grid-container-demo&gt;
&lt;p&gt;That’s a lot of different layouts to craft. I look forward to more sustainable art direction for years to come. No more hacky negative margins or fixed positioned items… right?&lt;/p&gt;
&lt;h2&gt;More Multipage View Transitions&lt;/h2&gt;
&lt;p&gt;I’ve had &lt;a href=&quot;https://daverupert.com/2023/05/getting-started-view-transitions/&quot;&gt;multi-page view transitions on my site&lt;/a&gt; for years now. The original was a title transition from the index template to the post template where the post title would do a subtle swoop up and morph from an &lt;code&gt;H3&lt;/code&gt; to display-sized &lt;code&gt;H1&lt;/code&gt;. This was great until I changed the font for my &lt;code&gt;H1&lt;/code&gt; (see above) and I obliterated the slight of hand magic I had before. Oops.&lt;/p&gt;
&lt;p&gt;Now the flagship animation on my site is not typography dependent. If you navigate through my site, you’ll see that the “Dave” SVG on the homepage transitions into the main navigation on subpages. As a bonus, I get a little bit of much-needed branding on subpages. I didn’t do anything special other than naming the view transition and beefing up the stroke when the logo is in its smaller form.&lt;/p&gt;
&lt;p&gt;The main nav is out-dented a bit by default, but using my new named columns I made the navigation go wider to match wide pages like my Bookshelf. Flexbox’s &lt;code&gt;justify-content: space-between&lt;/code&gt; and view-transitions is doing all the heavy lifting on that animation there but I’m pleased with the effect and it feels natural (aka not synthetic and cheap).&lt;/p&gt;
&lt;p&gt;I’m not a motion expert like &lt;a href=&quot;https://cydstumpel.nl/&quot;&gt;Cyd Stumpel&lt;/a&gt;, but it feels good to have big, bold, un-ignorable view transitions on my site.&lt;/p&gt;
&lt;h2&gt;Slimmed down CSS&lt;/h2&gt;
&lt;p&gt;A redesign is always a great opportunity to clean house. I did the thing where I deleted my entire CSS and started from a naked page. Bit-by-bit I pulled back in the pieces I still needed.&lt;/p&gt;
&lt;p&gt;I have about 40% less CSS which manifests in ~150 less lines of code to maintain and up to &lt;code&gt;~0.8 KB&lt;/code&gt; when compressed over the wire.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;LoC&lt;/th&gt;
&lt;th&gt;Raw&lt;/th&gt;
&lt;th&gt;Min+Gzip&lt;/th&gt;
&lt;th&gt;Min+Brotli&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Before&lt;/td&gt;
&lt;td&gt;557&lt;/td&gt;
&lt;td&gt;10.3 KB&lt;/td&gt;
&lt;td&gt;2.76 KB&lt;/td&gt;
&lt;td&gt;2.43 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After&lt;/td&gt;
&lt;td&gt;391&lt;/td&gt;
&lt;td&gt;5.36 KB&lt;/td&gt;
&lt;td&gt;1.97 KB&lt;/td&gt;
&lt;td&gt;1.76 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Now &lt;code&gt;0.8 KB&lt;/code&gt; isn’t much but because I inline my critical CSS the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; on every page, this number matters. My entire homepage document is &lt;code&gt;~5.5 KB&lt;/code&gt; (Brotli), so that’s a 10%~20% performance improvement from cleaning up my CSS. How did I get these gains, you ask? Well…&lt;/p&gt;
&lt;p&gt;One reason my CSS smaller is because I’m using modern CSS (nesting, &lt;code&gt;:has()&lt;/code&gt;, &lt;code&gt;:is()&lt;/code&gt;, &lt;code&gt;:where()&lt;/code&gt;, &lt;code&gt;:not()&lt;/code&gt;, etc). Those features seem like minor syntactic sugar but you also get more efficient selectors. For example my out-denting that I do in posts would previous be something like:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.post iframe, 
.post video, 
.post img,
.post table { }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In modern CSS that super-conjoined selector becomes something more expressive and elegant:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.post :is(iframe, video, img, table) {}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Those small improvements add up, but another reason the CSS is smaller is because its doing a lot less. Other than my inverse-sized H1s in posts, I’m not managing type styles at all beyond setting the body font-size. I think this is what Andy Bell calls “&lt;a href=&quot;https://bell.bz/be-the-browsers-mentor-not-its-micromanager/&quot;&gt;Be the Browser’s Mentor, Not Its Micromanager&lt;/a&gt;”. My strategy here is: Don’t futz with it until you can think of something way better than what the browser already does. That seems very &lt;a href=&quot;https://alistapart.com/article/dao/&quot;&gt;Dao&lt;/a&gt; or &lt;a href=&quot;https://frankchimero.com/blog/2015/the-webs-grain/&quot;&gt;Web’s Grain’y&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Onward to more art direction!&lt;/h2&gt;
&lt;p&gt;This redesign opens up a bright future for my site. I’ve already started on some of this work, but I’ll share that in a future post. I mentioned above but the named grid lines alone give me a lot of easy-to-use levers for expression. I touched up some &lt;a href=&quot;https://daverupert.com/2020/04/oh-the-paywalls-you-ll-meet/&quot;&gt;old art-directed posts&lt;/a&gt; and they are benefitting from the changes already.&lt;/p&gt;
&lt;p&gt;“Make it easy to play” seems like a good ethos for a personal site and I feel like I have that in the current manifestation.&lt;/p&gt;
</description>
        <pubDate>Sun, 18 Jan 2026 14:29:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/my-2026-redesign/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/my-2026-redesign/</guid>
      </item>
    
      <item>
        <title>Focus rings with nested contrast-color()?</title>
        <description>&lt;p&gt;As I was playing around with &lt;code&gt;contrast-color()&lt;/code&gt;, I got a wild idea that you could use &lt;code&gt;contrast-color()&lt;/code&gt; to invert its return value by nesting it: &lt;code&gt;contrast-color(contrast-color(var(--some-color))&lt;/code&gt;. When would this be useful? Uh… Good question. I couldn’t come up with an example right away but after a bit I found one sitting right under my nose….&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.daverupert.com/posts/2026/focus-rings.jpg&quot; alt=&quot;four buttons in one line. a secondary button, an accented primary button with a focus state, a subtle button and a transparent button&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Our focus-rings in &lt;a href=&quot;https://storybooks.fluentui.dev/web-components/&quot;&gt;Fluent&lt;/a&gt; use a 1px inset white highlight and a 2px offset black focus-ring. It’s a smidge chonkier than the Chromium default. The reason we do this is to guarantee contrast against the focused-element, in the above example, a blue button. Without the addition of the white stroke, the black outline wouldn’t “pop” with enough contrast to the blue background.&lt;/p&gt;
&lt;p&gt;To make this work, we have a &lt;code&gt;--focus-inner-ring&lt;/code&gt; token and a &lt;code&gt;--focus-outer-ring&lt;/code&gt; token themed for both light and dark modes.&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus-visible&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--focus-inner-ring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--focus-outer-ring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;How would this change with nested &lt;code&gt;contrast-color()&lt;/code&gt;?&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus-visible&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--page-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--page-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;All you would need is one token you probably already have (&lt;code&gt;--page-bg&lt;/code&gt;) vs two tokens. Neat.&lt;/p&gt;
&lt;p&gt;One consideration… your focus-ring isn’t always on a &lt;code&gt;--page-bg&lt;/code&gt;. Sometimes it shows up on a &lt;code&gt;--card-bg&lt;/code&gt; and this little trick might fall apart. As always, your mileage may vary.&lt;/p&gt;
&lt;p&gt;Aside: This got me thinking it’d be nice to have a &lt;code&gt;currentBackgroundColor&lt;/code&gt; like we have &lt;code&gt;currentColor&lt;/code&gt; in CSS today.  I’m not sure how much career I’ve got left to wait for that, but who knows.&lt;/p&gt;
&lt;h2&gt;On second thought…&lt;/h2&gt;
&lt;p&gt;Mulling this over a bit more… you might be better off using &lt;code&gt;color-scheme&lt;/code&gt; and &lt;code&gt;light-dark()&lt;/code&gt; for this instead.&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt; &lt;span class=&quot;nd&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	 &lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
 &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus-visible&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nl&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
   &lt;span class=&quot;nl&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
   &lt;span class=&quot;nl&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Yeah… I’d probably do that. You dodge the spotty &lt;code&gt;contrast-color()&lt;/code&gt; support and have a singular function instead of a nested situation. It keeps it simple and readable.&lt;/p&gt;
&lt;p&gt;If you converted this to tokens, you’d probably need four tokens to fill out the inner/outer and light/dark matrix. But I’d consider not using custom color tokens for focus-rings at all and embrace the higher contrast… or limit tokens to the outer-ring.&lt;/p&gt;
</description>
        <pubDate>Sun, 11 Jan 2026 18:30:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/nested-contrast-color-focus-rings/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/nested-contrast-color-focus-rings/</guid>
      </item>
    
      <item>
        <title>Interpolate contrast-color() to manipulate lightness</title>
        <description>&lt;p&gt;In &lt;a href=&quot;https://daverupert.com/2026/01/algorithmic-hover-states-with-contrast-color/&quot;&gt;my first post on &lt;code&gt;contrast-color()&lt;/code&gt;&lt;/a&gt; I demo’d using &lt;code&gt;color-mix()&lt;/code&gt; to change a background-color on hover, but I will be honest… mixing black and white isn’t always what you want. It would be cool and helpful to coerce  &lt;code&gt;contrast-color()&lt;/code&gt; to return either &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;-1&lt;/code&gt; so that we could adjust lightness in a color function on hover instead of only mixing white and black.&lt;/p&gt;
&lt;p&gt;Building on the inline CSS &lt;code&gt;if()&lt;/code&gt; statements &lt;a href=&quot;https://daverupert.com/2026/01/contrast-color-with-custom-design-tokens/&quot;&gt;in my last post&lt;/a&gt;, we can use the same trick to interpolate the result of &lt;code&gt;contrast-color()&lt;/code&gt; into a number.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Disclaimer: All caveats from the previous post about browser support, caching quirks, and expected syntax changes still apply.&lt;/small&gt;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;500&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;myPogBv&quot; data-pen-title=&quot;contrast-color() powered design system colors &quot; data-user=&quot;davatron5000&quot; style=&quot;height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
      &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/davatron5000/pen/myPogBv&quot;&gt;
  contrast-color() powered design system colors &lt;/a&gt; by Dave Rupert (&lt;a href=&quot;https://codepen.io/davatron5000&quot;&gt;@davatron5000&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
      &lt;/p&gt;
      &lt;script async src=&quot;https://public.codepenassets.com/embed/index.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;Ahh… feel that? Now our states maintains its harmonious color palette where mixing in white or black gets us a bit muddier results. We’re picking another note on the scale of the color’s lightness ramp.&lt;/p&gt;
&lt;p&gt;The relevant CSS to make this trick work goes like this:&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;c&quot;&gt;/* Needed for if() statement */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--captured-color&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;syntax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;&amp;lt;color&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;inherits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;initial-value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* https://lea.verou.me/blog/2024/contrast-color/ */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--bg-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--l-threshold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.623&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-infinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;--captured-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--lighter-or-darker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--captured-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* go extra lighter */&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;-1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* go darker */&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;  
  &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
  
	&lt;span class=&quot;err&quot;&gt;&amp;amp;:hover,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&amp;amp;:focus&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
			&lt;span class=&quot;n&quot;&gt;calc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--lighter-or-darker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; 
		&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For comparison’s sake, I web-inspected up a little apples-to-apples, side-by-side of the &lt;a href=&quot;https://cdpn.io/pen/debug/myPogBv&quot;&gt;adjusting lightness way&lt;/a&gt; and the &lt;a href=&quot;https://cdpn.io/pen/debug/bNpzYzX&quot;&gt;color-mixing way&lt;/a&gt; of algorithmic hover states where it’s 10% lightened/darkened versus 10% mix of white/black.&lt;/p&gt;
&lt;img src=&quot;https://cdn.daverupert.com/posts/2026/colormixing.png&quot; alt=&quot;a side by side look at adjusting lightness vs mixing in white and black. the rest for all the buttons is on top and the hover state for all the buttons is on the bottom. The hover states for the buttons on the adjusting lightness demo are a bit warmer, but probably hard to notice to the average person.&quot;&gt;
&lt;p&gt;The difference is almost imperceptible, but the hover states from the “Adjust Lightness” method feel a tad bit warmer, particularly on the bottom row with the green, blue, and purple buttons. The difference becomes more obvious if the step is greater than 10%.&lt;/p&gt;
&lt;p&gt;Unless your customers are a bunch of color dorks, they probably won’t see it the care you put into this. But I’m willing to wager that even if they don’t see the difference, they will be able to feel the difference.&lt;/p&gt;
&lt;p&gt;We also get a lot more control with this &lt;code&gt;if()&lt;/code&gt; statement route. For example, I can set the lighten amount to &lt;code&gt;2.5&lt;/code&gt; (+25%) instead of &lt;code&gt;1&lt;/code&gt; (+10%) because that’s what felt better. If you’re algorithmically generating your color palettes, it should be easy to find the ideal values; either a step-up or step-down, perhaps. And we’re also not just limited to lightness! You could mess with chroma or whatever the &lt;code&gt;b&lt;/code&gt; in &lt;code&gt;lab()&lt;/code&gt; is. Find what makes sense for your system.&lt;/p&gt;
&lt;p&gt;A part of me wants to take this even further to get more control. For example, if the color is super dark (e.g. black) and the lightness value is below &lt;code&gt;0.1&lt;/code&gt;, lighten by 25%, otherwise lighten by 10%. That might be possible with an &lt;code&gt;if()&lt;/code&gt; inside the &lt;code&gt;oklch()&lt;/code&gt; or a &lt;code&gt;sin()&lt;/code&gt; function… but that sounds like a lot of Math and probably hurts readability. More experiments to do though.&lt;/p&gt;
&lt;p&gt;It’s fun to embark on this new world of algorithmic color schemes in vanilla CSS. While I’m excited to play, I’m more excited to see what your beautiful brains come up with.&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Jan 2026 15:35:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/coercing-contrast-color/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/coercing-contrast-color/</guid>
      </item>
    
      <item>
        <title>Using your design system colors with contrast-color()</title>
        <description>&lt;p&gt;One predictable pain point with &lt;code&gt;contrast-color()&lt;/code&gt; is that it only returns &lt;code&gt;black&lt;/code&gt; and &lt;code&gt;white&lt;/code&gt; named colors. From a design systems perspective, that’s not ideal because you want &lt;em&gt;your&lt;/em&gt; colors. You want your harmonious brand and the colors you and your team spent thousands of man hours in meetings deciding on. Those colors.&lt;/p&gt;
&lt;p&gt;In fact, &lt;a href=&quot;https://css-tricks.com/exploring-color-contrast-for-the-first-time/&quot;&gt;an earlier version of Safari had &lt;code&gt;color-contrast()&lt;/code&gt;&lt;/a&gt; (confusing I know, naming is hard) which allowed you to pass in a list of best candidates to choose from. I beleive that proposal got mired in standards discussions, color contrast algorithms, and competing proposals; and &lt;code&gt;contrast-color()&lt;/code&gt; is what survived which got simplified down to a binary result.&lt;/p&gt;
&lt;p&gt;In the future though, we can use &lt;code&gt;contrast-color()&lt;/code&gt; and &lt;code&gt;if()&lt;/code&gt; together to help pick the value we want. Alas, at the time of writing no browser supports both &lt;code&gt;if()&lt;/code&gt; and &lt;code&gt;contrast-color()&lt;/code&gt;.  But we can use &lt;a href=&quot;https://lea.verou.me/blog/2024/contrast-color/&quot;&gt;Lea Verou’s &lt;code&gt;--contrast-color()&lt;/code&gt; workaround&lt;/a&gt; to experiment with how this will work in Chromium today.&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;500&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;myPogBv&quot; data-pen-title=&quot;contrast-color() powered design system colors &quot; data-user=&quot;davatron5000&quot; style=&quot;height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
      &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/davatron5000/pen/myPogBv&quot;&gt;
  contrast-color() powered design system colors &lt;/a&gt; by Dave Rupert (&lt;a href=&quot;https://codepen.io/davatron5000&quot;&gt;@davatron5000&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
      &lt;/p&gt;
      &lt;script async src=&quot;https://public.codepenassets.com/embed/index.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;The CSS to get this working looks something like this:&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;k&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--captured-color&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;syntax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;&amp;lt;color&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;inherits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;initial-value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* https://lea.verou.me/blog/2024/contrast-color/ */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--bg-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--l-threshold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.623&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-infinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--ds-text-white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;wheat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--ds-text-black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;darkslategray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--captured-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  
  &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--captured-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-text-white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--ds-text-black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And that’s it! Using (a form of) &lt;code&gt;contrast-color()&lt;/code&gt; you can select the proper tokens from your design system. Cool.&lt;/p&gt;
&lt;p&gt;One quirky bit needed to make it work is defining a type for &lt;code&gt;--captured-color&lt;/code&gt; using CSS &lt;code&gt;@property&lt;/code&gt;, &lt;a href=&quot;https://blog.kizu.dev/captured-custom-properties/&quot;&gt;a trick I learned from Roma Komarov&lt;/a&gt;. To be honest I don’t fully understand &lt;em&gt;the why&lt;/em&gt; behind Registered Custom Properties and the &lt;a href=&quot;https://drafts.css-houdini.org/css-properties-values-api/#calculation-of-computed-values&quot;&gt;Computed Value Time Behavior&lt;/a&gt; superpower, but my simple brain created a rule “If you’re going to compare a variable to a &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt; in a CSS &lt;code&gt;if()&lt;/code&gt; statement, make sure to register the variable as a &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt;.”&lt;/p&gt;
&lt;p&gt;If/when any of the browsers start supporting both features, I expect we’ll have to update &lt;code&gt;oklch(1 0 0)&lt;/code&gt; in the style query to &lt;code&gt;white&lt;/code&gt; or &lt;code&gt;rgb(255 255 255)&lt;/code&gt;.  At least, I hope it works that way.&lt;/p&gt;
&lt;p&gt;One unexpected challenge that I encountered with this demo was that if I abstracted out the &lt;code&gt;if&lt;/code&gt; statement out into its own custom function, it would break. I’m not 100% sure why but I think it’s based on how CSS functions cache results. I’ll have to dig into this more, but I’m happy the inline &lt;code&gt;if&lt;/code&gt; statement works. Hopefully someone smarter can figure it out.&lt;/p&gt;
&lt;p&gt;Anyways, exiting times. And can we pause for a moment and marvel at how this is all vanilla 2026 CSS?! What a world.&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Jan 2026 03:21:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/contrast-color-with-custom-design-tokens/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/contrast-color-with-custom-design-tokens/</guid>
      </item>
    
      <item>
        <title>Algorithmic hover states with contrast-color()</title>
        <description>&lt;p&gt;Firefox 146 added support for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/contrast-color&quot;&gt;&lt;code&gt;contrast-color()&lt;/code&gt;&lt;/a&gt; joining Safari 26 in the First Implementor’s Club. For those unfamiliar, &lt;code&gt;contrast-color(&amp;lt;color&amp;gt;)&lt;/code&gt;  is a new CSS function that will take a &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt; as input and returns either  &lt;code&gt;white&lt;/code&gt; or &lt;code&gt;black&lt;/code&gt; depending on which has the most contrast.&lt;/p&gt;
&lt;p&gt;The quintessential example is choosing a foreground text &lt;code&gt;color&lt;/code&gt;  with the best contrast.&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; 
	&lt;span class=&quot;c&quot;&gt;/* @returns black (5.25:1 WCAG AA Pass) 
			not white (3.99:1 WCAG AA Fail) */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If someone changes &lt;code&gt;--button-bg&lt;/code&gt; to purple, the foreground color automatically resolves to the either white or black, whichever has more contrast. It avoids having to set an extra token for color and takes the guess work out of picking an accessible foreground color.&lt;/p&gt;
&lt;p&gt;I think this is going to be an incredible boon to design systems where I don’t control what &lt;code&gt;--button-bg&lt;/code&gt; is, but I do care about providing accessible experiences. And I think that’s the goal of this feature; to have “smart defaults” that lead to more accessible websites, easier algorithmically-driven color systems, and better “theme a whole website from a single color picker” demos.&lt;/p&gt;
&lt;h2&gt;Sure contrast-color() can do foreground colors, but what about backgrounds?&lt;/h2&gt;
&lt;p&gt;We’re having conversations at work about algorithmically driven rest/hover/active states for Buttons. In the current &lt;a href=&quot;https://web.dev/baseline/&quot;&gt;Baseline&lt;/a&gt; you can use &lt;code&gt;color-mix()&lt;/code&gt; to lighten/darken colors on &lt;code&gt;:hover&lt;/code&gt;…&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

	&lt;span class=&quot;err&quot;&gt;&amp;amp;:hover,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&amp;amp;:focus&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srgb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;90%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;no&quot;&gt;black&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10%&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The code above will dim your button on &lt;code&gt;:hover&lt;/code&gt; 10% by mixing in black. But what if our Buttons are already dark (black, navy, etc)? In that situation we want to lighten the background-color instead of dimming. We can glue on new classes like &lt;code&gt;button.lighten-on-hover&lt;/code&gt; or &lt;code&gt;button.invert-hover&lt;/code&gt; and that works… until we get to light and dark theme modes of our Button where you probably want to lighten/darken oppositely depending on the mode…&lt;/p&gt;
&lt;p&gt;Ugh. In that situation you’d have &lt;code&gt;@media (prefers-color-scheme: dark)&lt;/code&gt;, &lt;code&gt;[data-theme=&amp;quot;dark&amp;quot;]&lt;/code&gt; styles in your Button styles and people are mad now because the Button styles are too complex. There’s got to be a better way!&lt;/p&gt;
&lt;p&gt;Well, do I have good news for you…&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;500&quot; data-default-tab=&quot;result&quot; data-slug-hash=&quot;bNpzYzX&quot; data-pen-title=&quot;contrast-color() powered lighten/darken bg on hover &quot; data-user=&quot;davatron5000&quot; style=&quot;height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
      &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/davatron5000/pen/bNpzYzX&quot;&gt;
  contrast-color() powered lighten/darken bg on hover &lt;/a&gt; by Dave Rupert (&lt;a href=&quot;https://codepen.io/davatron5000&quot;&gt;@davatron5000&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
      &lt;/p&gt;
      &lt;script async src=&quot;https://public.codepenassets.com/embed/index.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;Per my previous conversations, I wondered if we could use &lt;code&gt;contrast-color()&lt;/code&gt;  to programmatically lighten/darken an button based on its current &lt;code&gt;background-color&lt;/code&gt;. If the Button is black, and the contrast-color is white, let’s mix in white (and vice versa):&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;nd&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;color-scheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;py&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light-dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;navyblue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lightpurple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color-contrast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

	&lt;span class=&quot;err&quot;&gt;&amp;amp;:hover,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&amp;amp;:focus&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srgb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
			&lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10%&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Huzzah! Now our Button’s hover states go in the desired direction and our foreground &lt;code&gt;color&lt;/code&gt; is intrinsically styled based on its own &lt;code&gt;background-color&lt;/code&gt;. Nice. From a design systems perspective I’m pretty excited about the possibility to remove a bunch of state-based tokens from our collection.&lt;/p&gt;
&lt;h3&gt;Now available in… everywhere?&lt;/h3&gt;
&lt;p&gt;This approach only works in Safari and Firefox. However, if I use &lt;a href=&quot;https://lea.verou.me/blog/2024/contrast-color/&quot;&gt;Lea Verou’s method of polyfilling &lt;code&gt;contrast-color()&lt;/code&gt;&lt;/a&gt;, we can pop in a custom &lt;code&gt;@function --contrast-color()&lt;/code&gt; that works in Chromium 139+. The final working solution looks like this:&lt;/p&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;c&quot;&gt;/* @function supported in Chromium */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--bg-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--l-threshold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.623&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-infinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oklch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--bg-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;/* contrast-color() supported in Safari &amp;amp; Firefox */&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;--button-fg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  
  &lt;span class=&quot;err&quot;&gt;@supports&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;--button-fg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;--contrast-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;nt&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--button-fg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  
  &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:hover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srgb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;--button-fg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10%&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Depending on your browser matrix, this may work for you. It’s probably a &lt;em&gt;smidge&lt;/em&gt; too new for us to roll out to customers, right now but for personal sites heck yeah.&lt;/p&gt;
&lt;p&gt;This is interesting tech and I’m excited to dig in more. And spoiler alert, this is the first post in a small little series I have already written up for you.&lt;/p&gt;
</description>
        <pubDate>Thu, 08 Jan 2026 16:46:00 +0000</pubDate>
        <link>https://daverupert.com/2026/01/algorithmic-hover-states-with-contrast-color/</link>
        <guid isPermaLink="true">https://daverupert.com/2026/01/algorithmic-hover-states-with-contrast-color/</guid>
      </item>
    
  </channel>
</rss>

