How to publish here
What to type, where it goes, and the handful of things that make a page come out wrong without telling you. The build-side documentation lives in the theme repo; this is the writing side.
Ghost will happily publish something half-tagged. The theme is what notices. Almost everything below is a consequence of that one fact.
The eight things you publish
Everything except Footnotes is a Ghost post or page. Footnotes never touches Ghost — entries appear the moment you save them in the admin tool, with no publish step. And there are no custom theme settings anywhere in Ghost admin: the whole authoring surface is the body, the tags, the excerpt, the feature image and the post's meta fields.
What each type needs
roundup, bad-job-bingo, deep-dives — bare slugs, settled. The series tint on the issue-number cell comes from this.#issue-NNN, zero-padded, next in the house sequence — one sequence for the whole newsletter regardless of series. That is the whole step: the numeral cell reads the tag's description, and the deploy fills it in from the name within the hour (until then the cell shows the date). Typing the digits into the description yourself just makes it immediate. A deleted issue leaves a gap forever; never renumber.bjb-*), discipline, level, type, arrangement, salary band (the rung holding the top of the posted range), location, company, status — all on namespaced slugs (job-discipline-*, job-status-open…). Salary is one rung of the seven-band ladder (job-salary-0-50k … job-salary-300k-plus) or a no-comp tag; exact ranges go in the body as text. IT IS A MYSTERY is a location tag — the posting never said where the job is.Location: New York City. The theme lifts a line of exactly that shape into the header and the rail; countries show in the header, states and provinces in the rail.job-status-closed; the theme hides the Apply button and greys the strip.#resource tag. Without it the entry never appears in the library at all, and nothing warns you.res-directory-* of the ten: Podcasts, Blogs, Newsletters, Learning, Communities, Events, Books, Job Boards, Tooling, Gear.Label: value. The theme lifts it into the bordered fact table; the Website: fact powers the rail's "Open it ↗" (without one: a linked Title: fact, then the first link of a links paragraph). Recognized labels: Title, Website, Publisher, Type, Venue, Hosted by / Organizer, Platform, Format, Location, Access, Model / Version, Price / Subscription / Cost, Submitted by, Where to get it, Reviewed. Never Cadence — a schedule claim rots and nothing detects it.Vendor published only if it is. Nothing marks independent entries.res-directory-events, and the date lives in the body as <time datetime> — see Setting the body. An undated event sits in the upcoming list forever.Reviewed: row in the fact run. The other eight describe and stop.podcasts.captivate.fm/media/…), never the feed's analytics-wrapped one.#has-audio, so the archive shows the chip — added last, never first.Whose words are whose
Their words in Instrument Serif italic. Your words in the body sans. It holds on job posts, quoted passages and Footnotes, and it is the whole reason a reader can tell a company's language from yours without you having to say so.
/faqs/ states the provenance instead: assume a description came from the
resource unless a note says otherwise.Setting the body
An issue runs on three columns: a sticky contents rail on the left, the body in the middle at 562px, and a notes margin on the right. Below the breakpoint the rail collapses and the notes move to the end. Everything here was settled against a real issue, so the answer to "how do I mark this up" already exists — you are choosing from a set, not inventing.
Most of this is plain Ghost. The chip on each device says how it's authored: a green chip means you use the editor's own feature — or type the thing — and the theme styles it; a grey chip means an HTML card, and every one of those is saved as a Ghost snippet so it's a pick, not a paste.
Company · comp · location paragraph under it (type #### at the start of a line — the toolbar has no H4 button) — and the verdict's listing
count is derived from those H4s, so they are load-bearing. Department numerals and
tints are generated by the theme; add, remove or reorder departments and nothing
renumbers by hand. A Bingo verdict H2 must be the exact verdict name —
Green Means Go · Eh, It's Probably Fine · Tread Carefully · BINGO · Seriously, Maybe
Don't — because the icon, tint, rule and count all hang off matching the text.…signed agreements to acquire Contentful, m3ter,1 and the big one, Fin.
#note-1 and superscript it, or put the whole paragraph in an HTML card with the marker inside it. Save the list as a snippet; bump N per note.<p>…acquire Contentful, m3ter,<sup><a href="#note-1" data-note-ref="1">1</a></sup> and the big one, Fin.</p> <!-- one HTML card at the end of the body --> <ol class="sh-notes"> <li id="note-1">Which I had genuinely never heard of before this.</li> <li id="note-2">The second note.</li> </ol>
As I discussed in last week’s premium newsletter, the AI Tokenomics of it all are deeply unfavourable.
Ed Zitron · Where’s Your Ed At
I just want it on the record that that’s what they’re calling it.
<blockquote class="sh-pull"><p>The line, in my own voice, turned up.</p></blockquote>
Yes, they really did rename the company mid-acquisition.
Which means the number they reported last quarter was never the number at all.
<mark> around the words and stop — the theme paints one pass of coral and overrides the browser's yellow. For the display-size line-to-screenshot, the marked pull quote below — the theme injects the paint, runs two passes, and lands the swipe as the reader reaches it. Coral is the ink in an issue; the blue marker on /bad-job-bingo/ belongs to that section and is not a per-page choice. With JavaScript off a display-size mark reads as a plain pull quote — deliberate, not something to work around.…the number they reported <mark>was never the number at all</mark>. <blockquote class="sh-pull sh-pull--marked"><p>The line to screenshot.</p></blockquote>
Great people deserve great benefits
I mean, shitty people deserve great benefits too, Supabase.
note
I play Bad Job Bingo with real Customer Experience job listings, and rate them using my five-point scale. A job appearing in a positive category isn’t an endorsement of any role or company, and a job appearing in a negative category doesn’t mean I think you shouldn’t apply. You’re an adult and you get to decide.
<ul class="sh-list-short"> … </ul>
@CNN, quote-tweeted by
@EldritchGirl. On desktop the theme moves a Regular image's caption into the
notes margin. The description lives in alt, which is the one thing that
is never optional.youtube-nocookie.com / Vimeo's dnt=1 before it
leaves the page. Vertical video — TikTok, Reels — sits at 300px with your reaction
alongside. Nothing ever autoplays, and TikTok and Instagram do not load at
all until a reader presses play: their embed is a hand-authored click-to-load facade,
never a pasted URL, because their script tracks whoever opens the post otherwise.data-platform is tiktok or instagram. If you paste the URL by mistake the theme aborts their script and rebuilds a facade from the wreckage, but the rescue has no handle and no survival line — second best, not the contract.<div class="sh-video__facade" role="button" tabindex="0"
data-platform="tiktok" data-url="https://www.tiktok.com/@handle/video/…">
<div class="sh-video__facade-head"><span>TikTok</span><span>@handle</span></div>
<div class="sh-video__facade-body">
<span class="sh-video__facade-play" aria-hidden="true"></span>
<span class="sh-video__facade-cta">Play video</span>
<span class="sh-video__facade-note">Playing loads TikTok's player, which sets
their cookies. Nothing loads until you do.</span>
</div>
</div>
VIDEO REMOVED chip, your survival line
promoted to serif. Nothing detects a dead embed; the swap is yours. Do not delete
the paragraph around it.<div class="sh-video-removed">
<span class="sh-video-removed__chip">Video removed</span>
<p class="sh-video-removed__line">At eleven seconds he says the policy is
unlimited, and that every request last quarter was denied.</p>
<p class="sh-video-removed__meta">@handle · TikTok · taken down since publication</p>
</div>
Upcoming Events
snippet (the paste-ready copy is docs/snippets/upcoming-events.html in
the repo). Five fields per row in fixed order: date, place-or-time, title, host,
link. A row with no second line drops the <br><span>. Skipping
the snippet degrades to plain prose rows — the failure mode, not a second style.<div class="sh-events">
<div class="sh-event">
<p class="sh-event__when">JUL 13–14<br><span>NYC, NY</span></p>
<div class="sh-event__main">
<p class="sh-event__title">Event title</p>
<p class="sh-event__host">Hosted by <a href="…">Host</a>. <a href="…">Register →</a></p>
</div>
</div>
</div>
<time datetime="YYYY-MM-DD"> elements in the post body. Earliest is
the start, latest is the end, one element is a one-day event; the theme adds a noon
time internally so timezones can't shift the day. From the end date the row moves
under ALREADY HAPPENED on its own — and the entry page flips itself to its expired
state: grey band, THIS EVENT HAS ENDED, "Coming up instead". Never type the past
state by hand. The line's visible text is the entry page's headline dateline
(the big peach band under the title), so phrase it the way it should read at
display size. The excerpt is the human dateline —
30 Sep – 2 Oct 2026 · Austin, TX · In person — and drives display only.
Body order after the date line: facts (Type · Venue ·
Price · Website, never dates or location — the band owns
those), then one paragraph of links (Tickets · Schedule · Refund policy · Code of
conduct — the Tickets link powers the rail's black CTA, which reads Register ↗
when the link is registration-shaped and Get tickets ↗ otherwise), then the
neutral description, ending with a short Hosted by {organizer}. line,
organizer linked — the theme lifts it into the fact table as a HOSTED BY row and
the expired page's ORGANIZER row reads the same line.
Never put a TikTok or Instagram embed in an event body: the events index
renders every body to read the dates, so their script would run for every reader of
the index.<time datetime="2026-09-30">30 September</time> – <time datetime="2026-10-02">2 October 2026</time>
Unique to each type
Everything above still applies; these pull out the elements that belong to one post type only, because that is exactly what gets buried. If a page comes out wrong, check its sheet first.
Upcoming Events snippet, one row per event.#### at the start of an empty line, or paste the tool's rich-text issue copy — then a paragraph Company · comp · location with exactly two · . The theme lifts the pair into the facts block beside your commentary and draws the coloured rule between entries — never type an <hr>. No comp → No comp given. Then the quote pair: blockquote = the posting's words, your reply as plain body copy. The BJB Job Tool's issue copy emits exactly this.#has-audio goes last.Location: City, and the theme lifts it into the facts. Reader-sourced listings carry #reader-submitted.job-status-closed — the theme greys the strip and hides the Apply button (the last button card in the body).#resource + exactly one res-directory-* + any Collections. Without #resource the entry never reaches the library.Label: value paragraphs. Website: powers "Open it ↗" (fallbacks: a linked Title:, then the links paragraph's first link). Never Cadence.— their description, unedited credit is retired.Reviewed: fact row. The other eight Directories describe and stop. Vendor published only when true.res-directory-events with <time datetime> in the body, the dateline excerpt, and never a TikTok/Instagram embed card. Body order: date line · facts (Type / Venue / Price / Website) · links paragraph (Tickets / Schedule / Refund policy / Code of conduct) · description. Never dates as fact lines, never a typed past state. The meta description is the event's card line on the library indexes (the tool writes the short summary there); without one the card shows the body's first prose paragraph.Never write
The support ask
All of it is free. None of it is free to make.
Reader's benefit first, ask second. A fact rather than a plea, and it never implies anything is being withheld. Reword it if a particular page needs it — don't reinvent the shape.
Asks in order: Subscribe (if you want to), then Become a Support(ing) Human — the tier's name, never "become a member" — then Buy me a coffee. A fundraiser is a line of text, never a button. Every support block closes on this, or something with the same shape:
Support if you can, don’t worry about it if you can’t. Support Human is for you either way.
It removes the obligation instead of softening it. Do not replace it with anything that ranks the options, says what a tier unlocks, or thanks the reader in advance. Nothing is locked, so nothing can be unlocked — including by a fundraiser. One exemption: the sign-off sentence in the email is your own line and runs coffee before Support(ing) Human. That order is settled there and nowhere else. Fundraisers run two weeks with a stated end date, show a ledger and never a thermometer, and say plainly that falling short is fine.
When something is missing
<mark> and stop; the theme picks two passes or one by size.#issue-NNN leaves the numeral cell showing the date instead of a number.<time datetime> never expires out of the upcoming list.#job / #resource / #portfolio) falls through to the newsletter feed.If you are hand-writing HTML inside a post, two house rules follow
you in: text at or below 13px is never lighter than #6b6b6b on paper,
#3a3a3a on a section tint or #b8b6b4 on the near-black
ground, and never smaller than 10px; and accent color is not for body text.
Decorative marks are exempt — twinkles, oversized numerals, the Footnotes dagger †.
The four tools
<time datetime> in the body, the
dateline excerpt, and the right tags, at the real publish date.<time datetime>
line, the dateline excerpt, real publish dates, and slug-checked tags. It also hands
the Roundup's events block over for copying. Since the 25 Aug 2026 rewire, drafts
arrive in the full entry-page body order — date line, facts (extractor-prefilled
where the source page offers them), links row, description, Hosted by — plus
optional collection tags and the vendor flag. Since 10 Sep 2026 a quoted description
drafts as a plain blockquote with nothing under it — the credit line is retired.job-status-open, #job last.
The rewire landed and passed acceptance 21 Aug 2026 — tags are matched by slug, missing
ones are minted with their pretty names, and no hand-correcting is needed.Before you hit publish
.sh-pull on the one blockquote that's yours.#has-audio last, and a series tag as well.Settled by the build
The seven questions this page carried while the theme was being built, each answered from the templates that actually run — kept here so the answer is findable where the question used to be.
deep-dives (renamed from feature, redirects live). The Events directory is res-directory-events. Everything namespaced per the table above.<time datetime="YYYY-MM-DD"> in the body is the only mechanism; the excerpt is display only.#has-audio: the audio card at the top of the body is the storage, the media URL is Captivate's direct one, the excerpt is the summary line, and the tag goes last.<time datetime> and the events card are emitted by the tool, drafts tagged res-directory-events + #resource. No hand-steps.IT IS A MYSTERY filed under location, internal tags last. No hand-steps.