Merge pull request 'Add unlisted /socialism pages for the worker-ownership model' (#123) from feature/socialism into master
Build and Deploy / build-deploy (push) Successful in 1m21s

Reviewed-on: #123
This commit was merged in pull request #123.
This commit is contained in:
2026-09-23 12:17:16 -06:00
35 changed files with 1766 additions and 0 deletions
+3
View File
@@ -369,3 +369,6 @@ FodyWeavers.xsd
native/**/build/
# Playwright MCP scratch output
.playwright-mcp/
# Private /socialism working files (founding draft, progress log) - repo is public
JoshHeaps.Net/Content/Socialism/_*.md
@@ -0,0 +1,24 @@
---
title: Capital, After
section: Growing the Sector
order: 80
summary: Outside investment in a co-op is rented, not owned: profit-sharing claims that expire and carry no vote.
---
# Capital, After
Outside investment into a locked co-op doesn't disappear. It changes shape.
**Rented, not enthroned.** An investor funds the company and receives repayment plus a share of profits for the life of the loan. Then the claim **extinguishes**, and the workers hold 100%.
Today's equity is *perpetual*: an original investor's great-grandchildren collect forever off work they never did. This claim *expires*. That's the whole reform, in one word. Capital gets rented.
The returns can be enormous. A profit-share loan into a risky seed-stage co-op might pay 10x or 30x. That's fine. The principle was never *no big payday*. It was **no perpetual claim and no control**.
There is one limit, though. A claim that takes 90% of the profits for 40 years is "voteless and expiring" on paper, but it turns the co-op into a shell. So for co-ops borrowing from the bank, outside claims rank behind the bank's loan, last at most 15 years, and need the bank's approval. See [Guarding the Pilot](pilot-safeguards.md#draining-it-through-investors).
**Be honest about what this is.** A profit-contingent return means the investor eats the loss when things go badly. That is residual risk, which is the economic job we call equity, whatever we print on the paper. Don't claim it "isn't a stake in the work." It is. Claim what's actually true and actually better: *finite, and voteless.*
**The consequence, priced in.** Capital charges for risk. An instrument with equity-like downside and a terminating upside gets funded last, or demands a bigger profit share. Revenue-based financing already exists in today's market and stays niche for exactly this reason. It bites hardest on brand-new ventures and barely at all on mature, profitable firms.
This rule applies only to co-ops. Conventional firms keep conventional equity. That makes the cost-of-capital question an empirical one: [the test](the-test.md) will show whether co-ops can raise enough on these terms, alongside the bank, to grow.
@@ -0,0 +1,27 @@
---
title: The Constitution
section: Guardrails
order: 130
summary: The biggest risk is that the model gets repealed, not that the state overreaches. Plus money out of politics and rights the majority can't take away.
---
# The Constitution
This model asks little of the state: charter [a bank](the-bank.md), enforce [the lock](the-lock.md), run [the floor](the-floor.md). The concentration-of-power argument still applies to the floor (see [Open Problems](open-problems.md) on "essential" sectors), but it isn't the biggest risk.
**The main risk is durability, not overreach.** A model that can be built gradually can be dismantled gradually. A future Congress can defund the bank, and a statutory lock can be repealed by the same kind of majority that passed it. Postwar social democracy got rolled back once the coalition that built it weakened; a voluntary co-op sector is exposed to the same thing. So the design question is: **what makes this hard to reverse?** Partial answers: the lock written into each co-op's own charter and into state co-op law, not just federal statute; a federation that becomes financially independent of the public bank; and, above all, a co-op sector large enough to have its own constituency.
**Money out of politics.** Legislative work pays well enough that good people want the job, but any money, gift, or benefit from a non-government entity ends the salary and starts a prison sentence. Politicians should benefit only from serving their people.
**But representation alone is not a guardrail.** This is the trapdoor, and it needs saying explicitly:
> *A government that perfectly represents its people will target a group whenever the people want that group targeted.*
Representation amplifies the majority; it does not restrain it. Jim Crow was representative: it represented its white voters faithfully, and that is exactly how it ground people down for a century. Internment was popular. Clean elections stop capture *by the rich*. They do nothing to stop the majority deciding a minority is the enemy.
**So: counter-majoritarian rights.** Things a person keeps *even when everyone around them votes to strip them away.* The whole point of a right is that it holds on the day the majority is wrong, and you cannot assume in advance that you'll always be the majority, or always be right.
- Keep the Bill of Rights. Make rights that protect individuals **extremely difficult to repeal.**
- **Two tiers.** Speech, due process, equal protection, freedom from imprisonment without trial: near-absolute. Property: strong, but balanceable against the public interest with compensation, which is what the Takings Clause already says. *(This model doesn't touch existing property at all. It asks nothing of the property tier.)*
- **The Senate had the right idea, badly built.** Keep the cooling-saucer function: a second chamber that slows things down and forces broad coalitions instead of bare-51% steamrolls. Drop the geographic weighting. Land should not get votes. Equal state representation and the protection of slavery were the *same bargain* in 1787, and that structure later shielded Jim Crow.
- **No final guardrail exists.** Entrench rights and you've moved power to whoever *interprets* them. There's no rule so perfect it guards itself. The answer isn't a better final rule; it's **redundancy**: several overlapping checks, none supreme, so that capturing any one of them doesn't hand someone the whole apparatus.
@@ -0,0 +1,20 @@
---
title: The Federation
section: Growing the Sector
order: 70
summary: Co-ops pool risk through a shared fund that absorbs shocks, moves workers when a firm fails, and becomes a lender in its own right.
---
# The Federation
Worker ownership has a risk problem that's easy to miss: **concentration.** It matters even more in a young, voluntary co-op sector.
A worker-owner holds their salary, their profit share, and their skills all inside one firm. That is exactly the risk a shareholder diversifies away and a worker cannot. It is the real source of risk-aversion: if one bad bet can kill the company that is also your paycheck and your equity, you take the safe option every time, and an economy of safe options stops producing breakthroughs.
The fix is a structure between firms, and Mondragon already built it:
- **Firms pool a slice of profits into a mutual solidarity fund.** The fund absorbs shocks. A firm having a bad year draws support instead of dying.
- **When a firm does die, the federation redeploys its workers into member firms.** Your company failing stops meaning your life failing. *This* is what licenses healthy risk-taking: not lower stakes on paper, but a floor under the fall.
- **The fund becomes a second lender.** Over time, the federation (financed by its members and by the indivisible reserves of dissolved co-ops) becomes a source of patient capital that doesn't depend on the public bank at all. That is the path to the co-op sector outliving the political coalition that started it.
Membership is voluntary, but the incentives all point in: unfederated co-ops face the concentration problem alone.
@@ -0,0 +1,20 @@
---
title: The Founder Problem
section: The Co-op
order: 40
summary: Without the chance to sell the company, why would a strong founder start a co-op? The hardest part of the design.
---
# The Founder Problem
This is the hardest part of the new design, and it needs to be said plainly.
**Most of a founder's payoff in a conventional startup comes from the exit: selling the company.** The lock removes the exit permanently. So the obvious risk is adverse selection: the best entrepreneurs go conventional, and the bank's applicants are the people who couldn't raise money anywhere else. If that happens, the experiment is rigged to fail before it starts.
The model needs a reason to found a co-op that doesn't depend on selling it. Tools that exist:
- **Internal capital accounts.** Each member has an individual account that accumulates their share of retained profits and pays out when they leave or retire. Mondragon built these precisely so that membership builds real wealth without making the firm tradeable. It is a way to cash out your *stake* without selling the *firm*.
- **Founder salary premiums**, set in the founding bylaws and voted on by members as the firm grows.
- **Patronage dividends:** profit distributed in proportion to contribution, not just headcount, during the founding years.
None of these fully replace a nine-figure exit. That's honest. The model is betting that enough people value what the co-op offers (control, stability, a firm they can't be sold out of) to make up the difference. That bet is part of what's being tested.
+39
View File
@@ -0,0 +1,39 @@
---
title: Free-Market Democratic Socialism
summary: A working model for building an economy where the people who do the work own and govern the companies they work for. Nobody's company gets taken, and markets, wages, investment and personal property all stay.
---
# Free-Market Democratic Socialism
## The idea in one sentence
**Your house, car, savings and tools are yours, and nobody touches them. But a permanent, tradeable claim on the work of thousands of strangers is a different kind of thing, so there should be companies where that claim never forms, and nothing in law or finance should stop people from building them.** [Read the thesis](thesis.md).
## Nobody is forced
This model doesn't buy, seize or convert anyone's company. Instead it builds new worker-owned companies alongside existing ones, then lets customers and workers choose between them.
- **Workers own their company.** Every member gets one vote. A share of the profits grows with tenure until long-time members split them equally. Salaries still exist, and hard jobs still pay more. [Worker Ownership](worker-ownership.md)
- **A small public bank lends to worker co-ops.** It charges market rates, so it only succeeds if co-ops can really compete. Its whole job is to be willing to lend to a kind of company other banks won't. [The Bank](the-bank.md)
- **Co-ops funded this way stay co-ops forever.** They can't be sold to conventional owners, and members can't vote to cash out what earlier members built. [The Lock](the-lock.md)
- **It runs as an honest experiment.** A one-time $350 million pilot aims to fund about 400 new co-ops. The success measures are published before the first loan. If, after twelve years, co-ops stay open about as well as similar conventional firms while paying their members fairly, and the bank earned at least what Treasury bonds would have, Congress votes on growing it. If not, it shuts down automatically. [The Test](the-test.md) and [The Pilot, in Numbers](pilot-spec.md)
- **Co-ops back each other up.** They pool part of their profits into a shared fund. If one fails, its workers are moved into others instead of being left with nothing. [The Federation](federation.md)
- **Nobody is left behind by low-margin work.** Owning a company doesn't help much when there's barely any profit to own, so a strong floor covers the rest. [Ownership and the Floor](the-floor.md)
## What stays the same
| Stays | Why |
| --- | --- |
| Existing companies | Nobody's company is bought or taken. Conventional firms keep conventional ownership. |
| Markets and competition | Co-ops and conventional firms compete for the same customers and workers. |
| Salaries | Hard and in-demand jobs still pay more. A surgeon still earns a surgeon's salary. |
| Personal property | Homes, cars, savings and tools are untouchable. |
| Investment and big returns | Investors can still fund co-ops and make 10x or 30x. Their claim just runs out and carries no vote. [Capital, After](capital.md) |
## Why it matters
This isn't mainly about money. **People deserve a say in governing the place where they spend most of their waking lives.** Today most workers are ruled by distant owners who answer to nobody who works there. Co-ops are rare, and one likely reason is that nobody will lend to them. This model fixes the financing and lets people choose. [Making the Case](the-argument.md)
## Honest about what's unsolved
This is a working model, not a finished one. The biggest open question is whether strong founders will start companies they can never sell ([The Founder Problem](founder-problem.md)). The full list of what isn't solved yet is kept in the open. [Open Problems](open-problems.md)
@@ -0,0 +1,15 @@
---
title: Intellectual Property
section: Beyond Co-ops
order: 100
summary: Targeted patent reform would help new firms, but it's kept separate from the bank so the achievable part doesn't wait on the hard part.
---
# Intellectual Property
Patent terms are too long for how fast many industries move, and some patents should never have been granted. Loosening IP would lower the barrier for any new firm, co-ops included. It belongs in the model, but it is **decoupled from the bank** for two reasons:
- **It's sector-dependent.** In software, patents mostly protect incumbents and trolls against entrants; weakening them helps new firms. In pharma and hardware, a patent is often the *only* thing keeping a small entrant from being copied to death by a competitor with better manufacturing and distribution. Blanket loosening can hand the advantage to scale, which is the opposite of the goal.
- **It's politically far heavier.** A small bank is achievable. Patent reform means fighting every industry that lives on patents. Coupling them means the achievable thing waits on the hard thing.
So the IP reform is targeted: shorter terms where innovation cycles are short, a much stricter bar for software and business-method patents, and aggressive action against patent trolls. Where patents genuinely protect small inventors, leave them alone.
@@ -0,0 +1,34 @@
---
title: Open Problems
section: Guardrails
order: 140
summary: An honest list of what isn't solved yet.
---
# Open Problems
An honest list of what the model hasn't solved yet, most dangerous first.
1. **Adverse selection on founders.** *(The most dangerous.)* The lock removes the exit. If the strongest founders go conventional, the bank's portfolio is the rejected pool, and the test fails for reasons that say nothing about co-ops. Internal capital accounts and founder premiums help; whether they're enough is unknown.
2. **The horizon problem.** Members near retirement have little reason to vote for long-lived investments whose payoff arrives after they leave. Internal capital accounts that credit members for retained earnings are the standard answer. It needs to be designed carefully, not assumed.
3. **Is the lock too rigid?** A co-op that should be sold (a better operator exists, the members want out) can only go to another co-op. If the co-op sector is small, that buyer pool is tiny, and viable firms may be liquidated instead of rescued. The federation as buyer of last resort is a partial answer. Critics on the right add a sharper version: a lock that outlasts a repaid loan by generations is a permanent restriction on selling property, bought with one loan, and it binds members who never agreed to it.
4. **Scale.** Even a total success at pilot scale leaves most workers in conventional firms. The labor-market effect needs a sector large enough to move wages, and nobody knows how long growth to that size takes, if it happens at all. That's the price of not forcing it.
5. **Political durability.** See [The Constitution](constitution.md). Gradual construction invites gradual repeal.
6. **Growth and dilution.** Softened by the tenure ramp, not eliminated. In steady state, an equal split per head still means a marginal hire must generate the average surplus to break even for incumbents. Capital-intensive expansion into lower-margin lines will face internal resistance conventional firms don't have.
7. **Who decides which sectors are "essential"?** Subsidy authority is price-setting power over a large chunk of the labor market, and every low-margin industry will suddenly discover it is Essential.
8. **The 1/N problem.** *(Mostly answered.)* Peer monitoring works at 30 people; at 10,000 your extra effort raises the pool by a rounding error. The answer is culture and structure: co-ops really do push out free riders, and the federation model keeps units small enough for monitoring to bite while pooling risk above them.
9. **The pilot's own weak points.** [The pilot](pilot-spec.md) puts the burden of proof on the co-ops, which means roughly a 1-in-10 chance of shutting down a pilot that was actually working. It tests individual co-ops, not the [federation](federation.md) support network Mondragon relied on. Its comparison group (small businesses with government-backed loans) is biased in directions that partly cancel out, by amounts nobody knows. And market-rate lending based on collateral may mostly reach founders who already have some wealth. Approval rates by race, gender and wealth are published so that shows up, but publishing a gap doesn't close it.
10. **Federal or state?** A federal bank is the cleanest single experiment. But a few state-chartered lenders running one shared, pre-registered plan would fail smaller, fit the fact that co-op law is state law, and might be harder to repeal all at once. That trade-off hasn't been worked through.
11. **Voluntary buyouts: in or out?** *(Open question.)* Should the bank also finance existing owners who *choose* to sell to their workers at market price, the way the UK's employee-ownership trusts work? It would grow the sector faster without forcing anyone. But it would mix two different experiments, and conversions carry different risks than startups.
*Not problems here, because nobody's company is forcibly bought:* valuing every firm in the economy, owners stripping value before a takeover, foreign capital flight, and years of payouts to former owners. The contractor boundary isn't an economy-wide problem either. Its co-op version, hiring non-members to dodge membership, is handled by [the lock](the-lock.md)'s membership requirement.
@@ -0,0 +1,95 @@
---
title: Guarding the Pilot
section: Growing the Sector
order: 66
summary: The rules that stop people from gaming the pilot with sham co-ops, hidden owners, split-up borrowers, zombie firms, or a rigged review.
---
# Guarding the Pilot
Any program that hands out money gets gamed. Venezuela's co-op boom produced tens of thousands of co-ops that existed mainly on paper ([YES! Magazine, 2007](https://www.yesmagazine.org/issue/latin-america/2007/05/12/venezuelas-co-op-boom)). Uruguay's FONDES sent nearly half its money to three politically connected firms ([El Observador, 2015](https://www.elobservador.com.uy/nota/mitad-de-dinero-del-fondes-fue-para-empresas-companeras--201572500)).
This page lists the ways someone could cheat [the pilot](pilot-spec.md), or sabotage it, and the rule that blocks each one. Most of these tricks don't require breaking any law. They only need a loophole, which makes them the likeliest threats. So the rules are written to close the loopholes.
## The hidden boss
**The trick.** A founder keeps the building, equipment, brand and software in a separate company he owns. He signs up three friendly "members" and gives the co-op a management contract or franchise deal with his company. The co-op borrows $3 million, and the money flows back to him as rent, fees and royalties. On paper it's a co-op. In practice it's his business, funded by the public.
**The rules:**
- **Every deal with an insider is disclosed.** Any contract with a founder, manager, member's family, or a company they own is reported to the bank and checked each year to confirm it's priced like a deal between strangers. Overpayments are treated as a breach of the loan.
- **Members can fire management.** Any management or franchise contract can be ended by a members' vote on short notice. A contract the members can't get out of is a boss.
- **The business owns what it needs to operate, or can buy it.** If key assets are leased from an insider, the bank gets a claim on them or the co-op gets an option to buy them at a fair price. That way the co-op can't be held hostage, and the bank's collateral is real.
- **Membership is real.** Probation lasts at most 12 months. At least three-quarters of the work hours must be done by members. Both are checked every year. A co-op that falls short counts as failed in the [pilot's survival measure](pilot-spec.md#what-gets-measured).
- **Lying costs something.** False statements on a loan application mean immediate repayment, and the people who made them are personally liable.
## Draining it through "investors"
**The trick.** [Outside investors in a co-op](capital.md) get no vote and a claim that expires. But nothing so far limits how big or long that claim can be. A friendly investor could take 90% of the profits for 40 years, and the co-op would be a shell.
**The rules, for pilot borrowers:**
- **The bank gets paid first.** Any outside profit-sharing claim ranks behind the bank's loan.
- **The bank must approve new claims.** Claims last at most 15 years.
- **Insiders' claims count as insider deals.** An investment by a founder or their family is checked the same way as any other insider contract.
## Splitting one borrower into many
**The trick.** The limit is $3 million per co-op. So a promoter, franchisor or landlord sets up 30 "separate" co-ops, each run by a relative or employee, and collects $90 million: a quarter of the fund, controlled by one person.
**The rules:**
- **"Related" means economically tied, not just sharing names.** Co-ops count as related, and share one $3 million limit, if they share a founder or manager, a franchisor, a landlord, a major supplier, an outside investor, or a paid promoter. Family members count as the same person, following the same kind of rules the tax code already uses for family ownership.
- **Caps on middlemen.** No single promoter, consultant or referral source can bring in loans totalling more than 3% of the fund.
- **Money arrives in stages**, as the business hits milestones, so a sham can't take the full amount and disappear.
## Relabeling an old business as "new"
**The trick.** A failing conventional business re-registers as a co-op to get a loan. That brings back the FONDES rescue problem through the side door. It would also flatter the survival numbers, because the business has already made it through its riskiest early years.
**The rule.** "New" describes the business, not the paperwork. If a co-op takes over an existing firm's assets, customers, location or most of its staff, it isn't new. It's either refused as a rescue or scored with the existing co-ops.
## Keeping zombies alive
**The trick.** If the test fails, the bank shuts down. So the bank's own staff have the strongest reason of anyone to make the numbers look good. They can stretch out loans, let unpaid interest pile up, and keep dead firms technically open. A healthy co-op can also absorb a dying one, so the closure never shows up.
**The rules:**
- **"Open" means actually operating:** at least three members and sales above a minimum level. An empty shell counts as closed.
- **Loans are valued honestly.** At review, outstanding loans are valued at what a buyer would pay. A loan whose terms were eased to avoid default is marked down. Unpaid interest added to the balance doesn't count as income.
- **Mergers are treated the same on both sides.** A co-op absorbed by another co-op, and a conventional firm bought by another firm, are both counted as neither success nor failure. A second analysis counts them both ways.
## Sabotage
**The trick.** An opponent recruits 25 or 30 plausible applicants, has them draw down their loans, strip the money and default. That pushes losses past the emergency stop and freezes the pilot before it reaches a verdict.
**The rules:**
- **Fraud doesn't end the experiment.** Under the [emergency stop](pilot-spec.md#the-decision-rule), lending restarts once the reviewers confirm the specific gaps are closed. Losses that are later recovered are credited back.
- **The staged payouts and middleman caps above** limit how much any ring can take before it's noticed.
## Rigging the review
**The trick.** The headline thresholds are fixed, but a lot of smaller choices aren't: which firms count as matches, how closures are detected in the data, which years are included. Lobbyists on both sides would fight over each one, and whoever picks the reviewers picks the answer.
**The rules:**
- **The analysis code is filed in advance**, not just the plan, along with a digital fingerprint that shows it hasn't changed.
- **The academic reviewers are nominated by the National Academies of Sciences**, and nobody with ties to the bank or to co-op advocacy groups can serve.
- **Any change from the filed plan must be signed, explained and published**, and the result under the original plan is always reported next to it.
## Rigging the price
**The trick.** A friendly bank chief could quietly undercharge co-ops, which is a hidden subsidy. A hostile one could overcharge them into failure.
**The rule.** The [annual rate audit](pilot-spec.md#what-market-rate-means) works in both directions. Undercharging is counted as a loss against the bank's results. Overcharging gets the affected loans repriced.
## Political favoritism
**The trick.** This is what FONDES actually did: politicians steer loans to allies.
**The rules:**
- **Every loan is public:** the borrower, the amount, the rate and the terms.
- **Every contact from an elected official or their staff about a specific loan is logged and published.**
- **The board answers to elected officials. Individual loans don't.** Officials can appoint and remove the bank's board. But no official can direct a decision on a particular loan, and loan officers are bankers, not appointees.
@@ -0,0 +1,174 @@
---
title: The Pilot, in Numbers
section: Growing the Sector
order: 65
summary: The concrete pilot: how much money, how many co-ops, what gets measured, against whom, and the exact results that grow the bank or shut it down.
---
# The Pilot, in Numbers
[The Test](the-test.md) says the bank runs as an experiment. You can't fault an experiment that has no numbers, so this page supplies them. Every number here is a first draft and open to argument. What matters is that they're written down *before* the first loan, so nobody (me included) can pick them after seeing the results.
The rules that stop people from gaming the pilot (sham co-ops, hidden owners, rigged comparisons) have their own page: [Guarding the Pilot](pilot-safeguards.md).
## The short version
| | |
| --- | --- |
| **Money** | $350 million, once. |
| **Lending window** | Years 1–5 (up to year 8 if good applicants are scarce). |
| **Target** | About 400 new worker co-ops. |
| **Loan size** | Up to $3 million per co-op, including all later loans. |
| **Price** | Market rate: what a similar conventional business would pay. No personal guarantees from members. |
| **Compared against** | Similar new conventional firms that got similar-sized loans, plus a lottery among borderline applicants. |
| **Final review** | Year 12, by an independent reviewer. |
| **Passes if** | Co-ops stay open about as well as the comparison firms *while paying their members fairly*, and the bank earns at least what the money would have earned in Treasury bonds. |
| **Shuts down if** | Either of those fails. |
The rest of this page explains each line.
## Two warnings from real life
Two public efforts to fund co-ops went badly. The pilot is built to avoid repeating them.
**Uruguay's FONDES.** In 2011 Uruguay set up a public development fund to lend to worker-run firms. By 2016 it had funded 22 firms, and almost 90% of its loans (US$63 million of US$69 million) had been written down as uncollectable. Eight firms got 93% of the money. Three with close ties to the governing party got nearly half. The biggest single loan, US$15 million, went to Alas Uruguay, an airline formed by the workers of the failed state airline. It stopped flying ten months after launch. The original bill capped any one firm at 3% of the fund, but lawmakers raised the cap to 15% before passing it. ([El Observador, 2017](https://www.elobservador.com.uy/nota/-en-que-estan-los-principales-emprendimientos-financiados-por-el-fondes--20176201600); [El Observador, 2015](https://www.elobservador.com.uy/nota/mitad-de-dinero-del-fondes-fue-para-empresas-companeras--201572500))
What went wrong: most of the money went to *rescuing firms that had already failed* under other owners, a few borrowers got most of it, and politics chose them. Uruguay reformed the fund in 2015. It added a 10% cap per business group and a limit of two loans per firm in five years ([la diaria, 2016](https://ladiaria.com.uy/articulo/2016/6/arrancando-de-cero/)).
**Venezuela's co-op boom.** After 2001, Venezuela gave co-ops cheap state loans, first pick of government contracts, and tax breaks. Registered co-ops went from under 800 to over 100,000 in a few years. A 2006 government census found only about 50,000 actually operating. Many had been set up to collect the benefits, not to run a business ([YES! Magazine, 2007](https://www.yesmagazine.org/issue/latin-america/2007/05/12/venezuelas-co-op-boom); [Grassroots Economic Organizing](https://geo.coop/blog/some-counter-intuitive-effects-government-support-co-ops-venezuela)).
What went wrong: cheap money attracts people who want the money, not the co-op. That's the main reason [the bank](the-bank.md) charges market rates.
## Why a new bank, not existing programs
Fair question. Congress already made co-ops eligible for the Small Business Administration's (SBA's) main loan program in 2018, through the Main Street Employee Ownership Act. It has barely been used. The SBA kept requiring personal guarantees on those loans, meaning individual members pledge their own homes and savings if the business fails. That doesn't work for a firm owned by dozens of workers ([House Committee report, 2018](https://www.congress.gov/committee-report/115th-congress/house-report/645/1); [NCEO, 2022](https://www.nceo.org/employee-ownership-blog/house-committee-urges-sba-fully-implement-main-street-eo-act)).
Private co-op lenders exist and do good work, but they're small. Shared Capital Cooperative, lending to co-ops since 1978, had about $20 million in assets in 2021 ([offering statement](https://www.sec.gov/Archives/edgar/data/1722839/000121390021050617/ea148092-1a_sharedcapital.htm)). The pilot's question is what happens when financing on normal commercial terms is available at real scale. The existing channels can't answer that.
## How much money, and why
**$350 million, one time.** In the pilot, the bank lends only its own capital. It doesn't borrow on top of it. That makes the worst case easy to state: taxpayers can lose at most $350 million, minus whatever is repaid.
It breaks down like this:
- **About $300 million for loans.** Around 400 co-ops with a typical first loan of about $500,000 is roughly $200 million. The rest is for follow-on loans to co-ops that grow. For comparison, Shared Capital's average loan is about $230,000. The pilot's loans are larger because it's meant to fund real businesses with real payrolls, not only very small ones.
- **$20 million, capped, for business help:** bookkeeping, governance training, legal setup. Venezuela's census blamed many of its failures on the lack of exactly this. This money is a public cost, stated openly and capped, and it's counted in the pilot's total cost to taxpayers. It isn't allowed to hide inside loan pricing.
- **The remainder** is a cash cushion and running costs.
## Why about 400 co-ops
This is the number that lets the test tell a real answer apart from luck.
New businesses close a lot. Of all US business locations opened in 2013, only about 35% were still open ten years later ([Bureau of Labor Statistics](https://www.bls.gov/bdm/us_age_naics_00_table7.txt)). With closures that common, a small pilot is noise: 30 co-ops could look great or terrible by chance.
To be confident that co-ops do "at least about as well" as conventional firms, you need to see several hundred closures across both groups. Standard survival statistics say that about 400 co-ops, each compared with five similar conventional firms, give roughly a 90% chance of a clear verdict if co-ops really are exactly as durable. If they're *more* durable, as the best existing study suggests (below), a clear verdict is easier to reach.
That also means a roughly 10% chance of shutting down a pilot that was actually working. That's the cost of putting the burden of proof on the co-ops, and it's stated openly.
**The honest problem with 400.** The whole US worker co-op sector was about 751 firms in 2023, roughly triple what it was a decade earlier ([NCEO summary of the Democracy at Work Institute census](https://www.nceo.org/employee-ownership-blog/democracy-at-work-institute-releases-its-2023-worker-cooperative-state-of-the-sector-report)). That's about 50 new co-ops a year. Reaching 400 in five years means roughly doubling the rate at which co-ops get founded.
That creates exactly the pressure that sank Venezuela: an institution with a target lowers its standards to hit it. So:
- **No lending targets.** Nobody is paid, promoted or judged on loan volume.
- **If good applications fall short, the lending window stretches** (up to year 8) instead of standards dropping. The final review moves back by the same amount. That rule is fixed now.
- **A shortfall is itself a result.** If good co-op applicants don't show up even when financing is available, that's evidence for the "co-ops are rare because they're hard, not because they're unfunded" explanation, and it gets reported that way.
## Who can borrow
- **New worker co-ops only, for the main test.** "New" means the *business* is new, not just the legal paperwork. A conventional firm that reincorporates as a co-op isn't new (see [Guarding the Pilot](pilot-safeguards.md)).
- **Existing co-ops may borrow too, but they're scored separately.** Firms that have already survived for years would make the results look better than they are.
- **No rescues of failed conventional firms.** That's where FONDES lost its money, and it's a different experiment (see *Voluntary buyouts* in [Open Problems](open-problems.md)).
- **At least three worker-members at the first loan**, meeting the [co-op definition](worker-ownership.md) and accepting [the lock](the-lock.md).
- **Members are on the payroll as employees.** That gives them minimum wage, unemployment insurance and workers' compensation like any other worker. It also means the co-op shows up in the government business records the test relies on.
- **Any legal industry.** Loan officers judge business plans, not industries. But no single industry may take more than 25% of the money lent, and no single county more than 10%, so one bad sector or one local market can't sink the whole test.
## Loan terms
- **$3 million per co-op, lifetime.** That's under 1% of the fund. FONDES let one airline take over a fifth of its money. That can't happen here. Related co-ops share one limit (see [Guarding the Pilot](pilot-safeguards.md)).
- **Paid out in stages** as the business hits agreed milestones, not in one lump.
- **No personal guarantees from members.** The risk that the business fails is exactly the risk the bank exists to price and carry. Loans can be secured by the business's own assets, like any business loan.
- **Underwriting can rely on cash flow**, not only on collateral. Collateral-heavy lending mostly measures how much wealth the founders already had, which shuts out the workers co-ops tend to serve.
## What "market rate" means
The bank prices each loan the way a normal lender would price a conventional business with the same numbers: same revenue, same industry, same track record, same collateral. Because there are no personal guarantees, the rate is higher than it would be with them. That's the honest price of the risk.
Two checks keep the price honest:
- **An annual audit**, in both directions. Each year an outside auditor compares a sample of the bank's loans with rates on comparable conventional small-business loans. It also checks the things that don't show up in the rate: who gets approved, how much collateral is required, and how often troubled loans get softer terms. If loans are systematically too cheap, the shortfall is counted as a loss against the bank's results. If they're too expensive, the affected loans are repriced.
- **A private market check.** Every loan is offered to private and community lenders, who can buy up to 20% of it on the same terms. How often they say yes is published. If nobody ever wants a piece, that suggests the price is too low for the risk.
## What gets measured
All of this is written down and filed in a public study registry before the first loan, the way serious medical trials and a few careful social-policy studies already do. One example is the [Oregon Health Insurance Experiment](https://www.nber.org/programs-projects/projects-and-centers/oregon-health-insurance-experiment/oregon-health-insurance-experiment-background). The actual analysis code is filed too, so the method can't quietly change later.
**The two measures that decide the outcome:**
1. **Fair survival.** Does the co-op stay open and keep treating its members fairly? A co-op counts as *failed* if any of these happens:
- it closes, or falls below three members or a minimum level of sales;
- for two years running, its members' median pay per hour (wages plus profit share) falls below 85% of the matched conventional firms' median;
- it stops being a real co-op: fewer than three-quarters of its work hours are done by members, or its workers are kept on probation past the limit.
The pay rule matters. Co-ops can survive a bad stretch by cutting their own pay instead of cutting jobs, and the best existing study couldn't rule that out. A co-op that survives by paying its people far less than the business down the street hasn't passed.
2. **The bank's money.** At the end, after every loss, write-off and running cost, has the loan book earned at least what the same money would have earned in Treasury bonds over the same years? Anything less means taxpayers lost money compared with just holding bonds. Loans still outstanding are valued at what a buyer would pay for them. Loans that were restructured to avoid default are marked down, so going easy on struggling borrowers can't hide losses.
A useful yardstick: among the SBA's mature loan groups from 1992 to 2004, loans making up about 6% to 10% of the money lent eventually defaulted, and about 37% of the defaulted amount was later recovered ([GAO-20-618](https://www.gao.gov/products/gao-20-618)). A lender charging market rates with losses in that range covers them from interest.
**Measures that are published but don't decide:** jobs created, wages at the bottom and top and the gap between them, revenue per worker (a rough measure of productivity), how long members stay, injury rates, and the bank's default and recovery rates. Also:
- **Who got loans.** Approval rates and loan terms by the founders' race, gender and personal wealth. If collateral-based lending quietly shuts out the people co-ops mostly serve, it should show.
- **Local effects.** Business openings and closures in the counties where co-ops were funded, so any damage to existing local businesses is visible.
- **Results by industry**, including care work like home health and cleaning, where most US co-op members work today.
Why only two deciding measures: the more measures you allow to count, the easier it is to find *one* that looks good. Two, fixed in advance, can't be gamed that way.
## Who co-ops are compared against
This is the hardest part of any test like this. Co-ops that got a loan aren't like the average new business. They had a plan good enough to get a loan. Comparing them with *all* new businesses would flatter them.
**Main comparison: new conventional firms that got a similar-sized loan through the SBA's main program.** They're matched on industry, region, start year, starting size, legal form, and the number of founders. Businesses with more founders tend to survive longer, and co-ops always have at least three. This group is imperfect in both directions. SBA borrowers had to show they couldn't get credit elsewhere, which makes them a weaker comparison. But their loans carry a government guarantee that makes credit cheaper for them, which makes them a stronger one. The reviewer reports both biases openly. Researchers have already matched SBA borrowers with similar firms in government business records ([Brown and Earle, *Journal of Finance*, 2017](https://papers.ssrn.com/abstract=2641184)), so the data work is feasible.
**Second check: a lottery at the margin.** Among applicants whose scores land just around the approval line, the bank decides by lottery who gets a loan. Then it follows both groups. This is the cleanest test of the core claim: *does access to financing make co-ops that would otherwise not exist, or not survive?* The lottery group will be small, so it supports the main result rather than replacing it.
**Third check:** co-ops against *all* similar new firms.
**Sales count the same way on both sides.** A conventional firm that gets bought hasn't necessarily failed, and a co-op can't be bought at all because of [the lock](the-lock.md). So acquisitions and mergers, on either side, are counted as neither success nor failure in the main analysis, with a second analysis counting them both ways.
**What existing evidence predicts.** The strongest study so far followed every firm in Uruguay from 1997 to 2009: about 29,000 firms, 223 of them worker-run. After leaving out very small businesses and adjusting for tax differences, worker-run firms were about 29% *less* likely to close in any given period than conventional ones ([Burdín, *ILR Review*, 2014](https://journals.sagepub.com/doi/10.1177/001979391406700108)). The advantage was clearest in services. In manufacturing and transport there was no clear difference. That's encouraging, but it's one country, and it's why pay is built into the survival measure above.
## The timeline
- **Year 0.** Charter the bank. File the full analysis plan, code, benchmarks and thresholds. Name the reviewers.
- **Years 1–5.** Lending window, stretching to year 8 if applications fall short.
- **Year 6.** Public interim report. It can't trigger growth. It can only trigger the emergency stop.
- **Year 12.** Final review. Every co-op funded has been open for at least seven years. That covers most of the danger period for new businesses and, almost certainly, at least one recession.
**The reviewers:** the Government Accountability Office (GAO), Congress's own auditor, which already reviews SBA lending, working with academic economists nominated by the National Academies of Sciences. They must have no ties to the bank or to co-op advocacy groups. The bank's staff don't grade their own work. The reviewers can depart from the filed plan only in a signed, published explanation, and the filed plan's result is always reported alongside.
## The decision rule
At year 12, both measures must pass:
1. **Fair survival.** We can be 95% confident that co-ops' chance of failing in a given year, as defined above, is no more than 25% higher than the comparison group's. If co-ops are exactly as durable or more, this should pass. If they're clearly worse, it fails.
Why allow up to 25% rather than demanding exact equality? No test can prove two things are *exactly* equal. You can only rule out differences bigger than some margin, and a tighter margin takes more co-ops. Ruling out a 10% gap would take somewhere around 1,500 to 2,000 co-ops, more than twice the entire US co-op sector. The 25% margin is also a value judgment, stated openly: a society might reasonably accept firms that are a little less durable in exchange for workplaces people govern themselves. Readers who think that price is too high should say so. Burdín's result suggests the margin won't matter, because co-ops may well come out ahead.
2. **The bank's money** earned at least the Treasury rate.
**If both pass:** the charter triggers a fast-track, up-or-down vote in Congress on a second capitalization, with no amendments and no committee bottleneck. It can't be automatic, because no Congress can bind a later one's spending. A fast-track vote is the most that can honestly be promised. If the bank is later allowed to borrow, its debts carry **no federal guarantee**, written into the charter. Fannie Mae and Freddie Mac needed a taxpayer rescue in 2008 partly because markets had always assumed the government stood behind them. This bank shouldn't be able to create that assumption.
**If either fails, the shutdown happens by itself, with no further vote needed.** No new loans. The remaining loans are offered at fair value to co-op and community lenders, who keep the same repayment terms. Whatever they don't buy is collected by the Treasury on the original terms until paid off. None of it goes to distressed-debt buyers. The money goes back to the Treasury. The co-ops stay co-ops, because [the lock](the-lock.md) is in their own charters, but they're on their own.
**There is no "inconclusive, keep going" option.** If the evidence doesn't clearly show co-ops holding their own, that counts as a fail. The burden of proof is on the co-ops, which is where a skeptic would put it.
**The emergency stop.** If net losses ever pass 20% of the capital ($70 million), new lending freezes, and the reviewers report within six months on the cause:
- **A recession:** lending restarts only if the SBA's own loans from the same years lost money at a similar rate. That's a fixed comparison, not a judgment call.
- **Fraud:** lending restarts once the reviewers certify the specific gaps are closed and recovery has been pursued. Otherwise one organized fraud ring could end the experiment on purpose (see [Guarding the Pilot](pilot-safeguards.md)).
- **Bad lending decisions:** no restart. That's a result.
## What this pilot can't tell you
- **Whether the labor market changes.** 400 co-ops won't move anyone's wages. See [The Test](the-test.md).
- **Whether the best founders come.** The test measures the co-ops that *did* apply. If strong founders stay away ([The Founder Problem](founder-problem.md)), a pass means "the co-ops that exist can compete," not "co-ops would win with everyone's best people."
- **Whether co-ops do better with a full support network.** The pilot funds individual co-ops. It doesn't build [the federation](federation.md) that Mondragon relied on, so co-ops that join a federation are reported separately.
- **Whether it survives politics.** Congress can refuse the second capitalization, or repeal the whole thing. See [The Constitution](constitution.md).
@@ -0,0 +1,20 @@
---
title: Prison Labor
section: Beyond Co-ops
order: 120
summary: Only with full pay parity, and only if no budget ever benefits from more people being locked up.
---
# Prison Labor
Incarcerated people work **the same jobs, at the same pay, side by side with free temps.**
Pay parity is not a detail. It is the entire moral load-bearing wall, and it is the first thing a critic will assume was left out, so it goes in the first sentence, always.
Pay parity is what separates this from convict leasing. The historical horror ran on a *cost advantage*: after the Civil War, Southern prisons became labor suppliers and arrests rose to meet demand. The Thirteenth Amendment abolished slavery *"except as a punishment for crime,"* and that clause is why it worked, and it is still in the Constitution. Remove the cost advantage and the state gains nothing by locking more people up.
**The test, applied forever:** *if automation arrived tomorrow and every prison job vanished, would any budget line get harder to balance?* If yes, the trap is live and the design has failed.
Required guardrails: pay parity, genuinely optional participation, no quotas, no budget line that improves with a larger prison population.
**The goal is reform, not punishment.** People should leave prison with savings, a work history, and a reference. Employment after release is one of the strongest predictors of not going back.
@@ -0,0 +1,18 @@
---
title: Startups
section: Growing the Sector
order: 90
summary: Fund the science, back the boring, make the co-op a real option for founders, and don't let government pick the startups.
---
# Startups
**One line: fund the science, backstop the boring, give founders a real co-op option. Don't pick the startups.**
Government should not be a venture capitalist. VC works by being wrong 70% of the time and letting two freak winners pay for everything. No public agency survives that headline rate. It would get cautious, fund safe bets and well-connected people, and safe bets don't produce breakthroughs. The failure mode isn't corruption; it's risk-aversion under political accountability.
So:
1. **Fund the science, not the companies.** DARPA and NIH gave us the internet, GPS, touchscreens, mRNA. The state buys the ingredients; a thousand private actors race to cook.
2. **Make the co-op a real option for founders.** A garage company is founders and early employees, with almost no separation between labor and ownership. The bank, internal capital accounts, and the federation exist so that choosing co-op form isn't choosing to be underfunded. Early-stage co-op capital will still cost more than conventional VC. That's [the founder problem](founder-problem.md), and [the test](the-test.md) will show how much it matters.
3. **Backstop the boring.** Rural grocery store, local clinic, unglamorous manufacturer. That's development banking, not venture, and government is genuinely good at it. Loan guarantees, SBA-style. These are also the sectors where co-ops have historically done best.
@@ -0,0 +1,24 @@
---
title: Making the Case
section: Making the Case
order: 150
summary: Lead with "nobody is forced," point to the co-op banks that already exist, argue from freedom rather than dollars, and don't overclaim.
---
# Making the Case
**Lead with "nobody is forced."** The model takes nothing from anyone. It charters a bank, asks it to lend at market rates to a kind of firm other banks won't touch, and publishes the results. If co-ops can't compete, the experiment says so and it gets wound down. That is the most market-friendly proposal on the left, and it should be argued that way.
**The second line: "we already did this."** Congress chartered a cooperative bank in 1978. Mondragon built one in the 1950s. Italy has run a co-op development fund on member profits for decades. This is an old, tested idea aimed at a new target.
**Germany is now a supporting point, not the lead.** Co-determination puts workers on up to half the supervisory board of large firms, by law, and Germany is still a capitalist market economy. It shows ownership and governance rules are choices societies make, not laws of nature. But it's no longer needed to defend a mandate, because there isn't one.
**Don't lead with "they extract while workers starve."** It's the weakest version of the case, and it invites "the return is compensation for capital and risk," which wins the exchange. The strong version:
> *Bargaining power is lopsided. Workers have no realistic path to a claim on the enterprise they build. Capital markets don't fund firms that workers own. Fix the financing and let people choose.*
**Don't argue it in dollars.** The dollars framing ($150k/head, hungry kids) is exactly what leaves the model vulnerable to *"then just give them cash; a big enough UBI is simpler."* If ownership is only an *instrument* for moving money, a UBI substitutes for it.
It isn't. It's the goal. **People deserve to govern the thing they spend their life inside.** The objection is *domination*, not just poverty. That claim is about human freedom, it survives the UBI, and no amount of cash dissolves it.
**And don't overclaim.** The pilot proves business viability or it doesn't. Don't promise that it will reshape the labor market. Say that's what success at scale would do, and let the data earn the rest.
@@ -0,0 +1,28 @@
---
title: The Bank
section: Growing the Sector
order: 50
summary: A small public bank that lends only to worker co-ops, at market rates, with professional underwriting and published results.
---
# The Bank
**A small public investment bank that lends only to worker cooperatives.**
Why a bank and not a mandate: co-ops are rare, and there are two competing explanations. One says they're rare because capital markets won't fund firms whose owners can't sell equity to outsiders. The other says they're rare because they're genuinely harder to run. A bank that removes the financing barrier is the experiment that tells those apart. If co-ops were starved of capital, they'll grow. If they're hard to run, the portfolio will fail, and we'll have learned that honestly and cheaply.
Mondragon already proved the first half of the premise: it had to build its own bank, Caja Laboral, because ordinary banks wouldn't lend to it.
**Design:**
- **Charter:** lends only to firms that meet the [co-op definition](worker-ownership.md) and accept [the lock](the-lock.md).
- **Priced at market rates.** This is deliberate. The bank's edge must be *willingness* to underwrite a firm structure other lenders refuse, not *cheap money*. If it lends below market, every result is unfalsifiable: success gets dismissed as "free state money," failure gets dismissed as "hobbled by the lock." At market rates, survival and returns mean something.
- **Professional, insulated underwriting.** Loan officers are bankers, not appointees. Lending decisions are walled off from legislators the way monetary policy is walled off from Congress. A bank that funds whichever co-op has the best-connected sponsor fails the experiment and deserves to.
- **Self-sustaining by design.** One-time capitalization, then it lives on its loan book. Losses are public and published. A permanent appropriation would turn it into a subsidy line, and subsidy lines get captured.
- **Full transparency.** Portfolio data (default rates, survival, wages, productivity, member retention) published annually, so anyone can check the result, including critics.
The actual numbers (how much money, how many co-ops, loan limits, and how "market rate" is checked) are in [The Pilot, in Numbers](pilot-spec.md). The rules against sham co-ops and political favoritism are in [Guarding the Pilot](pilot-safeguards.md).
**Precedent:** the United States already has one. Congress created the National Consumer Cooperative Bank in 1978. It was never scaled or aimed at worker co-ops specifically, but "a federally chartered bank for cooperatives" is not a new idea. Italy's Coopfond, financed by a mandated slice of member co-op profits and used to seed new ones, has decades of data on exactly this kind of lending.
**And a warning:** Uruguay's public fund for worker-run firms, FONDES, lost almost 90% of its loan book within five years, mostly on rescues of already-failed firms with political connections. [The pilot](pilot-spec.md#two-warnings-from-real-life) is designed around that failure.
@@ -0,0 +1,32 @@
---
title: Ownership and the Floor
section: Beyond Co-ops
order: 110
summary: Ownership ends the skim, but a floor ends the hunger. Low-margin work needs both, and the floor can't wait for the co-op sector to grow.
---
# Ownership and the Floor
This is the correction that matters most, and it took the longest to see.
**Equal ownership within firms does not produce equal outcomes across them.**
A worker-owned cleaning company still operates on cleaning-company margins, maybe $8k of profit per head. A worker-owned software firm throws off $150k per head. Both workers are owners. One of them still can't feed their kids.
Profit-per-head is set by technology and demand elasticity, forces ownership rules don't reach. Cleaning productivity has barely moved in forty years: one person, one mop. Ownership of the surplus doesn't change how much surplus *exists*.
So:
- **Ownership ends the skim.** It is the right answer to *extraction*: a large surplus flowing to people who didn't make it.
- **A floor ends the hunger.** The home health aide, the childcare worker, the line cook: their problem was never that private equity was skimming their $150k. Their problem is there is no $150k.
You need both. They do different jobs. And because the model doesn't force anyone to convert, this section matters *more*, not less: the co-op sector will grow slowly, if it grows at all, and the floor doesn't wait for it. **One in six Utah kids goes hungry, and a lot of their parents work in sectors where there is barely any surplus to own.**
The floor, in pieces:
- A strong minimum wage.
- **Targeted subsidy for essential low-margin work, paid to workers, not firms.** Somebody has to clean the nursing home for the poor. If the sector can't pay, the public does, directly, so the buyer can't absorb the subsidy by bidding less.
- **Funded automation research aimed at exactly those sectors.** If productivity can't rise on its own, raise it. This is explicitly a *transition* strategy: support the workers until the technology lands. Say that out loud, or you end up permanently subsidizing a job you're simultaneously trying to eliminate, and the subsidized workers start lobbying against the automation. (This is what happened with coal.)
- **A transitional public temp corps.** Companies apply for subsidized labor. The state supplies temps and funds the automation in parallel. Everyone knows going in that the job has a sunset. Voluntary, real wages, open to anyone who wants a bridge.
**The endpoint:** a society where work is not the price of being allowed to eat. Where people who don't work are taken care of, and people who work are people who want *more*: the finer things, a bigger share, the reward for doing what's hard or what nobody else will do.
@@ -0,0 +1,22 @@
---
title: The Lock
section: The Co-op
order: 30
summary: Any co-op funded by the bank stays a co-op forever. It can't be sold to conventional owners or cashed out by its members.
---
# The Lock
**Any firm funded by the bank stays a worker co-op forever. It can never be bought, sold, or converted into anything else.**
The lock is what keeps a successful experiment from being quietly bought back. Without it, the best-performing co-ops are the likeliest takeover targets, and every success becomes an acquisition. The lock exists so that wins accumulate instead of being harvested.
What it covers:
- **No sale to a non-co-op.** A co-op may merge with or be absorbed by another locked co-op. It may never be sold to conventional owners.
- **No demutualization.** Members cannot vote to dissolve the co-op and split the value. (This is the failure mode that ended many US mutual savings banks and UK building societies: a generation of members cashed out what earlier generations built.)
- **No outside voting equity.** Outside money comes in only as voteless, expiring claims (see [Capital, After](capital.md)).
- **Membership requirement.** A locked co-op cannot run on hired non-member labor. Workers become members after a defined probationary period (the pilot caps it at 12 months). This blocks the "degeneration" pattern, where a co-op becomes a small ownership club employing a large wage-labor underclass. Mondragon's non-member foreign subsidiaries are the warning case.
- **Indivisible reserves.** A slice of every year's profit goes to a collective reserve no member can ever withdraw. On dissolution, after debts are paid, remaining assets go to the federation fund, not to the members. Italian co-op law already works this way. It removes the incentive to kill the co-op for its assets.
What the lock does *not* do: keep failing firms alive. A locked co-op can still go bankrupt, and its assets can still be sold in liquidation. It just can't be sold as a going concern to anyone but another co-op.
@@ -0,0 +1,18 @@
---
title: The Test
section: Growing the Sector
order: 60
summary: The bank runs as an experiment: metrics set in advance, a fixed review date, and a scale-up or wind-down rule nobody can change after seeing the data.
---
# The Test
The bank is an experiment, so it runs like one.
- **Pre-register the metrics before the first loan:** survival rates, productivity, wages, member retention, and loan performance, measured against matched conventional firms in the same sectors and regions.
- **Fixed review point.** After a set period (long enough to see business cycles), an independent review publishes the results. The pilot sets it at year 12.
- **Scale-up or wind-down, decided in advance.** If co-ops match or beat conventional firms at market-rate lending, the bank's capital is expanded. If they don't, it's wound down and the loan book is sold. Both outcomes are written into the charter from day one, so nobody can move the goalposts after seeing the data. That includes me.
[The Pilot, in Numbers](pilot-spec.md) spells all of this out: the exact measures, the comparison group, the pass and fail thresholds, and an emergency stop.
**What the test can prove, and what it can't.** At pilot scale, this tests *business viability*: can co-ops compete, survive, and repay market-rate debt? It does **not** test the labor-market effect, meaning the idea that as co-ops grow, conventional firms have to treat workers better or lose them. That effect is real in principle, but it needs a co-op sector big enough to move wages at the margin. Mondragon employs tens of thousands of people and hasn't reshaped Spanish employment practice. The labor-market effect is the long-run payoff of success, not something the pilot can claim.
+18
View File
@@ -0,0 +1,18 @@
---
title: The Thesis
section: Foundations
order: 10
summary: Personal property is untouchable. Productive capital, a permanent claim on other people's work, is a different thing, and there should be firms where that claim never forms.
---
# The Thesis
**The word "property" protects two very different things, and only one of them deserves that protection.**
There is *personal property*: your house, your car, your savings, your tools. The things you live in and use. These are untouchable. Nobody is collectivizing your couch.
Then there is *productive capital*: a perpetual, tradeable claim on the output of a thousand people you will never meet. This is not the same kind of right. It has been wearing the same word by accident, and the accident does political work for the people who benefit from it.
The dividing line: **it stops being a tool and becomes capital when it earns you a claim on other people's labor that you don't work alongside.** The plumber's van is not extracting from anyone. TPG's stake in Conservice is.
What follows from the thesis is not "therefore the state may take that capital." It is something narrower and harder to argue with: **therefore there should be firms where that claim never forms in the first place, and nothing in law or finance should stop people from building them.**
@@ -0,0 +1,23 @@
---
title: Worker Ownership
section: The Co-op
order: 20
summary: What a worker co-op means here: one member, one vote from day one, and a profit share that grows with tenure and then caps.
---
# Worker Ownership
A worker co-op under this model means two things, and they are not the same thing:
**One worker, one vote. Unconditional, from membership.** This is the moral core and it does not ramp, vest, or vary. The objection to the current system is *domination*: being ruled by a distant firm that answers to nobody who works there. The cure for domination is the vote, and you don't earn your way into not being dominated.
**Profit share ramps with tenure, then caps.** A new member starts at a partial share and grows to a full, equal share over roughly five to ten years. After the cap, everyone's share is identical. The thirty-year lifer and the eight-year veteran split profit the same.
Why the ramp: it kills the dilution panic. Under flat equal shares, every new hire immediately eats everyone's slice, and cooperatives empirically under-hire for exactly that reason. With a ramp, hiring decisions move toward "does this person grow the pie" during precisely the window when their value is most uncertain.
Why the cap: uncapped tenure weighting builds a gerontocracy of shares and chains people to their first employer. Capped at a career-fraction, people can change companies, move cities, start over, and still reach a full share with plenty of career left.
- **Base salaries still exist**, set by the company. A brain surgeon won't work somewhere without a high salary, and shouldn't have to. Hard jobs and in-demand jobs still pay more. The incentive to do difficult work survives intact.
- **Governance is up to each company.** Workers pass bylaws deciding what requires a vote and what doesn't. Some will use direct democracy, some representative systems, some will delegate almost everything to management they hire and can fire. "Workers vote on every decision" is a strawman and always was.
The concrete case: the average employee where I work generates roughly $150,000/year in profit after all costs. That money currently flows upward to private equity. A firm with those economics, built as a co-op, sends it to the people who made it.
+9
View File
@@ -9,9 +9,18 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="1.4.0" />
<PackageReference Include="System.Text.Json" Version="9.0.3" />
</ItemGroup>
<ItemGroup>
<!-- Public /socialism documents. Underscore-prefixed files (founding draft, progress log) are private and never deployed. -->
<Content Include="Content/Socialism/*.md" Exclude="Content/Socialism/_*.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Resources/**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+15
View File
@@ -0,0 +1,15 @@
namespace JoshHeaps.Net.Models;
public class SocialismDoc
{
public string Slug { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Summary { get; set; } = string.Empty;
public string Section { get; set; } = string.Empty;
public int Order { get; set; }
public string HtmlContent { get; set; } = string.Empty;
public List<SocialismHeading> Headings { get; set; } = [];
public int ReadingMinutes { get; set; }
}
public record SocialismHeading(int Level, string Id, string Text);
+60
View File
@@ -0,0 +1,60 @@
@page "/socialism/{slug}"
@model JoshHeaps.Net.Pages.Socialism.DocModel
@{
ViewData["Title"] = Model.Doc!.Title + " - JoshHeaps.Net";
Layout = "_Layout";
}
<div class="soc-progress" id="socProgress"></div>
<button class="soc-menu-toggle" id="socMenuToggle" aria-controls="socSidebar" aria-expanded="false">Contents</button>
<div class="soc-shell">
<partial name="_Nav" model="Model" />
<div class="soc-main">
<nav class="soc-breadcrumbs" aria-label="Breadcrumb">
<a href="/socialism">Overview</a>
@if (!string.IsNullOrEmpty(Model.Doc.Section))
{
<span>/</span><span>@Model.Doc.Section</span>
}
</nav>
<header class="soc-doc-header">
<h1 class="soc-doc-title">@Model.Doc.Title</h1>
@if (!string.IsNullOrEmpty(Model.Doc.Summary))
{
<p class="soc-doc-summary">@Model.Doc.Summary</p>
}
<span class="soc-doc-meta">@Model.Doc.ReadingMinutes min read</span>
</header>
<article class="soc-content">
@Html.Raw(Model.Doc.HtmlContent)
</article>
<nav class="soc-pager" aria-label="Previous and next">
@if (Model.Previous is not null)
{
<a class="soc-pager-link prev" href="@(Model.Previous.Slug == SocialismDocService.IndexSlug ? "/socialism" : "/socialism/" + Model.Previous.Slug)">
<span class="soc-pager-label">&larr; Previous</span>
<span class="soc-pager-title">@(Model.Previous.Slug == SocialismDocService.IndexSlug ? "Overview" : Model.Previous.Title)</span>
</a>
}
@if (Model.Next is not null)
{
<a class="soc-pager-link next" href="/socialism/@Model.Next.Slug">
<span class="soc-pager-label">Next &rarr;</span>
<span class="soc-pager-title">@Model.Next.Title</span>
</a>
}
</nav>
</div>
<partial name="_Toc" model="Model.Doc.Headings" />
</div>
@section Styles {
<partial name="_Head" />
}
@@ -0,0 +1,31 @@
using JoshHeaps.Net.Models;
using JoshHeaps.Net.Services.Implementations;
using JoshHeaps.Net.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace JoshHeaps.Net.Pages.Socialism;
public class DocModel(ISocialismDocService docService) : SocialismPageModel
{
public SocialismDoc? Doc { get; private set; }
public SocialismDoc? Previous { get; private set; }
public SocialismDoc? Next { get; private set; }
public IActionResult OnGet(string slug)
{
if (slug == SocialismDocService.IndexSlug)
return RedirectPermanent("/socialism");
Doc = docService.GetDoc(slug);
if (Doc is null)
return NotFound();
CurrentSlug = slug;
AllDocs = docService.GetAllDocs();
var position = AllDocs.FindIndex(d => d.Slug == slug);
Previous = position > 0 ? AllDocs[position - 1] : null;
Next = position >= 0 && position < AllDocs.Count - 1 ? AllDocs[position + 1] : null;
return Page();
}
}
@@ -0,0 +1,65 @@
@page "/socialism"
@model JoshHeaps.Net.Pages.Socialism.IndexModel
@{
ViewData["Title"] = Model.Overview!.Title + " - JoshHeaps.Net";
Layout = "_Layout";
}
<div class="soc-progress" id="socProgress"></div>
<button class="soc-menu-toggle" id="socMenuToggle" aria-controls="socSidebar" aria-expanded="false">Contents</button>
<div class="soc-shell">
<partial name="_Nav" model="Model" />
<div class="soc-main">
<header class="soc-hero">
<h1 class="soc-hero-title">@Model.Overview.Title</h1>
@if (!string.IsNullOrEmpty(Model.Overview.Summary))
{
<p class="soc-hero-summary">@Model.Overview.Summary</p>
}
@if (Model.Chapters.Count > 0)
{
<a class="soc-hero-cta" href="/socialism/@Model.Chapters[0].Slug">Start reading &rarr;</a>
}
</header>
<article class="soc-content">
@Html.Raw(Model.Overview.HtmlContent)
</article>
@if (Model.Chapters.Count > 0)
{
<section class="soc-chapters" id="explore">
<h2 class="soc-chapters-title">Explore the full model</h2>
@foreach (var group in Model.Chapters.GroupBy(d => d.Section))
{
@if (!string.IsNullOrEmpty(group.Key))
{
<h3 class="soc-chapters-group">@group.Key</h3>
}
<div class="soc-card-grid">
@foreach (var doc in group)
{
<a class="soc-card" href="/socialism/@doc.Slug">
<span class="soc-card-title">@doc.Title</span>
@if (!string.IsNullOrEmpty(doc.Summary))
{
<span class="soc-card-summary">@doc.Summary</span>
}
<span class="soc-card-meta">@doc.ReadingMinutes min read</span>
</a>
}
</div>
}
</section>
}
</div>
<partial name="_Toc" model="Model.Overview.Headings" />
</div>
@section Styles {
<partial name="_Head" />
}
@@ -0,0 +1,24 @@
using JoshHeaps.Net.Models;
using JoshHeaps.Net.Services.Implementations;
using JoshHeaps.Net.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace JoshHeaps.Net.Pages.Socialism;
public class IndexModel(ISocialismDocService docService) : SocialismPageModel
{
public SocialismDoc? Overview { get; private set; }
public List<SocialismDoc> Chapters { get; private set; } = [];
public IActionResult OnGet()
{
Overview = docService.GetDoc(SocialismDocService.IndexSlug);
if (Overview is null)
return NotFound();
CurrentSlug = SocialismDocService.IndexSlug;
AllDocs = docService.GetAllDocs();
Chapters = AllDocs.Where(d => d.Slug != SocialismDocService.IndexSlug).ToList();
return Page();
}
}
@@ -0,0 +1,21 @@
using JoshHeaps.Net.Models;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace JoshHeaps.Net.Pages.Socialism;
/// <summary>
/// Shared base for the /socialism pages. These pages are unlisted: nothing links to them
/// and search engines are told not to index them.
/// </summary>
public abstract class SocialismPageModel : PageModel
{
public List<SocialismDoc> AllDocs { get; protected set; } = [];
public string CurrentSlug { get; protected set; } = string.Empty;
public override void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
Response.Headers["X-Robots-Tag"] = "noindex, nofollow";
base.OnPageHandlerExecuting(context);
}
}
@@ -0,0 +1,4 @@
<meta name="robots" content="noindex, nofollow" />
<link href="/css/variables.css?v=@ViewData["cssVersion"]" rel="stylesheet" type="text/css" />
<link href="/css/socialism/socialism.css?v=@ViewData["cssVersion"]" rel="stylesheet" type="text/css" />
<script src="/js/socialism/socialism.js?v=@ViewData["cssVersion"]" defer></script>
+32
View File
@@ -0,0 +1,32 @@
@model SocialismPageModel
@{
var groups = Model.AllDocs
.Where(d => d.Slug != SocialismDocService.IndexSlug)
.GroupBy(d => d.Section);
}
<nav class="soc-sidebar" id="socSidebar" aria-label="Document navigation">
<a href="/socialism" class="soc-sidebar-home @(Model.CurrentSlug == SocialismDocService.IndexSlug ? "active" : "")">Overview</a>
<input type="search" class="soc-filter" id="socFilter" placeholder="Filter sections..." aria-label="Filter sections" />
@foreach (var group in groups)
{
<div class="soc-nav-group">
@if (!string.IsNullOrEmpty(group.Key))
{
<div class="soc-nav-group-title">@group.Key</div>
}
<ul>
@foreach (var doc in group)
{
<li>
<a href="/socialism/@doc.Slug"
class="soc-nav-link @(doc.Slug == Model.CurrentSlug ? "active" : "")"
data-filter-text="@doc.Title.ToLowerInvariant() @doc.Summary.ToLowerInvariant()">@doc.Title</a>
</li>
}
</ul>
</div>
}
</nav>
+16
View File
@@ -0,0 +1,16 @@
@model List<SocialismHeading>
@if (Model.Count > 1)
{
<aside class="soc-toc" aria-label="On this page">
<div class="soc-toc-title">On this page</div>
<ul>
@foreach (var heading in Model)
{
<li class="[email protected]">
<a href="#@heading.Id" data-toc-id="@heading.Id">@heading.Text</a>
</li>
}
</ul>
</aside>
}
@@ -0,0 +1,4 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using JoshHeaps.Net.Models
@using JoshHeaps.Net.Pages.Socialism
@using JoshHeaps.Net.Services.Implementations
+1
View File
@@ -20,6 +20,7 @@ builder.Services.AddHttpClient("BlogApi", client =>
client.Timeout = TimeSpan.FromSeconds(10);
});
builder.Services.AddSingleton<IBlogService, BlogService>();
builder.Services.AddSingleton<ISocialismDocService, SocialismDocService>();
builder.Services.AddSingleton<IChessService, ChessService>();
builder.Services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
@@ -0,0 +1,178 @@
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using JoshHeaps.Net.Models;
using JoshHeaps.Net.Services.Interfaces;
using Markdig;
using Markdig.Renderers.Html;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
namespace JoshHeaps.Net.Services.Implementations;
/// <summary>
/// Serves the markdown documents in Content/Socialism. Files starting with an underscore
/// (the founding draft, the progress log) are private and never served.
/// </summary>
public partial class SocialismDocService : ISocialismDocService
{
public const string IndexSlug = "index";
private readonly string _contentDir;
private readonly ILogger<SocialismDocService> _logger;
private readonly ConcurrentDictionary<string, CacheEntry> _cache = new();
private static readonly MarkdownPipeline Pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
public SocialismDocService(IWebHostEnvironment env, ILogger<SocialismDocService> logger)
{
_contentDir = Path.Combine(env.ContentRootPath, "Content", "Socialism");
_logger = logger;
}
public SocialismDoc? GetDoc(string slug)
{
if (!IsValidSlug(slug))
return null;
var path = Path.Combine(_contentDir, slug + ".md");
if (!File.Exists(path))
return null;
// Cache keyed on last-write time so edited documents show up without a restart.
var lastWrite = File.GetLastWriteTimeUtc(path);
if (_cache.TryGetValue(slug, out var entry) && entry.LastWrite == lastWrite)
return entry.Doc;
try
{
var doc = Parse(slug, File.ReadAllText(path));
_cache[slug] = new CacheEntry(doc, lastWrite);
return doc;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to render socialism doc {Slug}", slug);
return entry?.Doc;
}
}
public List<SocialismDoc> GetAllDocs()
{
if (!Directory.Exists(_contentDir))
return [];
return Directory.EnumerateFiles(_contentDir, "*.md")
.Select(Path.GetFileNameWithoutExtension)
.Where(slug => slug is not null && IsValidSlug(slug))
.Select(slug => GetDoc(slug!))
.OfType<SocialismDoc>()
.OrderBy(d => d.Slug == IndexSlug ? 0 : 1)
.ThenBy(d => d.Order)
.ThenBy(d => d.Title)
.ToList();
}
// Lowercase letters, digits and hyphens only: rules out private "_" files and path traversal.
private static bool IsValidSlug(string slug) => SlugRegex().IsMatch(slug);
private static SocialismDoc Parse(string slug, string raw)
{
var (meta, body) = SplitFrontMatter(raw);
var markdown = Markdown.Parse(body, Pipeline);
var headings = new List<SocialismHeading>();
string? firstH1 = null;
foreach (var heading in markdown.Descendants<HeadingBlock>())
{
var text = InlineText(heading.Inline);
if (heading.Level == 1)
{
firstH1 ??= text;
continue;
}
var id = heading.GetAttributes().Id;
if (heading.Level <= 3 && !string.IsNullOrEmpty(id))
headings.Add(new SocialismHeading(heading.Level, id, text));
}
foreach (var link in markdown.Descendants<LinkInline>())
{
if (!link.IsImage && link.Url is not null)
link.Url = RewriteLink(link.Url);
}
var words = WordRegex().Matches(body).Count;
return new SocialismDoc
{
Slug = slug,
Title = meta.GetValueOrDefault("title") ?? firstH1 ?? slug,
Summary = meta.GetValueOrDefault("summary") ?? string.Empty,
Section = meta.GetValueOrDefault("section") ?? string.Empty,
Order = int.TryParse(meta.GetValueOrDefault("order"), out var order) ? order : int.MaxValue,
HtmlContent = markdown.ToHtml(Pipeline),
Headings = headings,
ReadingMinutes = Math.Max(1, (int)Math.Round(words / 230.0))
};
}
// "economy.md#floor" -> "/socialism/economy#floor"; "index.md" -> "/socialism".
private static string RewriteLink(string url)
{
var match = RelativeDocLinkRegex().Match(url);
if (!match.Success)
return url;
var target = match.Groups["slug"].Value;
var anchor = match.Groups["anchor"].Value;
return (target == IndexSlug ? "/socialism" : $"/socialism/{target}") + anchor;
}
private static (Dictionary<string, string> Meta, string Body) SplitFrontMatter(string raw)
{
var meta = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var match = FrontMatterRegex().Match(raw);
if (!match.Success)
return (meta, raw);
foreach (var line in match.Groups["yaml"].Value.Split('\n'))
{
var idx = line.IndexOf(':');
if (idx <= 0)
continue;
meta[line[..idx].Trim()] = line[(idx + 1)..].Trim().Trim('"');
}
return (meta, raw[match.Length..]);
}
private static string InlineText(ContainerInline? inline)
{
if (inline is null)
return string.Empty;
return string.Concat(inline.Descendants<Inline>().Select(i => i switch
{
LiteralInline literal => literal.Content.ToString(),
CodeInline code => code.Content,
_ => string.Empty
}));
}
[GeneratedRegex("^[a-z0-9][a-z0-9-]*$")]
private static partial Regex SlugRegex();
[GeneratedRegex(@"^(?:\./)?(?<slug>[a-z0-9][a-z0-9-]*)\.md(?<anchor>#[^\s]*)?$")]
private static partial Regex RelativeDocLinkRegex();
[GeneratedRegex(@"\A---\r?\n(?<yaml>.*?)\r?\n---\r?\n", RegexOptions.Singleline)]
private static partial Regex FrontMatterRegex();
[GeneratedRegex(@"\b\w+\b")]
private static partial Regex WordRegex();
private record CacheEntry(SocialismDoc Doc, DateTime LastWrite);
}
@@ -0,0 +1,9 @@
using JoshHeaps.Net.Models;
namespace JoshHeaps.Net.Services.Interfaces;
public interface ISocialismDocService
{
SocialismDoc? GetDoc(string slug);
List<SocialismDoc> GetAllDocs();
}
@@ -0,0 +1,557 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
scroll-padding-top: 1.5rem;
}
body {
margin: 0;
background-color: var(--color-bg);
color: var(--color-text);
font-family: var(--font-body);
line-height: 1.6;
}
/* ── Reading progress ── */
.soc-progress {
position: fixed;
top: 0;
left: 0;
height: 2px;
width: 0;
background: var(--color-accent);
z-index: 20;
transition: width 0.1s linear;
}
/* ── Three-column shell: nav | content | on-this-page ── */
.soc-shell {
display: grid;
grid-template-columns: 250px minmax(0, 760px) 220px;
justify-content: center;
gap: 3rem;
padding: 0 clamp(1rem, 3vw, 2rem);
}
.soc-main {
padding: 4rem 0 6rem;
min-width: 0;
}
/* ── Sidebar ── */
.soc-sidebar {
position: sticky;
top: 0;
align-self: start;
max-height: 100vh;
overflow-y: auto;
padding: 4rem 0 2rem;
scrollbar-width: thin;
scrollbar-color: var(--color-border) transparent;
}
.soc-sidebar-home {
display: block;
color: var(--color-heading-secondary);
font-weight: 600;
text-decoration: none;
margin-bottom: 1rem;
}
.soc-sidebar-home.active,
.soc-sidebar-home:hover {
color: var(--color-accent);
}
.soc-filter {
width: 100%;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 6px;
color: var(--color-heading-secondary);
padding: 0.45rem 0.65rem;
font: inherit;
font-size: 0.8rem;
margin-bottom: 1.25rem;
}
.soc-filter:focus {
outline: none;
border-color: var(--color-accent-border);
}
.soc-nav-group {
margin-bottom: 1.25rem;
}
.soc-nav-group-title {
color: var(--color-text-subtle);
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 0.4rem;
}
.soc-sidebar ul {
list-style: none;
margin: 0;
padding: 0;
}
.soc-nav-link {
display: block;
color: var(--color-text);
text-decoration: none;
font-size: 0.85rem;
padding: 0.3rem 0 0.3rem 0.75rem;
border-left: 1px solid var(--color-border);
transition: color 0.2s, border-color 0.2s;
}
.soc-nav-link:hover {
color: var(--color-heading-secondary);
border-left-color: var(--color-border-hover);
}
.soc-nav-link.active {
color: var(--color-accent);
border-left-color: var(--color-accent);
}
.soc-nav-link.hidden {
display: none;
}
/* ── On this page ── */
.soc-toc {
position: sticky;
top: 0;
align-self: start;
max-height: 100vh;
overflow-y: auto;
padding: 4rem 0 2rem;
font-size: 0.8rem;
}
.soc-toc-title {
color: var(--color-text-subtle);
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 0.6rem;
}
.soc-toc ul {
list-style: none;
margin: 0;
padding: 0;
}
.soc-toc a {
display: block;
color: var(--color-text-subtle);
text-decoration: none;
padding: 0.2rem 0;
transition: color 0.2s;
}
.soc-toc .soc-toc-level-3 a {
padding-left: 0.85rem;
}
.soc-toc a:hover {
color: var(--color-heading-secondary);
}
.soc-toc a.active {
color: var(--color-accent);
}
/* ── Landing hero ── */
.soc-hero {
margin-bottom: 3rem;
}
.soc-hero-title {
color: var(--color-heading);
font-size: clamp(2rem, 4vw, 2.75rem);
letter-spacing: -0.02em;
line-height: 1.15;
margin: 0 0 1rem;
}
.soc-hero-summary {
color: var(--color-heading-secondary);
font-size: 1.15rem;
line-height: 1.7;
margin: 0 0 1.5rem;
}
.soc-hero-cta {
display: inline-block;
color: var(--color-bg);
background: var(--color-accent);
font-weight: 600;
font-size: 0.9rem;
text-decoration: none;
padding: 0.55rem 1.1rem;
border-radius: 6px;
transition: background 0.2s;
}
.soc-hero-cta:hover {
background: var(--color-accent-hover);
}
/* ── Chapter cards ── */
.soc-chapters {
margin-top: 4rem;
}
.soc-chapters-title {
color: var(--color-heading);
font-size: 1.4rem;
margin: 0 0 1.25rem;
}
.soc-chapters-group {
color: var(--color-text-subtle);
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.08em;
margin: 2rem 0 0.75rem;
}
.soc-card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 1rem;
}
.soc-card {
display: flex;
flex-direction: column;
gap: 0.4rem;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 10px;
padding: 1.1rem 1.2rem;
text-decoration: none;
transition: background 0.2s, border-color 0.2s, transform 0.2s;
}
.soc-card:hover {
background: var(--color-surface-hover);
border-color: var(--color-accent-border);
transform: translateY(-2px);
}
.soc-card-title {
color: var(--color-heading-secondary);
font-weight: 600;
}
.soc-card-summary {
color: var(--color-text);
font-size: 0.85rem;
line-height: 1.5;
flex: 1;
}
.soc-card-meta {
color: var(--color-text-subtle);
font-size: 0.75rem;
}
/* ── Document header ── */
.soc-breadcrumbs {
display: flex;
gap: 0.5rem;
font-size: 0.8rem;
color: var(--color-text-subtle);
}
.soc-breadcrumbs a {
color: var(--color-text-subtle);
text-decoration: none;
transition: color 0.2s;
}
.soc-breadcrumbs a:hover {
color: var(--color-heading-secondary);
}
.soc-doc-header {
margin: 1.5rem 0 2.5rem;
}
.soc-doc-title {
color: var(--color-heading);
font-size: clamp(1.75rem, 3vw, 2.25rem);
letter-spacing: -0.02em;
line-height: 1.25;
margin: 0 0 0.75rem;
}
.soc-doc-summary {
color: var(--color-heading-secondary);
font-size: 1.05rem;
margin: 0 0 0.5rem;
}
.soc-doc-meta {
color: var(--color-text-subtle);
font-size: 0.8rem;
}
/* ── Rendered markdown ── */
.soc-content {
line-height: 1.8;
}
.soc-content > h1:first-child {
display: none; /* the page header already shows the title */
}
.soc-content h2,
.soc-content h3,
.soc-content h4 {
position: relative;
color: var(--color-heading-secondary);
letter-spacing: -0.01em;
margin: 2.5rem 0 0.75rem;
}
.soc-content h2 {
font-size: 1.45rem;
padding-top: 1.5rem;
border-top: 1px solid var(--color-border);
}
.soc-content h3 { font-size: 1.15rem; }
.soc-anchor {
position: absolute;
left: -1.2em;
color: var(--color-text-subtle);
text-decoration: none;
opacity: 0;
transition: opacity 0.2s;
}
.soc-content h2:hover .soc-anchor,
.soc-content h3:hover .soc-anchor {
opacity: 1;
}
.soc-content p {
margin: 0 0 1.25rem;
}
.soc-content a {
color: var(--color-accent);
text-decoration: none;
}
.soc-content a:hover {
color: var(--color-accent-hover);
text-decoration: underline;
}
.soc-content strong {
color: var(--color-heading-secondary);
}
.soc-content ul,
.soc-content ol {
margin: 0 0 1.25rem 1.5rem;
padding: 0;
}
.soc-content li {
margin-bottom: 0.4rem;
}
.soc-content blockquote {
margin: 1.5rem 0;
padding: 0.75rem 1.25rem;
border-left: 3px solid var(--color-accent);
background: var(--color-surface);
color: var(--color-heading-secondary);
border-radius: 0 8px 8px 0;
}
.soc-content blockquote p:last-child {
margin-bottom: 0;
}
.soc-content hr {
border: none;
border-top: 1px solid var(--color-border);
margin: 2.5rem 0;
}
.soc-content code {
background: var(--color-surface-raised);
color: var(--color-heading-secondary);
padding: 0.15rem 0.4rem;
border-radius: 4px;
font-size: 0.85em;
font-family: var(--font-mono);
}
.soc-content table {
width: 100%;
border-collapse: collapse;
margin: 0 0 1.5rem;
font-size: 0.9rem;
display: block;
overflow-x: auto;
}
.soc-content th,
.soc-content td {
border: 1px solid var(--color-border);
padding: 0.5rem 0.75rem;
text-align: left;
vertical-align: top;
}
.soc-content th {
background: var(--color-surface-raised);
color: var(--color-heading-secondary);
}
.soc-content details {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 8px;
padding: 0.75rem 1rem;
margin: 0 0 1.25rem;
}
.soc-content summary {
cursor: pointer;
color: var(--color-heading-secondary);
font-weight: 600;
}
.soc-content .footnotes {
font-size: 0.85rem;
color: var(--color-text-subtle);
}
/* ── Pager ── */
.soc-pager {
display: flex;
gap: 1rem;
margin-top: 4rem;
}
.soc-pager-link {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.2rem;
border: 1px solid var(--color-border);
border-radius: 10px;
padding: 0.9rem 1.1rem;
text-decoration: none;
transition: border-color 0.2s, background 0.2s;
}
.soc-pager-link.next {
text-align: right;
margin-left: auto;
}
.soc-pager-link:hover {
border-color: var(--color-accent-border);
background: var(--color-surface);
}
.soc-pager-label {
color: var(--color-text-subtle);
font-size: 0.75rem;
}
.soc-pager-title {
color: var(--color-heading-secondary);
font-weight: 600;
}
/* ── Mobile ── */
.soc-menu-toggle {
display: none;
}
@media (max-width: 1200px) {
.soc-shell {
grid-template-columns: 230px minmax(0, 760px);
}
.soc-toc {
display: none;
}
}
@media (max-width: 860px) {
.soc-shell {
grid-template-columns: minmax(0, 1fr);
}
.soc-main {
padding-top: 4.5rem;
}
.soc-menu-toggle {
display: block;
position: fixed;
top: 1rem;
left: 1rem;
z-index: 15;
background: var(--color-surface-raised);
backdrop-filter: blur(8px);
border: 1px solid var(--color-border);
border-radius: 6px;
color: var(--color-heading-secondary);
font: inherit;
font-size: 0.85rem;
padding: 0.4rem 0.8rem;
cursor: pointer;
}
.soc-sidebar {
position: fixed;
inset: 0 30% 0 0;
min-width: 260px;
max-height: none;
background: var(--color-bg);
border-right: 1px solid var(--color-border);
padding: 4.5rem 1.25rem 2rem;
z-index: 10;
transform: translateX(-100%);
transition: transform 0.25s ease;
}
.soc-sidebar.open {
transform: translateX(0);
}
.soc-pager {
flex-direction: column;
}
}
@@ -0,0 +1,86 @@
document.addEventListener('DOMContentLoaded', () => {
addHeadingAnchors();
trackReadingProgress();
highlightCurrentSection();
setUpSidebarFilter();
setUpMobileMenu();
});
// Hover "#" links on headings so any section can be linked to directly.
function addHeadingAnchors() {
document.querySelectorAll('.soc-content h2[id], .soc-content h3[id]').forEach(heading => {
const anchor = document.createElement('a');
anchor.className = 'soc-anchor';
anchor.href = '#' + heading.id;
anchor.textContent = '#';
anchor.setAttribute('aria-label', 'Link to this section');
heading.prepend(anchor);
});
}
function trackReadingProgress() {
const bar = document.getElementById('socProgress');
if (!bar) return;
const update = () => {
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
bar.style.width = scrollable > 0 ? (window.scrollY / scrollable) * 100 + '%' : '0';
};
window.addEventListener('scroll', update, { passive: true });
update();
}
// Highlights the "On this page" entry for the section currently being read.
function highlightCurrentSection() {
const links = [...document.querySelectorAll('.soc-toc a[data-toc-id]')];
if (links.length === 0) return;
const headings = links
.map(link => document.getElementById(link.dataset.tocId))
.filter(Boolean);
const update = () => {
let current = headings[0];
for (const heading of headings) {
if (heading.getBoundingClientRect().top <= 120) current = heading;
}
links.forEach(link => link.classList.toggle('active', link.dataset.tocId === current?.id));
};
window.addEventListener('scroll', update, { passive: true });
update();
}
function setUpSidebarFilter() {
const input = document.getElementById('socFilter');
if (!input) return;
input.addEventListener('input', () => {
const query = input.value.trim().toLowerCase();
document.querySelectorAll('.soc-nav-link').forEach(link => {
link.classList.toggle('hidden', query !== '' && !link.dataset.filterText.includes(query));
});
document.querySelectorAll('.soc-nav-group').forEach(group => {
const anyVisible = group.querySelector('.soc-nav-link:not(.hidden)');
group.style.display = anyVisible ? '' : 'none';
});
});
}
function setUpMobileMenu() {
const toggle = document.getElementById('socMenuToggle');
const sidebar = document.getElementById('socSidebar');
if (!toggle || !sidebar) return;
const setOpen = open => {
sidebar.classList.toggle('open', open);
toggle.setAttribute('aria-expanded', String(open));
toggle.textContent = open ? 'Close' : 'Contents';
};
toggle.addEventListener('click', () => setOpen(!sidebar.classList.contains('open')));
sidebar.addEventListener('click', event => {
if (event.target.closest('a')) setOpen(false);
});
}