2025-10-30 02:46:00
Debate was dead long before Charlie Kirk was shot in the neck.
==There has never existed a genuine marketplace of ideas where Tabula Rasa rational actors approached a memetic battlefield ready to hear out all sides and come to the best argued conclusion.== It was always a pretender to praxis.
If you're skeptical, I ask you recall the argument that shifted (significantly, in the way you desire in others) one of your current positions. In your heart of hearts do you believe you were reprogrammed by a perfectly strung together argument, promptly conceded and adopted the new position? No. You experienced an unpleasant encounter with a member of your own ingroup, or a new entertaining content sphere, or a new community, or something more profound. Your behaviours changed in some meaningful way and your belief system followed.
It is well enough studied I feel no need to cite it that ==people adopt the beliefs that are convenient to them.== Maintaining beliefs that help them preserve their status, relationships and material wealth, as well as their personal psychostructural schema. Policy prescriptions large and small (take smoking bans for example) imposed on a disgruntled population frequently, indeed usually, find themselves more popular AFTER they have been undemocratically enacted on the populace. Troubling implications for democracy aside, we are confident that people change their beliefs after they change their behaviours and circumstances. This has far more troubling implications for online discourse.
The ultimate reality of the online debate sphere was to engage in contests of personality ultimately unrelated to the power of ideas. Over time it became less convenient for audiences to support losing personalities and more convenient to support winning ones. Ignorant, naive or selfish creators unwittingly engaged in this atmosphere, while cynical and pragmatic ones understood that ==the real prize was accumulating a fanbase that could then be gradually converted via the only real method of changing hearts and minds that scales cheaply - interpersonal relationships (or their nearest available simulacra - online community).==
Since the importance of ideas/policies/political positions were unrelated to the actual game of status jousting - there was never a real need to remain fixed to a shared reality. To their uncharacteristically unfortunate detriment ==Liberals tend to maintain a position in shared "consensus reality"== - the accumulation of "objective" positions backed by institutions like academia, government and expert opinion. The right-wing, and to a certain extent the far-left1, do not suffer from these same constraints, and eventually the establishment defenders of liberalism were overwhelmed; unable to do anything but signal inwardly to their existing base in order to accumulate power while achieving no actual change in the world.
The savviest ideological2 operators on both sides then changed tactics.
Rather than compete for the same small subset of terminally online viewers, you should instead turn your base into ideological warriors, capable of becoming force multipliers for your ideas. 10 000 viewers are utterly inconsequential - 10 000 culture warriors each speaking to the dozens of people they come into daily contact with is suddenly a serious movement. But we then arrive at one of the fundamental misunderstandings of the space - ==online debates between creators are nothing like persuasively convincing people in the real world.== Worse still, the psychological makeup of the majority of these culture warriors, while useful, is uniquely distinct from the actual population one would want to influence in crucial ways.
It is no coincidence that a huge number of the people who participate in these spaces are, if not literally autistic, operating in an extremely autistic mode (in the same sense one might be operating in a "schizophrenic" mode). I have been known to flippantly declare that "Autism is Evil" and while I maintain the bit, the more nuanced explanation is that the autistic mode of analysis both reinforces, and is highly compatible with, the worst excesses of our current cultural/social/economic systems. ==It is a rigid mode of thinking - emphasising categorisation, hierarchy and an objective root "factful" interpetation of any given event.== In speaking to the many autistic people in this space, I find commonalities in their frustration that regular people "just don't get it" or "lack critical thinking skills". They are terribly frustrated that anyone can support a man like Donald Trump who not only lies, but self-contradicts in loud and obvious ways. They see truth and fact as inherently virtuous and any who oppose them as inherently subversive to a positive formation of society.
I believe the most important reason for this is that, in a world that is very difficult and unpleasant to navigate for the autistic or undersocialised - debate becomes a genuinely useful and productive mode of communicating with other people. It can get you far in your career (again generally only in ways that reinforce the worst elements of our current systems), it can help you overcome social anxieties and awkwardness, it can help you become more like "cool" media personalities and characters like Dr House, Ben Shapiro, Destiny and Elon Musk. Men with money, power, respect and women. ==Online debate is one of the few remaining modern routes to socialisation== and a mode of analysis that follows rigid rules, hierarchies and categorisations.2 Giving this up is painful, no one wants to regress to the point where they feel like an outcast again.
I sympathise, but this mode of analysis and communication has done irreparable harm to society.3 ==The Autistic Mode is a dehumanizing, atomising and spiky approach to worldview development that creates insurmountable incompatibilities with other people and communities== - yielding an end stage of extreme individualism. It is no coincidence that hardline libertarians are the community who have most encouraged debate as the mode of communication between opposing ideologies - with the express purpose of exposing such incompatibilities that the only solution is to endorse the idea that "every man is a state". The internet, a culture initially built and dominated by libertarians with these ideals, was very much built around this worldview. Now that the internet is integrated into the average child's development, this influence is deeply ingrained offline as well.
Most people acknowledge that the increase in ADHD4 diagnosis is influenced by the modern cultural modes and productions that are clearly reshaping human development (e.g. children consuming highly dopaminergic short form video). It is less obviously observable that the same is occurring for autism, but it is. Rigid institutionalism, single-truth categorisation, fetishization of IQ over EQ and structural systems prioritising quantitative over qualitative understanding have trained a generation to lean into their autistic modes of navigating the world in order to become the specialised-laborers and alienated-consumers ideal for a complex economy pursuing infinite growth.5 ==These autistics are a highly valuable labour force== because they prefer a rigid hierarchy to perform within (constructed by someone else though they are frequently blind to this), but once established they will execute with great force and consistency.
For the same reasons they are also lethally effective culture warriors.
We find ourselves, then, with a very particular hierarchy in this memetic space - there exists a pool of potential culture warriors that must themselves be won over in order to benefit from the force multiplier of their advocacy. Importantly, the way that these culture warriors are themselves won over is very different to how one should convince the general public. Online Debate is an "opt-in" system, an intellectual sport like chess - and ==many of the most successful people in the space are surrounded only by those who have opted into the conceits of this system.== They are heavily encouraged both economically and socially to perform in this specific way even though they themselves are not always operating in the autistic mode - indeed the best are generally much more well-rounded than their viewers. Unfortunately as they develop their audiences, their feedback mechanisms become highly dependent on their performance relative to the metrics of this Online Debate Game. Initially (around the beginning of Trump's first term) this actually functioned fairly well - liberalism was the dominant cultural force, institutions were fairly well regarded and all ideologies essentially had to acquiesce in some respects to the liberal conceit that reality is accurately and singularly defined by institutions, experts and democratic governance.
Over time, both through the rise of the far-right in actual governance and continuous pressure around the weaknesses and contradictions of liberalism, the right was able to make crucial cultural gains and begin abandoning this consensus reality defined by liberal institutions. Thought-terminating memetics like "fake news" became sufficient to disregard the liberal frame and this left Online Debate in a precarious position - the right wing was well-versed in operating within the liberal frame in order to eke out small victories here and there, while liberals enjoyed the dominant narrative and establishment backing. When right wing culture began to surpass the liberal status quo we found ourselves in a situation where ==a highly optimised memetic predator hit critical mass and utterly overwhelmed the existing ecosystem.== Now we have liberals who don't know how to operate in any frame other than their own (either totally blackpilled and disengaged, fighting the left over tougher targets or clinging to the delusion that liberal institutions are still dominant and will hold in the face of an authoritarian regime dismantling them) up against the right-wing forged in hostile territory - eager to exercise their newfound power.
Some of Liberalism's suppressive tactics have come back to haunt them here - deplatforming and forcing the right-wing into private, less visible places gave them the perfect substrate to experiment and develop more complex and effective memetic weapons within.6 By contrast, the more publicly accepted far-left often has its novel half-formed and naive cultural products immediately seized, magnified and crystallized by right wing media conglomerates. This forced leftists to either defend a half-finished (and often bad) idea, cede territory or ineffectually attempt to make the complicated, nuanced argument I'm making now to a lay audience in a hostile fast-paced environment. ==The far right benefitted from stealthily developing ideas and tactics in private, sallying out to make attacks into the open field==7 and retreating to iterate out of view. A guerilla war America has lost in the past.
If you also believe that debates are ineffective in the modern day, perhaps for reasons other than those I outlined above8 then you may find the following useful. If you believe debates have a utility and merit today and that with rational discourse and the right argumentation you can win over the average American I will take my own advice, cease to attempt to convince you otherwise and wish you luck.
At a fundamental level, rationalisations follow feeling. Feelings are powerful and useful tools of pattern recognition, compressing vast amounts of incomprehensibly complex data into a format that is mostly correct, most of the time, for most people. ==Importantly, feelings are driven by incentives.== This is intuitive, you encounter noxious stimuli and feel pain to motivate you to retreat from it. You feel hunger to motivate you to pursue food. You feel to compel you to act. Humans are (efficiently) lazy, and will avoid hard work (like changing their psychological structures) in efficient ways. I'd always argue this is a different form of rationality, but most people who advocate for rationalism tend to be dismissive of these "irrational" justifications.
Nevertheless, this is the reality you operate in - if you cannot provide someone an incentive structure to change their beliefs, they will not change their beliefs. ==The first lesson to take from this is to never make it difficult for someone to change their beliefs.== This sounds obvious, and yet without fail debate bros fixate on winning and extracting a humiliating emotional and social cost from everyone they supposedly aim to convince. What's your goal? Are you here to change minds or are you here to win status? You can be honest with yourself, you don't have to tell anyone. Perhaps you wish to earn status now to change minds later? By accumulating power you get to incentivise people directly to change!9 Totally valid, but very frequently one is mistaken for the other.
In this framework, if your goal is to change a mind then your objective, in many ways, should be to lose the "debate." ==You must pay your opponent something in order to incentivise their change,== and if most debaters want the win more than anything else, there are certainly ways to change someone's position while "losing". In fact, the best case scenario here would be for your opponent to gradually take ownership of your position until they claim it was theirs all along, especially to their own audience. I've used this technique frequently myself10 offering people with very strong incentives and drives exactly what they want out of me in exchange for achieving my stated goals.
There are others like Fuentes who'll create memes like "Your Body My Choice" to give white liberal women the precise enemy they crave reacting to in order to gain mainstream prominence. Or MAGA who gave democrats the exact "Deplorables" they wanted (so much so that democrats frequently funded the most extreme candidates on the other side supposedly to weaken their electoral odds) getting free media attention in spades. ==In the liberal frame these always look like losses,== surely the massive backlash against Fuentes or horror at MAGA's worst excesses mean these were self-destructive? Yet they continue to win the electorate and greater mainstream power year by year. Fuentes is on his greatest "generational run" of media appearances from PBD to Red Scare to Tucker Carlson to date.
So once again - never make it difficult for someone to change their beliefs, or alternately - ==always offer someone an incentive for changing their beliefs==. At a more advanced level - offer your opponents an incentive to make a mistake.
But how do we know their incentives genuinely? This is where we come to our second lesson - ==To understand someone's incentives you must genuinely understand them.== Every moment you waste arguing over institutional definitions for phrases they're using like "Critical Race Theory" or the buzzword of the moment, is time that should be spent understanding what they mean by "Critical Race Theory". As the information environment has siloed into various echo chambers, so has language, and your definition is not more valuable or important than theirs (certainly not now that they are in power). So when they declare their unyielding support for the constitution and you bristle certain in the knowledge that they are "lying" - understand what they mean by it. What values do they feel are being represented by their constitution, what incentivises them to declare allegiance to it. ==For gods sake, know the actual answer to the question - "Why did they say that?"==
Ask yourself the important questions about what they are trying to achieve, then formulate a plan of action to provide it for them in exchange for them changing their position. You'll be astonished how quickly their desire for status supercedes the desire for them to convince you of a position. If you're willing to look like an idiot and make them the hero for adopting your position, ==this is a fair exchange of emotional or social capital for cultural capital.==11
Never forget that there is a reason you are in this community, and it is probable that they are there for similar reasons - the things you most want and least want to give up are the same things they most want and least want to give up. Not only does this mean you have insights into their mindset but if you have the excess supply of these things (hopefully borne of your very stable, grass-touching lifestyle, happy homelife, successful career, hobbies and friends) then you will be able to trade these emotional/social/egoic concessions for them adopting pieces of your worldview.
You don't have to. If you have a comfortable position ingroup signalling to your community in exchange for local status gains amongst that group, have at it. If anything, the understanding that you are merely playing a status game is a huge advantage, you may very well have lost to these people and been disturbed and frustrated that you got your ass handed to you despite an adherence to the strict rigor of debate, rationality and logic. ==Status signalling is a natural function of socialisation and everyone does it.== I'm doing it right now, it's basically impossible to avoid. Pretending to yourself that you aren't doing it will oftentimes make you worse at it.
If, however, you have a genuine ideological project - a genuine desire to change minds, change the world and make things better for people you care about, whether trans people, the poor or the white race - these are valuable tools to adopt that will make you more effective at doing so.
What's my incentive? I just want to help of course!11
The far-left erred on the side of a dogmatic approach that involved disengagement from questions (epitomised by Zizeks - 'Ethical progress produces a beneficial form of dogmatism. A normal, healthy society does not debate whether rape and torture are acceptable, because the public “dogmatically” accepts that they are beyond the pale.') in the pursuit of manifesting a society in which these questions did not require engagement. To their (and our) collective misfortune this world does not exist and will not exist in our lifetimes - rendering this choice deeply antipragmatic.↩
By which I mean, those operators whom have an ideological project beyond selfish power accumulation - a genuine desire to change the world rather than merely use politics as a growth mechanism for their personal accumulation of money, power and respect.↩
It being a root cause of many frustrating mechanisms that have resulted in contradictions the far right have been able to exploit for their own mainstream takeover.↩
Yes discovery is one mechanism by which we may see an increase in diagnosis. There is nevertheless, an actual population level increase beyond just our ability to recognise and diagnose autism/adhd.↩
This is of course one of many self-destructive contradictions in the modern system that hollows out culture and labor until it is unable to sustain itself.↩
I've personally spent quite a lot of time in Fuentes' private spaces for supporters and memetic engineers and seen this first hand. One important example was the discourse around Fuentes' front door being approached by an 'SJW'. The first images released were deeply unflattering, framing Fuentes' as a fearful homebody peeking through a crack in the door. I observed in real time as the Groypers (his culture warriors) realised this, were alarmed and immediately began sourcing other stillframes of the available video footage, before settling on a much more flattering shot of Fuentes'stamping on the recording device. After some internal debate and argument they quickly worked in unison to get the resulting memes into the zeitgeist to combat the narrative. I was in awe of the speed, internal mechanisms of production and discipline of response.↩
That public memetic battleground made up of all public spaces for discourse↩
Liberals may feel debate was once valuable but then misinformation destroyed the information environment/everyone suddenly became much stupider and harder to convince. The Far Right (and funnily enough the far left) might believe that debate is worthless in the face of constant psyops by a powerful cabal of elites. Whatever the reason, we agree on the premise.↩
As someone high up in a large tech company my time is sought after. I made it known that the way to guarantee getting this time to convince me to support some project or other is to go out for a vegan meal with me. The fact that the vegan meal is not the focus means it's easy for me to change their mind while they try to change mine about the business case. If you have something people want (and give it to them in exchange for them being malleable) you can create the incentives directly to change people. Pressure like this led to many of my team being far more open to veganism, and even events flipping to vegan catering.↩
If you ever wonder why some of my articles are written like schizophrenic poetry, it's because almost everyone genuinely arrives at the correct meaning while reading it, even as they stare at it in disbelief assured that it is incomprehensible, incorrect or self-aggrandizing. I have, on countless occasions, seen someone state "Smugbug is wrong the real answer is..." followed by my exact position.↩
I discuss this in more detail in (🐌🧠 progressive antipragmatism vs strategic discatharsis)[https://pondscum.gg/progressive-antipragmatism-vs-strategic-discatharsis/].↩
2025-10-30 00:03:00
As part of finding ways to achieve Digital Simplification, I wanted to find the easiest solution to maintain proper levels of privacy and security on my personal devices. Yes, I could go crazy with self-hosted solutions, dive into Mullvad VPN, or Faraday Cages, but that misses the whole point of what I'm trying to accomplish. I want the perfection combination of better-than-good and simple.
Is my final solution perfect? No. Is it better than what 95% of people do? Absolutely. Will I do the same thing on my wife's phone, and she won't want to throw it across the room? I think so. Will moody location aware apps like MLB.tv work consistently? So far, so good.
Here's what I've done and suggest you should do:
Extra: Enable Advanced Data Protection in Settings → iCloud → Advanced Data Protection. This requires all devices with your AppleID to be updated.
This should significantly obstruct what carriers, WiFi owners, and websites can see about you and your activity. More things should be encrypted and anonymized. The overall speed hit should be minimal. And best of all, it should require virtually no maintenance or ongoing upkeep. Set it and forget it.
Have any more tips? Reply on Mastodon.
2025-10-29 17:43:00
On the 25th of October Bear had its first major outage. Specifically, the reverse proxy which handles custom domains went down, causing custom domains to time out.
Unfortunately my monitoring tool failed to notify me, and it being a Saturday, I didn't notice the outage for longer than is reasonable. I apologise to everyone who was affected by it.
First, I want to dissect the root cause, exactly what went wrong, and then provide the steps I've taken to mitigate this in the future.
I wrote about The Great Scrape at the beginning of this year. The vast majority of web traffic is now bots, and it is becoming increasingly more hostile to have publicly available resources on the internet.
There are 3 major kinds of bots currently flooding the internet: AI scrapers, malicious scrapers, and unchecked automations/scrapers.
The first has been discussed at length. Data is worth something now that it is used as fodder to train LLMs, and there is a financial incentive to scrape, so scrape they will. They've depleted all human-created writing on the internet, and are becoming increasingly ravenous for new wells of content. I've seen this compared to the search for low-background-radiation steel, which is, itself, very interesting.
These scrapers, however, are the easiest to deal with since they tend to identify themselves as ChatGPT, Anthropic, XAI, et cetera. They also tend to specify whether they are from user-initiated searches (think all the sites that get scraped when you make a request with ChatGPT), or data mining (data used to train models). On Bear Blog I allow the first kinds, but block the second, since bloggers want discoverability, but usually don't want their writing used to train the next big model.
The next two kinds of scraper are more insidious. The malicious scrapers are bots that systematically scrape and re-scrape websites, sometimes every few minutes, looking for vulnerabilities such as misconfigured Wordpress instances, or .env and .aws files, among other things, accidentally left lying around.
It's more dangerous than ever to self-host, since simple mistakes in configurations will likely be found and exploited. In the last 24 hours I've blocked close to 2 million malicious requests across several hundred blogs.
What's wild is that these scrapers rotate through thousands of IP addresses during their scrapes, which leads me to suspect that the requests are being tunnelled through apps on mobile devices, since the ASNs tend to be cellular networks. I'm still speculating here, but I think app developers have found another way to monetise their apps by offering them for free, and selling tunnel access to scrapers.
Now, on to the unchecked automations. Vibe coding has made web-scraping easier than ever. Any script-kiddie can easily build a functional scraper in a single prompt and have it run all day from their home computer, and if the dramatic rise in scraping is anything to go by, many do. Tens of thousands of new scrapers have cropped up over the past few months, accidentally DDoSing website after website in their wake. The average consumer-grade computer is significantly more powerful than a VPS, so these machines can easily cause a lot of damage without noticing.
I've managed to keep all these scrapers at bay using a combination of web application firewall (WAF) rules and rate limiting provided by Cloudflare, as well as some custom code which finds and quarantines bad bots based on their activity.
I've played around with serving Zip Bombs, which was quite satisfying, but I stopped for fear of accidentally bombing a legitimate user. Another thing I've played around with is Proof of Work validation, making it expensive for bots to scrape, as well as serving endless junk data to keep the bots busy. Both of these are interesting, but ultimately are just as effective as simply blocking those requests, without the increased complexity.
With that context, here's exactly went wrong on Saturday.
Previously, the bottleneck for page requests was the web-server itself, since it does the heavy lifting. It automatically scales horizontally by up to a factor of 10, if necessary, but bot requests can scale by significantly more than that, so having strong bot detection and mitigation, as well as serving highly-requested endpoints via a CDN is necessary. This is a solved problem, as outlined in my Great Scrape post, but worth restating.
On Saturday morning a few hundred blogs were DDoSed, with tens of thousands of pages requested per minute (from the logs it's hard to say whether they were malicious, or just very aggressive scrapers). The above-mentioned mitigations worked as expected, however the reverse-proxy—which sits up-stream of most of these mitigations—became saturated with requests and decided it needed to take a little nap.

The big blue spike is what toppled the server. It's so big it makes the rest of the graph look flat.
This server had been running with zero downtime for 5 years up until this point.
Unfortunately my uptime monitor failed to alert me via the push notifications I'd set up, even though it's the only app I have that not only has notifications enabled (see my post on notifications), but even has critical alerts enabled, so it'll wake me up in the middle of the night if necessary. I still have no idea why this alert didn't come through, and I have ruled out misconfiguration through various tests.
This brings me to how I will prevent this from happening in the future.
This should be enough to keep everything healthy. If you have any suggestions, or need help with your own bot issues, send me an email.
The public internet is mostly bots, many of whom are bad netizens. It's the most hostile it's ever been, and it is because of this that I feel it's more important than ever to take good care of the spaces that make the internet worth visiting.
The arms race continues...
2025-10-29 09:05:16
So you may as well post that thing regardless And have it for yourself Anyone who comes along and enjoys it Is another sprinkle on the cake
I write weirdly So what
Share your weird
2025-10-29 01:24:00

I made a Halloween-inspired theme for Bear last year. This time, I thought I’d just give it a small polish. Well, that didn’t quite happen... 😅
I ended up going all in again, just for the fun of it. So this year you’ll get a spooky cursor, glowing bits, an annoyingly restless bat, and a whole lot more.
No tracking, just hauntingly simple blogging. Hauntman Morbidious
Feel free to use it however you like. Just copy the styles below, head to your theme settings, and paste them in.
Happy haunting! 👻
Update 29/10: 🦇 Fixed the moonwalking Michael Batson... it now flies in the right direction. Thanks Sylvia for pointing it out!
/* =========================
🎃 Bear Halloween Theme 2025
Robert Birming • robertbirming.com
Warning: includes one restless bat.
========================= */
@import url("https://fonts.bunny.net/css2?family=Henny+Penny&family=Nosifer&display=swap");
/* =========================
🧪 Base tokens
========================= */
:root {
--width: 720px;
/* type */
--font-main: "Nosifer", sans-serif;
--font-accent: "Henny Penny", system-ui, sans-serif;
--font-body: Verdana, sans-serif;
--font-scale: 1em;
/* light */
--background-color: #fff9f5;
--heading-color: #1a1a1a;
--text-color: #2c2c2c;
--link-color: #c25400;
--visited-color: #c25400;
--code-background-color: #fff2e5;
--code-color: #222;
--divider: rgba(0, 0, 0, 0.2);
/* candy */
--pumpkin: #ff7a18;
--vampire: #8b6fcb;
/* glow */
--glow-color: #ff7a18;
--glow-color-soft: #ffa24a;
}
@media (prefers-color-scheme: dark) {
:root {
/* darkness */
--background-color: #0d181c;
--heading-color: #f6f6f6;
--text-color: #ddd;
--link-color: #ffa24a;
--visited-color: #ffa24a;
--code-background-color: #111;
--code-color: #ddd;
--divider: rgba(255, 255, 255, 0.25);
--glow-color: #ffa24a;
--glow-color-soft: #ffcf87;
}
}
/* =========================
🏚️ Layout
========================= */
body {
font-family: var(--font-body);
font-size: var(--font-scale);
margin: auto;
padding: 48px 24px 24px;
max-width: var(--width);
line-height: 1.6;
color: var(--text-color);
background:
radial-gradient(900px 600px at 10% -10%, rgba(255, 122, 24, 0.08), transparent),
var(--background-color);
transition: background 0.4s ease;
}
/* =========================
🕸️ Headings
========================= */
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-main);
color: var(--heading-color);
margin-top: 1.4em;
margin-bottom: 0.6em;
letter-spacing: 0.5px;
line-height: 1.2;
text-align: left;
}
h1 { font-size: 1.5em; }
h2 { font-size: 1.3em; }
h3 { font-size: 1.1em; }
h1::before { content: "🕸️ "; }
h2::before { content: "🦇 "; }
h3::before { content: "🕯️ "; }
@media (prefers-reduced-motion: no-preference) {
h1 { animation: flicker 6s infinite steps(60, end); }
@keyframes flicker {
0%, 100% { opacity: 1; }
5% { opacity: 0.85; }
7% { opacity: 0.6; }
8% { opacity: 1; }
}
}
/* =========================
✍️ Text & links
========================= */
p, li, blockquote, figcaption, code, pre, td, th {
font-family: var(--font-body);
}
a {
font-family: var(--font-accent);
color: var(--link-color);
text-decoration: none;
background: none;
text-shadow: none;
transition: text-shadow .25s ease, transform .15s ease;
will-change: text-shadow, transform;
}
a:visited { color: var(--visited-color); }
a:hover,
a:focus-visible {
text-shadow:
0 0 6px var(--glow-color),
0 0 14px var(--glow-color-soft),
0 0 22px var(--glow-color-soft);
transform: translateY(-1px);
}
strong, b { color: var(--heading-color); }
/* =========================
🧭 Title & navigation
========================= */
.title a {
display: inline;
width: auto;
text-decoration: none;
padding: 0;
}
.title h1 {
display: inline;
font-family: var(--font-main);
font-size: 1.3em;
text-align: left;
margin: 0;
letter-spacing: 0.5px;
}
.title h1::after {
content: "👻";
margin-left: 5px;
}
nav {
margin-top: 10px;
}
nav a {
font-family: var(--font-accent);
margin-right: 8px;
border-radius: 6px;
padding: 2px 4px;
outline: none;
background: none;
border: none;
box-shadow: none;
transition: text-shadow .25s ease, transform .15s ease;
}
nav a:hover,
nav a:focus-visible {
text-shadow:
0 0 6px var(--glow-color),
0 0 14px var(--glow-color-soft),
0 0 22px var(--glow-color-soft);
transform: translateY(-1px);
}
nav a:hover,
nav a:focus {
border: none !important;
outline: none !important;
box-shadow: none !important;
}
/* =========================
🪞 Images (haunted flicker)
========================= */
figure {
display: block;
inline-size: 100%;
margin: 1.8rem 0;
}
figure > img,
figure > a > img,
img {
width: 100%;
max-width: 100%;
height: auto;
display: block;
border-radius: 6px;
box-shadow: 0 0 0 1px var(--divider);
transition: transform 0.3s ease, box-shadow 0.4s ease, filter 0.4s ease;
}
img:not(:hover) {
filter: brightness(1);
}
@keyframes haunted-flicker {
0%, 100% { filter: brightness(1); }
10% { filter: brightness(0.85); }
12% { filter: brightness(1.1); }
14% { filter: brightness(0.7); }
20% { filter: brightness(1); }
}
img:hover {
transform: translateY(-2px) rotate(-0.5deg);
animation: haunted-flicker 1.2s steps(6, end);
box-shadow:
0 0 6px var(--glow-color),
0 0 14px var(--glow-color-soft),
0 6px 20px rgba(255, 122, 24, 0.25);
filter: brightness(1.05);
}
@media (prefers-reduced-motion: reduce) {
img:hover {
animation: none !important;
}
}
figure figcaption {
font-family: 'Courier New', monospace;
font-size: 0.95rem;
color: color-mix(in oklab, var(--text-color) 85%, crimson 20%);
text-align: center;
margin-top: 0.5em;
text-shadow: 0 0 4px rgba(255, 0, 0, 0.2);
opacity: 0.9;
transition: opacity 0.3s ease, text-shadow 0.4s ease;
}
figure:hover figcaption {
opacity: 1;
text-shadow: 0 0 8px rgba(255, 0, 0, 0.4);
}
/* =========================
🪵 Dividers
========================= */
hr {
border: 0;
height: 14px;
margin: 2rem 0;
background:
linear-gradient(to right, transparent, var(--divider), transparent) center/100% 1px no-repeat,
radial-gradient(6px 6px at left center, var(--divider) 1px, transparent 1px),
radial-gradient(6px 6px at right center, var(--divider) 1px, transparent 1px);
}
/* =========================
📝 Lists
========================= */
ul, ol { padding-left: 1.4rem; margin: 1em 0; }
ul li::marker { content: "🎃 "; }
ul ul li::marker { content: "🟠 "; opacity: 0.7; }
/* =========================
🗯️ Blockquotes (warm glow)
========================= */
blockquote {
position: relative;
margin: 1.6em 0;
padding: 1.2em 1.4em 1em;
font-style: italic;
font-family: var(--font-body);
color: color-mix(in oklab, var(--text-color) 90%, transparent);
background: radial-gradient(circle at top left, rgba(255, 122, 24, 0.08), transparent 65%);
border-radius: 6px;
box-shadow:
0 0 6px var(--glow-color),
0 0 14px var(--glow-color-soft),
inset 0 0 12px rgba(255, 122, 24, 0.15);
transform: translateY(-2px);
transition: transform 0.25s ease, box-shadow 0.3s ease;
}
blockquote::before {
content: "“";
position: absolute;
left: 12px;
top: -10px;
font-size: 2.8rem;
line-height: 1;
opacity: 0.12;
color: var(--glow-color);
pointer-events: none;
}
blockquote cite {
display: block;
margin-top: 0.75em;
font-style: normal;
font-family: var(--font-body);
font-size: 0.9em;
text-align: left;
opacity: 0.85;
color: color-mix(in oklab, var(--text-color) 75%, transparent);
letter-spacing: 0.3px;
}
blockquote cite::before {
content: "— ";
opacity: 0.6;
}
/* =========================
🧑💻 Code
========================= */
code, pre, .highlight {
font-family: "Courier New", monospace;
background: linear-gradient(180deg, rgba(255, 122, 24, 0.08), var(--code-background-color) 40%);
color: var(--code-color);
border-radius: 5px;
padding: 3px 6px;
}
pre, .highlight {
display: block;
padding: 1em;
overflow-x: auto;
margin: 1.2em 0;
}
/* =========================
🍽️ Tables
========================= */
table {
width: 100%;
border-collapse: collapse;
border: 1px solid var(--divider);
margin: 1.5em 0;
}
th, td {
padding: 0.5rem 0.6rem;
border-top: 1px dashed var(--divider);
}
th {
text-align: left;
background: rgba(255, 122, 24, 0.1);
}
/* =========================
🦶 Footer
========================= */
footer {
padding: 25px 0;
text-align: center;
color: color-mix(in oklab, var(--text-color) 80%, transparent);
font-family: var(--font-body);
}
/* =========================
⏰ Time (slightly broken clock)
========================= */
time {
font-family: "Courier New", monospace;
font-style: normal;
font-size: 0.95rem;
letter-spacing: 0.6px;
color: color-mix(in oklab, var(--text-color) 75%, transparent);
display: inline-block;
transform: rotate(-1.5deg);
opacity: 1;
position: relative;
transition: transform 0.25s ease, opacity 0.3s ease;
}
time::after {
content: attr(datetime);
position: absolute;
left: 1px;
top: 1px;
opacity: 0.1;
color: var(--glow-color);
transform: rotate(1deg);
pointer-events: none;
}
time:hover {
transform: rotate(-3deg) scale(1.02);
opacity: 1;
}
/* =========================
🕯️ Blog post list
========================= */
ul.blog-posts {
list-style: none;
padding: 0;
margin: 1.5em 0;
}
ul.blog-posts li {
display: flex;
align-items: baseline;
padding: 0.3rem 0;
}
ul.blog-posts li::before {
content: "🕯️";
margin-right: 0.5rem;
opacity: 0.8;
transform: translateY(1px);
}
ul.blog-posts li span {
flex: 0 0 130px;
opacity: 0.7;
color: color-mix(in oklab, var(--text-color) 70%, transparent);
font-size: 0.95em;
}
ul.blog-posts li a {
font-family: var(--font-accent);
color: var(--link-color);
text-decoration: none;
transition: text-shadow 0.25s ease, transform 0.15s ease;
}
ul.blog-posts li a:visited { color: var(--link-color); }
ul.blog-posts li a:hover,
ul.blog-posts li a:focus-visible {
text-shadow:
0 0 6px var(--glow-color),
0 0 14px var(--glow-color-soft),
0 0 22px var(--glow-color-soft);
transform: translateY(-1px);
}
/* =========================
⚙️ Accessibility
========================= */
:focus-visible {
outline: 3px solid color-mix(in oklab, var(--glow-color) 55%, transparent);
outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
}
/* =========================
🦇 Optional: Restless bat
========================= */
/* =========================
🦇 Optional: Restless bat
========================= */
body::after {
content: "🦇";
transform: scaleX(-1);
position: fixed;
top: 10%;
left: -60px;
font-size: 1.8rem;
opacity: 0.6;
z-index: 9999;
pointer-events: none;
animation: emberwing 22s linear infinite;
}
@keyframes emberwing {
0% { transform: translate(0, 0) rotate(8deg) scaleX(-1); opacity: 0; }
5% { transform: translate(3vw, -1vh) rotate(6deg) scaleX(-1); opacity: 0.8; }
10% { transform: translate(10vw, -4vh) rotate(-6deg) scaleX(-1); }
15% { transform: translate(18vw, -3vh) rotate(-2deg) translateY(-2px) scaleX(-1); }
25% { transform: translate(40vw, 6vh) rotate(10deg) scaleX(-1); }
30% { transform: translate(46vw, 5vh) rotate(8deg) translateY(-3px) scaleX(-1); }
37% { transform: translate(55vw, -2vh) rotate(-3deg) scaleX(-1); }
45% { transform: translate(68vw, 1vh) rotate(2deg) translateY(-2px) scaleX(-1); }
50% { transform: translate(80vw, 3vh) rotate(6deg) scaleX(-1); }
58% { transform: translate(88vw, 2vh) rotate(4deg) translateY(-3px) scaleX(-1); }
65% { transform: translate(95vw, -5vh) rotate(-8deg) scaleX(-1); }
72% { transform: translate(110vw, -3vh) rotate(-4deg) translateY(-2px) scaleX(-1); }
75% { transform: translate(120vw, 0vh) rotate(5deg) scaleX(-1); }
82% { transform: translate(130vw, -2vh) rotate(3deg) translateY(-3px) scaleX(-1); }
85% { transform: translate(140vw, -4vh) rotate(-4deg) scaleX(-1); }
92% { transform: translate(150vw, -1vh) rotate(-2deg) translateY(-2px) scaleX(-1); }
100% { transform: translate(160vw, 3vh) rotate(8deg) scaleX(-1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
body::after { animation: none !important; opacity: 0 !important; }
}
/* =========================
👻 Optional: Spooky cursor
========================= */
body {
cursor: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'>\
<text y='24' font-size='24'>👻</text></svg>") 8 8, auto;
}
/* =========================
🔺 Optional: Pumpkin-powered upvote
========================= */
.post .upvote-button svg { display: none; }
.post .upvote-button {
position: relative;
display: inline-flex;
flex-direction: row;
align-items: baseline;
gap: 0.1875rem;
padding: 0.1875rem 0.375rem;
border: 0;
background: transparent;
color: inherit;
font: inherit;
cursor: pointer;
line-height: 1;
font-size: 1rem;
}
.post .upvote-button:hover { background: transparent !important; }
.post .upvote-button::before {
content: "🎃";
display: inline-block;
font-size: 1.125rem;
line-height: 1;
color: var(--link-color);
transform: translateY(2px);
transition: transform .15s ease, color .2s ease, text-shadow .2s ease;
}
.post .upvote-button:hover:not(:is(.upvoted, [aria-pressed="true"], [disabled]))::before {
transform: translateY(2px) scale(1.1);
text-shadow: 0 0 8px color-mix(in oklab, var(--pumpkin) 45%, transparent);
}
.post .upvote-button:is(.upvoted, [aria-pressed="true"], [disabled])::before {
content: "🧡";
color: var(--pumpkin);
animation: toast-pop .18s ease-out;
}
.post .upvote-button[disabled] { cursor: default; }
.post .upvote-button + .upvote-count {
margin: 0;
font-size: 0.90625rem;
line-height: 1;
color: var(--text-color);
opacity: 0.8;
transform: translateY(1.5px);
transition: color .25s ease, opacity .25s ease;
}
.post .upvote-button:is(.upvoted, [aria-pressed="true"], [disabled]) + .upvote-count {
color: var(--pumpkin);
opacity: 1;
}
@keyframes toast-pop {
0% { transform: translateY(2px) scale(1); }
40% { transform: translateY(2px) scale(1.3); }
100% { transform: translateY(2px) scale(1); }
}
@keyframes sparkle {
0% { opacity: 0; transform: translateY(4px) scale(.9) rotate(0deg); }
40% { opacity: 1; transform: translateY(-2px) scale(1.1) rotate(10deg); }
100% { opacity: 0; transform: translateY(-8px) scale(1) rotate(-6deg); }
}