plugin onboarding · design proposal · 2026-08-24

Somebody else's page

wp-admin gives us a rectangle, and the top of that rectangle is a notice dumping ground. Everything on this page follows from taking that seriously. The brief from the call was "not overly playful, like tangible one, but more wordpress-y, but still tangible identifiable" — so the question is not how to decorate a settings form, it is which signals survive containment.

Two decisions from the same call make this a frame rather than a screen: the wizard is core and inherits the installed plugin's colour, and the consent step is skipped rather than pre-checked when the licence already carries consent — so the step list is resolved at runtime, not authored. §3 is about the consequence nobody named: a progress rail you cannot draw until the licence returns.

This is greenfield, and it replaces something worse. An environment audit found zero onboarding across every Tangible plugin — no activation hook, no wizard, no first-run state; a clean activation of Loops & Logic 4.2.4 writes no options at all. What does exist is a non-dismissible, site-wide notice notice-error when a licence key is missing, plus a fake "update available" row on the Plugins list. Both violate our own rule that licence UI lives in the plugin's Settings tab and never in an admin-wide banner. So the first job of §3's licence step is to earn the right to delete that notice — a nag that fires forever is the current design, and anything with an ending beats it.

accent is structural, never a button no webfont no restyled form controls 4px / 3px radii no shadow first 120px expendable
1 · the ground rules

Five things core owns, and we don't touch

From the design DNA brief's constraint map. These are not stylistic preferences — each one has a failure mode that only shows up for some users, which is the worst kind.

Core ownsThe failure if we take itWhat we do instead
The primary button #2271b1 An indigo CTA beside a core-blue button makes two competing primaries. surfaces.css already wrote the rule down: the second coloured thing always kills the first one's pull. Use .button-primary unstyled. Indigo is demoted to structure: grid, rules, sheet numbers, meter fill.
Link colour, and 8 admin colour schemes that recolour it per user A hard-coded link colour looks broken only for the user on Midnight or Ocean. You will never see it. Never set a colour on a. Inherit.
Form controls and their #2271b1 focus ring Fighting core specificity breaks focus visibility — an accessibility regression traded for a nicer border radius. Zero restyling. This is the hardest rule here and the one most likely to be broken for aesthetic reasons.
The notice zone at the top of .wrap Any designed hero gets yellow banners inserted into the middle of it, by plugins we don't control. Design the first ~120px as expendable. Stress-tested in §9.
The admin font stack A webfont means FOUT on a page the user opened because something needs doing. No webfont. Monospace is used for labels only, and every platform has one.
The interesting consequence: because our accent is structural rather than interactive, per-plugin theming cannot produce an unusable screen. A plugin whose brand is pale yellow gets pale yellow grid lines — quiet, and fine. Had the accent been the button colour, that same plugin would ship a contrast failure. The constraint that felt like a loss is what makes §7 safe.
1b · the ground question

Four ways to own a rectangle

The indigo hairline grid was doing the "this is our paper" job, and it is the wrong device here for two reasons. It is already spent — the DDD viewer wears it, and a signature used twice in different registers stops signalling either. And its identity came from owning the page: a blueprint field reads as structure across a full sheet and as decoration inside somebody else's 900px column. Perfect for a proprietary surface. Noisy here.

So: four candidates, same screen, all four dropping the grid. What stays constant in every one is what now has to carry the identity — the mono micro-label, the 1.5px ink rule, hairlines over shadows, 4px radii, and the copy voice. If none of these read as ours, the problem was never the grid.

1 · the rule — no ground at all

SearchSync

02

Where should search run?

You can change this later. Local indexing needs nothing else from you.

step 2 of 4

White panel on WP's grey — structurally identical to a .postbox. Everything ours is in weight: the 1.5px ink rule under the heading, the mono step count, the line-height. Maximum nativeness. The risk is real and worth naming: at a glance this may read as core with better typography rather than as Tangible at all.

2 · the ledger — identity from structure

SearchSync

02 Where should search run? 2 / 4
engine
indexes
Posts, pages, courses · 1,248 items
reindex
On publish, and nightly at 03:00
changeable
Yes, any time, in Settings

wp-admin is made of tables, so leaning in is more native than resisting. The fixed mono label column is the whole device — and it does something the others don't: it forces every step to state its consequences as facts, which suits a product whose copy voice is already "state the fact plainly". Weakness: a poor fit for steps that are genuinely a choice between three things rather than a set of values.

3 · letterhead — one band of colour, then white

SearchSync

SearchSync setup step 2 / 4
02

Where should search run?

You can change this later.

One coloured gesture per screen — a tinted band with a 1.5px accent rule under it — and plain white beneath. This is the one that solves per-plugin theming properly, because a single band can be any colour without becoming noise, where a grid in a colour you didn't choose always is.

4 · field note — swap the brand colour, not the ground

SearchSync

SearchSync setup step 02 / 04
02

Where should search run?

You can change this later. Local indexing needs nothing else from you.

White ground, and the structural colour moved from indigo to olive #507F06. This is the option that changes the palette rather than the layout: olive is already in the brand set, it has never carried a surface anywhere, and it is far enough from core's #2271b1 that it can never be mistaken for a control. One filled mark, olive rules, everything else neutral. Weakness: green in wp-admin carries a learned meaning — success, active, update available — so it may read as a status rather than as a brand.

cream is gone from all four, deliberately

The doubt was about cream as well as the grid, so every option above sits on white — including the panel header strips, which were #FBF7F0 and are now a neutral #F7F7F8. Worth being clear about what that costs: cream was the cheapest warm signal we had, it is native by construction as a tinted .postbox header, and without it none of the four is warm at all. Options 1–3 are now neutral surfaces distinguished only by weight and structure; option 4 buys warmth back through the palette instead of the ground.

That is a real fork, not a detail: either Tangible-in-wp-admin is warm and we need a warm device that isn't cream, or it is neutral and the identity is carried entirely by typography and rules. I lean neutral, because every warm ground fights #f0f0f1 and the fight is the thing that reads as foreign — but it is a brand call, not a technical one.

Recommendation: letterhead, with the band in an unspent colour. It earns it functionally rather than visually: the band is the only place colour appears, so it is the only device that can absorb an arbitrary plugin accent and stay quiet — the §7 requirement the grid fails. And the band's colour can say whose step you are on, Tangible's for the core licence and consent steps, the plugin's for its own. That teaches the difference between "setting up this plugin" and "setting up your Tangible account" without a sentence of explanation, and it dissolves a problem I had otherwise left unsolved. Pair it with option 4's point and the Tangible band is olive, not indigo.

Neither loser is wasted. The ledger survives as the interior pattern for any step that is a set of values rather than a choice — §6's done screen is already a ledger, and §5's payload table is one too. And the rule is the correct fallback if the band is one gesture too many: it is strictly less than letterhead, so retreating costs nothing but deleting a div.

Everything below §2 still wears the incumbent cream-and-grid ground. Left deliberately: those sections are about flow, consent and structure, and re-skinning them before a ground is chosen would mean doing it twice. Read them for what they argue, not for how they look — the surface is one .tgbl-ground rule away from whichever option wins.

what I know about the DDDash round, and what I don't

From the three artifacts I could read, that round explored four named themes with authored intent strings: Warm Signal (#6359D6 on #FDFAF8, 12px radii), WP Native (#2271b1 on #f0f0f1, 3–4px, display face deleted), Dark Console, and Blueprint (#1E6BB8 on #EEF1F4, cool not warm, faint grid). So indigo-on-cream and the grid are both spent, and a cool steel-grey ground was considered there too — which is why I have not proposed one here.

What I don't have is that round's rejected options or the reasoning. If there is a record — a doc, a thread, or more artifacts than the three I was given — point me at it and I will check these four against it before you spend review time. Olive and salmon are the two brand colours I can see no evidence were tried, which is why option 4 reaches for olive; if olive was already killed there, that is exactly the kind of thing I would rather learn now.

2 · the fork

Takeover or in-place?

The one real structural decision. Both are drawn below with identical content so the frame is the only variable.

A · the sheet — full-page, admin menu hidden
⌂ oakhill-learning.comhowdy, dana
SearchSync setup
03

Where should search run?

You can change this later. Local indexing needs nothing else from you.

step 3 of 5

sheet 03 / 05 · searchsync 2.1

The mechanism is already proven in-house. A dormant tangible-wizard-module from 2021 — zero consumers, dead backend, placeholder copy from another product — nonetheless got the plumbing right: activation transient, hidden dashboard page, full-page <!DOCTYPE> takeover, an opt-out filter, and guards for multisite and bulk activation. Worth reading for the guards alone; it also already had a licence step and a telemetry step, which means it anticipated this call's framing five years early.

The notice problem disappears — no .wrap, no notices. We own the viewport, so the contained grid may sit on the sheet's own ground. Costs: hiding the admin menu is a heavy move, and it must always carry a visible Exit to WordPress or it reads as a trap.

B · the panel — normal admin page, menu present
⌂ oakhill-learning.comhowdy, dana

SearchSync

Finish setup to start indexing. Resume

Setup 3 of 5
03

Where should search run?

You can change this later. Local indexing needs nothing else from you.

step 3 of 5

Never traps anyone, survives being abandoned halfway, and the menu keeps the plugin's other pages one click away. Costs: it inherits the notice zone, and it is unmistakably a settings page — less ceremony for a first run that genuinely is an occasion.

what four LMS plugins actually do

Hands-on teardown of LifterLMS, Tutor LMS and LearnPress, plus LearnDash from its shipped source: 4 of 4 take over the full page, hiding the admin menu, bar and footer. So the sheet is not a bold choice, it is the convention — and a plugin that doesn't take over on first activation is the odd one out.

They split on how, and it matters. LifterLMS and LearnDash keep a normal admin page and display:none the furniture — cheap, and nonces, capabilities and enqueueing all keep behaving. Tutor and LearnPress render a fully custom template with the chrome absent from the DOM: total control, at the price of re-implementing the plumbing. For a shell shared across plugins, take the CSS-hide route, and add LearnDash's blanket .notice { display:none } — otherwise the notice zone follows you into the takeover, which is exactly what LearnPress's activation screen shows.

One more piece of convention worth copying: the wizard page is registered and then removed from the menu, so it stays URL-addressable forever. That is what makes "resume setup" possible without a second page.

Recommendation: both, chosen by whether the user consented to be interrupted. Clicking Activate is an invitation — a fresh install gets the sheet, and the ceremony is welcome. An auto-update the user never asked for is not an invitation, and hijacking the whole screen there is precisely the "Tangible is trying to get me to do stuff" failure raised on the call. That case gets the panel, or §8's what's-new scroll. One interior, two frames, and the rule for picking is a sentence rather than a preference.
3 · the resolved manifest

A rail you can't draw yet

Because consent is skipped when the licence already carries it, the step list is a result, not a constant — and the licence step is what produces it. So the rail has two lives: before the lookup returns, and after. Most wizards fake this by hard-coding five steps and quietly no-op'ing one. That is the version that feels sneaky later.

the step I was missing, and what it's really for

All four LMS wizards open with a welcome screen that asks nothing — the plugin's name, one or two reassuring sentences, one button. I had skipped it as ceremony and gone straight to the licence. That was wrong twice over.

It is conventional, so its absence reads as abrupt. But more usefully: it is where the licence lookup hides. Fire the request as the welcome screen paints, and by the time the reader has finished two sentences and pressed the button, the step list is resolved and the rail can be drawn correctly the first time. The awkward pending licence state below stops being the normal case and becomes the honest fallback for when the network is slow or the key is bad. A convention I nearly dismissed turns out to be load-bearing for the one hard problem on this page.

fallback · the count is honestly unknown
Setup
01 Licence
Remaining steps pending licence
01

Connect this site

Your licence tells us which features to switch on, and what we already know about your account — so this decides what else we need to ask you.

Find it in your account, under Licences.

checking

No fake number. The rail says pending licence rather than claiming 1 of 5, because we do not yet know whether it is four or five. Saying the true thing costs one row.

after · and the skipped step stays visible
Setup 2 of 4
01 Licence creator · 3 sites left
·· Email & diagnostics not asked · on file
02 Search index
03 Connection
04 Done

You said yes to email and diagnostics when you bought, so we skipped asking again. Manage that in your account.

02

Where should search run?

You can change this later.

Five rows, four steps. The skipped one is drawn present and accounted for — greyed number, not asked · on file, and one line saying why with a link to change it in the account, not here.

This is the idea the page is really about. Gabriel's reason for skipping consent was that asking again "would just be an opportunity for them to unconsent" — which is true, and also the exact reasoning that produces software people distrust when they find out. Showing the skip resolves both: the step is visible but not actionable here. We are not offering a checkbox to un-tick, and we are not hiding that a decision was already made on their behalf. The manage link goes off-plugin, so the flow keeps its yes while the user keeps their agency.
4 · the step archetypes

Five kinds of step, and that's all

Julia described a plugin's own steps in one sentence on the call — pick an indexing method, then supply connection fields, then see whether it worked. Three archetypes fall out of that, and core adds two. Every plugin's "special sauce" has to be expressible as a sequence of these, or the frame is wrong.

ArchetypeOwnerJobShown
LicencecoreIdentify the account. Resolves the rest of the flow. Always first, never skippable, absent entirely on free builds.§3
ConsentcoreEmail and diagnostics, asked separately. Present only when not already on file.§5
ChoicepluginPick one of a small closed set. Radio cards.§2
CredentialspluginCore form controls, unstyled, in our panel. Ends in a test, not a save.below
Verified statepluginReport the result with a real number. Its own step because failure needs somewhere to live.below
credentials · core controls, our container
03

Connect to Algolia

We'll test the connection before saving anything.

Needs write access. The search-only key won't do.

step 3 of 5

Inputs are core's, untouched — including the blue focus ring, which is the thing most likely to get "improved". Ours is the mono label above each field, the paper, and the hairline. The primary action is Test connection, not Save: a credentials step that saves without testing just moves the failure somewhere less helpful.

verified state · both outcomes
04

Connected

OK Index oakhill_posts reachable · 1,248 items queued · first sync in about 4 minutes

initial index

424 of 1,248 · you can leave this page

the same step, failing

401 Algolia rejected the key. This is usually the search-only key rather than an admin key. Where to find the admin key

The meter is the one place a filled accent bar is allowed, because it is data, not a control. Failure states name the actual cause — the mono 401 and "usually the search-only key" — instead of "something went wrong". This is where the copy voice earns its keep.

5 · consent

Show the payload, not a policy link

Gabriel's frame was "people have to perceive a fair exchange of value", and he named the competitors to study precisely because they are good at the opposite. The single move that separates us from them costs nothing: print the actual values from this site instead of describing them behind a link. A reader who can see the four lines we would send does not need to trust us.

free build · forced unbiased choice, unbundled
02

Two optional things

Two questions, and no is a complete answer to both — the plugin works exactly the same either way. We ask rather than assume, so you do have to answer.

Send us diagnostics?

It tells us which PHP and WordPress versions to keep supporting. This is the whole payload, as it stands on this site right now:

siteoakhill-learning.com
php8.2.14
wordpress6.8.1
searchsync2.1.0

No post content, no user data, no visitor data. Once a week, to tangible.one.

Release notes by email?

What changed and what broke, roughly monthly, to dana@oakhill-learning.com. Separate from anything to do with your licence or your receipts — those arrive either way.

answer both to continue

This is the Wordfence pattern, and it is here on evidence. The teardown of six competitors found exactly one decent flow — a forced, unbiased, unbundled Yes/No that refuses to submit on a non-answer — shipping at 4M+ installs. So nobody has to choose between a decent consent flow and a viable business. Three properties are doing the work: the two options are the same size and the same weight, nothing is pre-selected, and Continue is disabled until both are answered. An unchecked box is compliant and quietly means no; this actually asks, which is both more honest and higher-yield.

The two asks are never bundled, because bundling is where the worst finding lands: WP Mail SMTP pre-fills the admin's email and subscribes it to their list on Save and Continue, with no checkbox at all — so a user who visibly declines telemetry is subscribed anyway. And note the destination is named: tangible.one. Awesome Motive route telemetry to unbranded throwaway domains — miusage.com, aiousage.com, wpmailsmtpusage.com — as house convention. If the payload is defensible, the domain can carry our name.

pro build · covered by terms, so stated rather than asked
02

One optional thing

diagnostics · on

siteoakhill-learning.com
php8.2.14
wordpress6.8.1
searchsync pro2.1.0

Gabriel wants version diagnostics default-on for pro, justified by purchase terms. Drawn honestly that is a statement with an off switch, not a pre-ticked box — a pre-ticked box implies a choice we have actually already made. Two open items: the terms don't say this yet, and nobody has decided whether Turn it off exists at all.

The four lines are the whole argument. MonsterInsights Pro sends the admin email, the site URL, the licence key and the entire settings blob — under an option named anonymous_data, with no constant or filter that can turn it off. Ours is four lines you can read on screen before you answer. That contrast is not a moral flourish, it is the reason we can afford to ask rather than assume: a payload small enough to print is a payload you don't have to hide.
on offering a coupon for consent — the memory was real, the attribution wasn't

Gabriel recalled LearnDash trading a coupon for an email. No such string exists in LearnDash's shipped wizard — its email ask is a 48-hour demo, not a discount. The coupon is LifterLMS, and it is a rail-level step literally named "Coupon":

"Help Improve LifterLMS & Get a Coupon … Click 'Allow' to and we'll send you a coupon immediately."

(The broken sentence ships verbatim.) It is genuinely opt-in — nothing is written unless you click Allow. But there is no email field: it sends the site's admin_email, harvested from WP settings and never shown on screen. So the thing being exchanged is not disclosed at the moment of exchange, which is the same failure as a policy link — and it is avoidable for free. If we ever offer an incentive, print the address we are about to use, the way §8 does.

One structural advantage worth naming, since it is the whole reason we can be both honest and efficient. The bad examples buy their opt-in rates with friction reduction — pre-ticked boxes, blocked exits, refusals that record nothing and re-fire forever. We get the same friction reduction from §3 instead: a licence key belongs to an account that may already have consented at checkout, so we skip the question rather than rig it. Same outcome, opposite ethics.

5b · consent before side effects

Say what you're about to do to their site

The best single thing found in the whole competitive sweep, and it is LearnDash's: before writing anything, its final step enumerates every side effect — pages it will create, content it will import, settings it will flip, plugins it will install — each individually toggleable. It is the same principle as §5's payload table pointed at the filesystem instead of the network: show the actual thing, not a description of it.

It should be a shell-level guarantee rather than one plugin's good manners. Core renders this step from what the plugin steps declared, which means no Tangible plugin can quietly create a page — the frame won't let it.

04

Before we change anything

Everything below is on by default and every line is optional. Nothing has been written yet.

3 of 4 selected

Two deliberate details. The primary button says Make these changes, not Finish — the label names the consequence. And the one item that touches the user's own theme is off by default, because the shell can reasonably presume consent for things it owns and never for things it doesn't. That distinction is the whole rule, and it is checkable in review.

6 · the last step

No confetti

05

SearchSync is running

Here's what changed on this site.

licenceCreator · 3 of 5 sites
indexAlgolia · oakhill_posts
indexed1,248 items
search page/search

worth doing next

Two settings we didn't ask about during setup: which post types to include, and whether to index drafts. Both are safe to leave alone.

A done step that says "You're all set!" wastes the one moment the user is definitely paying attention. State what changed, with real numbers, then name the two things we deliberately didn't ask — which doubles as an apology for the questions we did ask.

Where you land is where convention collapses, and it is the most revealing screen in any of these products. LifterLMS drops you into post-new.php?post_type=course — onboarding ends by starting the work. Tutor LMS, having just built you three courses, instead lands you on a ~7,900px marketing wall with six separate "Get Pro" buttons and no link to the courses. Both took the same five minutes of the user's attention; only one spent it on the user. Our primary action is Try a search for that reason.

7 · per-plugin theming

One frame, whatever colour

Gabriel: the wizard "should inherit from the plugin that you're installing." Below is the identical markup with only --tgbl-accent and --tgbl-grid overridden. Because the accent is structural, no value of it can break a control or fail contrast — the worst case is a grid you can barely see, which is also the best case.

Loops & Logic
02

Integrations

02 Pick integrations
SearchSync
02

Search index

02 Where should search run?
Tangible Blocks
02

Block library

02 Choose a starter set
the failure mode we get by default if we don't constrain this

LearnPress's wizard is what unconstrained plugin theming produces: a purple logo, an amber progress bar, a WordPress-blue button and 400-weight grey headings — three unrelated colour stories on one screen, none of them load-bearing. That is not carelessness, it is the predictable result of letting each surface bring its own palette. Hence the contract in §10: a plugin gets an accent, a logo and an illustration slot. Type comes from WP, the button comes from core, and everything structural comes from the shell.

What stays constant is what carries the identity: the warm paper, the hairline, the mono labels, the 1.5px ink rule, the flatness. A user who has set up two Tangible plugins should recognise the second one as ours despite the colour change, not because of it. That is the actual test of whether this design works, and it is testable — put two of these side by side in front of someone.
8 · the other first run

The LDX case: value first, ask last

The acquired cohort did not install anything — an update landed. Gabriel's sequence was to lead with what they got, reassure on price, and only then ask. Titus's version became the instruction: "a scroll where they can look at pretty pictures and pretty text and the new stuff they can do." So this is not a wizard: no rail, no step count, nothing gated, and the ask is at the bottom where it can be ignored.

⌂ oakhill-learning.com

LDX Design

Updated to 3.0. See what's new

ldx design 3.0 · maintained again

Working with modern LearnDash layouts, finally

Tangible now maintains LDX Design. Your licence, your price and your renewal date are unchanged — this is not that kind of acquisition.

01

Compatible with LearnDash 4.x layouts

The focus-mode and course-grid templates render correctly again. Nothing to reconfigure — existing settings carry over.

screenshot · focus mode
02

Settings that admit what they do

Forty-one options reorganised into six groups, each with the sentence we wish had been there. Nothing removed.

03

Updates arrive again

Two years of PHP 8.2 and 8.3 deprecation notices are gone. 28 fixes

one ask, and it is genuinely optional

We want to know what to fix next, and the people who tell us are the people on the list. Nothing changes if you skip this.

The email is pre-filled from the licence, not the ask — we already know it, so pretending to collect it would be theatre. The checkbox is unticked, and No thanks is a real button. Note the 1.5px ink rule doing structural work here: it is the only thing separating the gift from the ask, and it needs to be unmistakable so nobody feels the ask was smuggled in.

9 · stress tests

The conditions it actually ships into

A design that only works on a clean install does not work. Two tests below; the first is the one that kills most plugin screens.

test 1 · four notices from four other plugins

SearchSync

Wordfence: your licence expired 3 days ago.

WooCommerce: database update required. Run it

Black Friday: 60% off Elementor Pro. Claim

PHP 8.0 reaches end of life soon.

Setup 2 of 4
02

Where should search run?

You can change this later.

Survives because it never competed. There is no hero, no title block, nothing above our container that a notice can land inside. The bordered edge is doing the work the page used to do — it says this rectangle is one coherent thing, which is legible even with four banners stacked above it. This is also the argument against a designed page header: it would be the first casualty, on somebody else's site, invisibly to us.

test 2 · admin colour scheme changed (Midnight)
⌂ oakhill-learning.com

SearchSync

02

Two optional things

The buttons went red with the scheme and nothing else moved, because we never set a colour on a control or a link. Our indigo is nowhere near them — it is in the grid and the sheet number.

And this is handled by construction rather than by discipline: anywhere the design genuinely needs the interactive colour it reads var(--wp-admin-theme-color, #2271b1), which WordPress itself sets and every colour scheme consumes. It is one of only five real custom properties core exposes — and Tangible Fields' TUI build already bridges it the same way, which makes this the ADR-010 path rather than a new one.

10 · the extension contract

What core owns, what the plugin brings

Gabriel: "the stuff that's true of every plugin is what we deal with in the core. And then the rest has to be essentially extendable or hookable by the plugin to put in its special sauce." Sketched, not specified — the shape matters more than the names at this stage.

CorePlugin
FrameThe whole shell: sheet vs panel, rail, header strip, actions row, tokens, and which frame gets used for which trigger.Nothing. A plugin cannot restyle the frame — that is the point of having one.
ThemeThe token set and every non-accent value.Three values: --tgbl-accent, --tgbl-grid, a 19px mark. Nothing else is overridable.
StepsLicence (always first, resolves the flow) and Consent (present only if needed).Any number of Choice / Credentials / Verified-state steps, contributed through a filter and slotted after the core pair.
CopyEverything on the core steps, including the consent wording — this is the part with legal exposure and it must not be per-plugin.Its own steps' copy.
CompletionRecords that onboarding ran, at what version, and what was skipped.Declares what "done" means for it, so a half-configured plugin can re-offer the rest.
two shipping constraints the audit turned up

There are two incompatible framework generations — Loops & Logic Pro is still on the legacy plugin-framework while everything else moved to the namespaced one plus a split-out updater. A shared onboarding module has to load under both, or Pro is excluded from its own product's setup flow. And the existing settings.css is inlined with no handle, so it cannot be dequeued — new admin CSS lands on top of roughly 25 hardcoded hexes rather than replacing them. Scoping everything under .tgbl-admin is what makes that survivable, and it is now a requirement rather than good manners.

The one thing worth arguing about now, because it is expensive later: a plugin contributes steps but cannot reorder or remove the core pair. Licence stays first because it resolves the flow, and consent stays core because its wording carries the legal risk. If a plugin ever needs to ask something before the licence, this whole model is wrong and we should find that out this week rather than after three plugins ship against it.
11 · open questions

Ordered by cost to change later

Q1 · is the licence step always first? — most expensive

Everything in §3 rests on it. It also implies free builds have a different flow rather than a shorter one, since there is no key to resolve — so a free plugin's consent step cannot be skipped, ever, and its rail starts resolved. Worth confirming that free onboarding is in scope at all.

Q2 · does the skipped-step row survive review?

It deliberately re-introduces visibility of a decision Gabriel wanted invisible — his reason for skipping was to avoid offering an unconsent opportunity. My claim is that a visible-but-not-actionable row keeps the yes and the trust, but it is his call, and it is the kind of thing that looks like a rounding error until somebody blogs about it.

Q3 · does pro's diagnostics statement get an off switch?

Drawn with one. Also blocked on a real prerequisite nobody owns: the terms of service do not currently cover default-on collection, so §5's right-hand screen is not shippable until they do.

Q4 · sheet or panel for a fresh install, if we only build one?

§2 recommends both because the trigger differs. If that is too much for a first cut, the panel is the safer single build — it degrades to a normal settings page, works abandoned, and needs no menu-hiding. The sheet is the better experience for the case that matters most.

Q5 · does the mark belong in the header strip? — cheapest

A 19px plugin mark is drawn top-left of every frame. It may be the one piece of decoration that earns nothing, given the plugin's name is right next to it and the admin menu already says where you are.

Painted 4:46 PM EST all artifacts