Verifying access…
← Back to simulator
McGrinsey · Sim · Wiki · Reference

Make models, not spreadsheets.

The Sim turns a tab-zoo of Excel scenarios into one chart, three layers of inputs, and a math layer you can read — so you argue about assumptions, not formulas.

How to read the chart.

One picture, three layers, two colours of truth. The chart paints a cost mountain with revenue riding on top. The gap between them is your business.

Layout, focus & fullscreen.

The chart is the hero. There are two ways to work with it, and they coexist: the normal webpage (scroll, everything inline) and a true fullscreen immersive mode (a trading-terminal cockpit). Use whichever fits the moment — switching between them never changes your model or loses anything.

Fullscreen — the immersive cockpit.

For a distraction-free, trading-dashboard experience, click ⛶ Fullscreen in the top bar (or press Shift + F). The browser goes true fullscreen — no webpage chrome, no scrolling — and the chart fills the entire screen like Koyfin or Kraken. Every control is still there, just tucked into edge drawers you slide in when you need them.

Save state — one clear signal.

A single save-state indicator sits in the top bar — in both the normal webpage and fullscreen (it's the same component), so you never have to guess whether a change took. It reflects the whole simulation's persistence state, not one panel:

The per-row Apply buttons and the small in-panel “all saved / unsaved” footers still tell you which row needs attention; the top-bar signal is the one-glance answer for the whole model.

Overlay lines — measure anything.

The defaults — cost mountain, revenue, P/L gap, net-profit reference — tell the headline story. To inspect anything else, overlay it as a thin line.

Initiatives on the chart.

Initiative impact is visible directly on the chart — no “did my CTR boost actually move anything?” guesswork.

Impact chains — honest by design.

Every initiative carries an auto-generated impact chain: the direct change to the target field, then the confident causal consequences, each marked with a direction arrow ( up / down). Direction is inferred from operator and value — × 0.5 or + negative is a decrease, × 1.5 or + positive is an increase, a bare set shows a neutral .

The operator verb describes only what the initiative does to the target (halves CPC, sets CPC to €0.50). Downstream nodes carry a direction arrow and a metric name — never the op verb. We deliberately don't write “Multiplies SPEND”: halving CPC does not halve spend, and the operator never propagates downstream.

Chains are anchor-aware and stay short (≤ 3 nodes). Honest examples:

Arrows tint green when the change moves toward profit, red when away, and grey when unsure. The tool shows less when the downstream is uncertain: a field with no confident causal story renders just the target node and stops — no invented downstream. Even “CTR ↑ → CPC ↓ → CAC ↓” stops at CAC, never promising orders — because you can lift CTR with clickbait that never converts. Conservative best-case, always.

Inputs you control.

Three layers, built bottom-up. Products are the atom — what you sell. Channels feed them traffic. Curves carry cost and revenue across time. Everything on the chart is a consequence of these.

Products — what you sell.

Each product row has an anchor mode. CRR (cost-revenue ratio — media spend as a share of revenue) is always your input; it's a media-buying judgement, not derivable. The anchor picks which one of orders, media_budget, profit_target is the number you type; the other two derive from AOV, margin %, and CRR %.

ORDERS

“I plan to sell X units/month at €Y AOV. What media spend does that take at Z% CRR?”

BUDGET

“I have €X/month for media. How many orders does that buy at Z% CRR?”

PROFIT

“I want €X profit/month. What spend + orders does that imply?”

CHANNELS

“Orders + media come from connected channels, not a CRR assumption.” (See connector.)

Every product also carries word-of-mouth mechanics — recommend %, friend purchase %, friend AOV ratio %, lag months, decay %. The viral coefficient K = recommend% × friend_purchase% rides on top of direct acquisition and shows live next to the row, with a steady-state multiplier chip and an · UNSTABLE warning when the math blows up. Full mechanics under WOM.

Lifecycle — start & (optional) end month.

Each product has a lifecycle window: a start month (when sales begin) and an optional end month (when they stop). By default products run forever — set a start, leave the end at . The end is for limited availability: a cohort course, a seasonal SKU. Open the Timing sub-section on any row to edit; a compact hint like ● M+3 → ∞ or ● M+3 → M+12 shows on the row whenever the lifecycle is non-default, so time-boxed products read at a glance.

Both fields use the same offset-from-TODAY M+N convention as initiatives. M+0 = the first projection month (now); M+6 = six months out; a negative offset (M-3) means the product was already selling three months before TODAY. Internally these are absolute timeline months, so changing history_months later never moves a product's real launch date.

While a product is inactive (before its start or after its end) it contributes zero orders, MRR, media spend, and gross profit for that month. The revenue and media-cost curves therefore step as products switch on and off — a course starting M+3 steps revenue up at M+3; one ending M+12 steps it down at M+13. Validation keeps end ≥ start (an end before the start collapses to a single month).

WOM tail-off. Because the cascade is driven by direct orders, WOM is naturally zero before start + lag. After the end month direct orders stop, but the last active cohort still rings out — final customers keep referring friends for a few months, tapering by the lag/decay cycle. That trailing referral tail is real and intentional.

Price schedule — change the price over time.

A product's price (its AOV) can change over time on a schedule. Open the Price schedule sub-section on any row and add one or more segments: each runs From M+X To M+Y — or toggle to run indefinitely — at a set price. A segment overrides the base AOV for every month it covers; in any month no segment covers, the base price applies (so an empty schedule = base price everywhere, exactly as before). Both From and To use the same offset-from-TODAY M+N convention as the lifecycle and initiatives.

When two segments overlap, the one with the later start wins for the overlapping months (last-defined wins). The effective price drives everything for that month — MRR, the media spend implied by CRR, the budget- and profit-anchor maths, word-of-mouth revenue, and channel-driven revenue — so the revenue curve steps at each price change. A compact hint like ● €37 → €49 @M+6 → €59 @M+12 shows on the row whenever a schedule exists.

Worked example. Base price €37; add one segment €49 from M+6, indefinite. Months M+0M+5 price at €37; from M+6 onward they price at €49. With a constant 100 orders/month, MRR is €3,700/mo through M+5 and steps up to €4,900/mo at M+6. A temporary promo works the same way: €29 from M+3 to M+5 dips the price (and revenue) for those three months, then it returns to the base €37 at M+6. A price segment that falls entirely outside the product's active lifecycle window is moot — an inactive month sells nothing regardless of price.

Channels — how you generate orders.

Each channel is one paid acquisition source with its own funnel and anchor. Pick a model first:

Then pick the anchor metric — the number you can measure, not the one you wish for: SPEND, IMPRESSIONS, CLICKS, LEADS (b2b only), or ORDERS. The funnel solves bidirectionally from there: it walks backward from the anchor to impressions, then forward to fill any remaining step.

Cost rates — CPM, CPC, CPL (b2b only), CPO — fill whichever you have data for. When the anchor is spend, the most upstream non-zero rate drives the funnel (preference CPM > CPC > CPL > CPO). When the anchor is a count, spend is computed forward using the same preference. Every active channel resolves to per-month impressions / clicks / leads / orders / spend / CAC, and its spend joins the cost stack as its own band.

LP CR % is informational on the row — in b2c it usually mirrors click_to_order, in b2b click_to_lead. It documents how a landing-page experiment moved but doesn't itself drive the funnel.

A channel can fund a specific product. The classic case: you sell Video Course 1 and Video Course 2, and your Meta Ads cost and performance differ per course. Model that as two channels — Meta Ads VC1 and Meta Ads VC2 — each wired to its own product.

Two steps to wire them:

In CHANNELS mode the orders / budget / profit cells go read-only (channel-driven), the Media CRR field disappears (it's inert — media comes from the channels), and a summary strip shows N channels connected · ~X orders/mo · €Y media/mo. AOV, margin %, WOM, and the lifecycle window stay editable — they apply no matter where the orders come from. Select CHANNELS with no channel pointing at the product and the row reminds you to wire one.

Anti-double-count rule. Channel spend is always in the cost stack (every channel, linked or not). A CHANNELS-anchored product takes its media from those channels, so it adds no CRR media of its own — otherwise the same euros would count twice. Products on the other three anchor modes still self-derive media from CRR. Net: total media = (sum of all channel spend) + (CRR media for non-CHANNELS products only).

Lifecycle gates everything. A CHANNELS product that starts M+6 stays at zero orders and zero media until M+6 even if its channels spend earlier — the product simply isn't selling yet. The channels are the magnitude during the active window; the lifecycle is the gate.

For now the model is one channel → one product (a product can have several channels; a channel funds at most one product). Product clustering / categories for large catalogues is on the roadmap.

Cost & revenue curves — time-shape.

Three curves are seeded automatically: agency cost (orange, flat), media cost (violet, derived from product CRR and/or summed channel spend), revenue (green, derived from products). Add your own custom curves on top.

Growth models:

Each row has its own Apply button + dirty-state pill — edit freely; values persist only on Apply. Horizon, time-unit, history-months, and currency sit in the panel header with their own Apply that re-fits the whole sim. Resizing the horizon or history re-computes parametric curves at the new length and re-derives revenue + media-cost from products; history values are preserved where the index still fits, new slots default to 0.

Historic data — actuals before TODAY.

Set history-months > 0 in the Curves panel header and a dedicated Historic Data panel appears above the curves. It's a matrix: one row per metric, one column per past month (oldest M-N left → newest M-1 right), a sticky row-total column, and a footer of column totals + grand total. Type past actuals into the cells; saves debounce 600 ms.

This is also where you tell the chart “we were already profitable since M-3”. Populate the revenue + cost rows and the FIRST PROFIT chip rewrites itself to PROFIT SINCE M-N.

Overlays — what changes over time.

Two layers ride on top of the base model. Initiatives are open-loop changes you toggle on and off. WOM is a closed-loop feedback layer where past orders compound future ones. (A third overlay — chart overlay lines — is measurement only; see above.)

Initiatives — what if we did X starting M+N.

An initiative is a typed change to one field on one entity for one window, with a cost. Five inputs and a switch:

Composition. Multiple initiatives on the same field apply in sort_order ascending — each op acts on the running value as it's encountered. A set overrides whatever came before it; × and + then chain on the result. So set 3 followed (higher sort_order) by × 1.2 resolves to 3.6 — but flip the order and the set 3 wins outright. Order is the lever; initiatives targeting different fields never interact.

WOM — word-of-mouth, time-varying.

Paid acquisition has CAC. Recommendations are free. WOM closes the loop: orders this month produce friend-orders next month, which produce friend-of-friend orders the month after.

Each product carries five WOM inputs:

Time-varying. If an initiative targets a WOM field, K changes from t_start onward. Orders before the window cascade with the original K; orders inside cascade with the new K (each cohort remembers the K at the moment of its original purchase). WOM has no media cost — friend buys are free acquisition, so the media-cost curve never charges for them.

Stability. The cascade converges when K × (1 − decay/100) < 1. Above that it explodes; the UI flags the row red (· UNSTABLE) and totals fall back to direct-only. Real businesses don't have K ≥ 1 — if your inputs say they do, the inputs are too optimistic.

Math reference.

One place, all the formulas. Variables: A = AOV, m = margin %, c = CRR %, K = viral coefficient, d = decay fraction. All math runs server-side in resolveScenarioPnL() and friends — the client mirrors it for live feedback, but persisted values come from the server.

Product resolved values, per anchor mode.

// orders anchor — you type o
media_spend = o * A * c / 100
mrr         = o * A

// media_budget anchor — you type b
unit_media_cost = A * c / 100
orders          = b / unit_media_cost      (if > 0 else 0)
mrr             = orders * A
media_spend     = b

// profit_target anchor — you type t
net_margin_per_order = A * (m - c) / 100
orders               = t / net_margin_per_order   (if > 0 else Unreachable)
mrr                  = orders * A
media_spend          = orders * A * c / 100

// channels anchor — orders + media come from connected channels
orders      = Σ active connected channels[t].orders
media_spend = Σ active connected channels[t].spend     // own CRR is IGNORED
mrr         = orders * A

// always (every mode)
gross_profit = mrr * m / 100
net_profit   = gross_profit - media_spend
// + a lifecycle gate: orders = mrr = media_spend = gross_profit = 0
//   unless  t >= start_month AND (end_month == null OR t <= end_month)

Unreachable fires in profit_target mode when m ≤ c — no number of orders hits the goal, because each order destroys more margin than it earns.

Channel funnel chains.

// b2c
clicks = impressions * (CTR/100)
orders = clicks      * (click_to_order/100)

// b2b
clicks = impressions * (CTR/100)
leads  = clicks      * (click_to_lead/100)
orders = leads       * (lead_to_order/100)

// the funnel solves bidirectionally: walk BACKWARD from the anchor metric
// to impressions, then FORWARD to fill remaining steps. (back-step uses
// division: e.g. clicks = orders / (click_to_order/100).)

// spend
spend = anchor_value                          // when anchor = spend
// otherwise, derive from the most upstream non-zero rate, preference order:
//   CPM > CPC > CPL(b2b) > CPO
spend = impressions/1000 * CPM   // or clicks*CPC, leads*CPL, orders*CPO

// always
CAC = spend / orders                          // when orders > 0

Cost stacking + anti-double-count.

total_cost[t] = Σ cost-kind curves[t]          // agency + media + custom
              + Σ active channels[t].spend       // every channel, linked or not
              + Σ active initiatives[t] cost     // oneshot@t_start + monthly

// ANTI-DOUBLE-COUNT: a CHANNELS-anchored product's media IS its channels'
// spend, already in the channel sum above. So the derived media-cost curve
// EXCLUDES channels-anchored products — they add no CRR media. Result:
net_media = (Σ all channel spend) + (CRR media for non-channels products only)

Profit + first-profit.

revenue[t]    = (Σ revenue-kind curves[t]) * revenue_multiplier   // global, after sums
total_cost[t] = total_cost[t]                  * cost_multiplier      // global, after sums
net_profit[t] = revenue[t] - total_cost[t]
first_profit_month = first t where net_profit[t] ≥ 0
                     AND (revenue[t] > 0 OR total_cost[t] > 0)   // skips empty (0,0) months
// PnL series length = history_months + horizon_months  (t = 0 .. length-1)

WOM cascade + steady state.

K           = (recommend_pct/100) * (friend_purchase_pct/100)
Kd          = K * (1 - decay_pct/100)
steady_mult = K / (1 - Kd)            // only when Kd < 1; total WOM as a
                                      //   multiple of the direct cohort

wom_orders[t]  = Σ over generations k = 1, 2, 3, …:
                   direct_orders[t - k*lag] * K^k * (1 - decay/100)^(k-1)
wom_revenue[t] = wom_orders[t] * A * (friend_AOV_ratio_pct/100)

// safeguards
//  - terminate when the cohort weight < 1e-4 OR k > 60
//  - lag = 0 treated as 1 (no instant cascade)
//  - STABILITY: Kd ≥ 1 → unstable; UI flags, totals fall back to direct-only
//  - time-varying: each source month's own K/lag/decay drives its cohorts

Initiative effect ordering.

// active initiatives are applied to a per-t copy of the target field in
// sort_order ASCENDING (then id). Each op acts on the RUNNING value:
//   set        field = value          // overrides whatever came before
//   multiply   field = field * value
//   add        field = field + value
// → composition is order-driven: a `set` later in the order wins outright;
//   `×` / `+` chain on the running value. Different fields never interact.
// global multipliers apply LAST, on the fully-summed revenue / total_cost.

Worked examples.

Nine scenarios, each isolating one mechanic. Numbers are pure model math, verified against the resolver code — no rounding shortcuts.

1. Pure direct sales.

1 product · orders anchor · no channels · no WOM · no initiatives

Video course. AOV = €37, margin = 100% (digital, no COGS), CRR = 30%, orders = 400/mo.

2. Media-budget anchor.

1 product · media_budget anchor

Same course. Flip the anchor to media_budget and type €5,000/mo at CRR = 30%, AOV = €37.

3. B2C funnel channel.

1 channel · b2c · spend anchor · CPM drives

Google Ads campaign, spend = €5,000/mo, CPM = €30, CTR = 2%, click→order = 1.5%.

4. B2B funnel channel.

1 channel · b2b · spend anchor · CPC drives

LinkedIn Lead Gen, spend = €4,000/mo, CPC = €2, click→lead = 5%, lead→order = 20%. (No CPM set, so CPC drives the funnel.)

5. Channel → product connector.

channels anchor · Meta Ads VC2 → Video Course 2 · starts M+6

Product Video Course 2: anchor CHANNELS, AOV = €49, margin = 80%, starts M+6, runs forever. Channel Meta Ads VC2: drives product = Video Course 2, b2c, anchor SPEND €3,000/mo, CPM = €30, CTR = 2%, click→order = 1.5%.

The channel resolves:

Video Course 2 inherits exactly those 30 orders/mo + €3,000 media — but only from M+6 onward (its lifecycle start; before M+6 it's zero even though the channel spends). Revenue = 30 × €49 = €1,470/mo; gross profit = 1,470 × 0.80 = €1,176. The cost stack shows the €3,000 once — from the channel band — never doubled by a CRR cut on the product.

6. Initiative with timing + its impact chain.

CTR boost on Google Ads · FROM M+3

Same Google Ads channel as example 3 (~50 orders/mo at CTR 2%). Add an initiative:

From M+3 onward CTR jumps 2% → 3%. Impressions stay anchored to spend (CPM math unchanged), but clicks rise 50% to 5,000 and orders rise 50% to 75/mo. Channel spend stays €5k/mo (still spend-anchored); the initiative band adds €2k oneshot at M+3 + €500/mo thereafter.

Its honest impact chain: × / set CTR ↑ → CPC ↓ → CAC ↓. The chain stops at CAC, not orders — lifting CTR with weak creative could fail to convert, so we don't promise the order uplift in the chain even though this clean example does deliver it.

7. WOM steady state.

Premium Plan · meaningful K

Premium Plan, 50 direct orders/mo, AOV = €199. WOM: recommend 40%, friend purchase 60%, friend AOV ratio 100%, lag 1 mo, decay 0%.

8. WOM-targeting initiative.

Launch referral program at M+3 · time-varying K

Same Premium Plan, but baseline WOM is weaker: recommend 10%, friend purchase 60%K_baseline = 0.06. Then launch a referral program:

From M+3 onward recommend% snaps 10 → 40, so K = 0.40 × 0.60 = 0.24. Orders before M+3 still cascade with the original K = 0.06 (steady_mult ≈ 0.064); orders in the window cascade with the new K = 0.24 (steady_mult ≈ 0.316). The WOM uplift ramps in over the lag horizon and adds roughly +13 extra orders/mo at the new steady state. Friend orders cost zero media — blended CAC drops.

9. Historic actuals validating a projection.

history-months = 6 · Meta Ads · spend + CTR + CPC actuals

You ran Meta Ads for the last 6 months and want the chart to show what really happened, then continue from your forward assumptions. Set history-months = 6, open the Historic Data panel, and on the Meta Ads channel add Spend, CTR %, and CPC rows. Paste the six monthly actuals into each.

For each past month the model uses your actuals verbatim and derives the rest:

Concretely: a month with spend €3,000, CPC €1.50, CTR 1.8%2,000 clicks, ~111,111 impressions. The history side of the chart now plots your real funnel; the projection side continues from your forward formula. If projected CTR / CPC drift from what actually happened, that's your cue to retune. Metrics you didn't enter (e.g. impressions, if you only had spend + CPC) are filled by derivation; what can't be derived stays blank — never fabricated.

Tips & failure modes.

Conventions.

Roadmap.

✓ shipped · · planned.

Cost mountain + brutal P/L zones — stacked bands, green/red gap, €0 baseline, first-profit chip, net-profit reference line
History vs Projection split — TODAY divider, M-N / M+N axis labels, history tint, smart first-profit chip
Per-product anchor modes — orders / media_budget / profit_target with live derived values + per-product Media CRR
Channels with multi-anchor funnel — spend / impressions / clicks / leads / orders × b2c / b2b, CPM / CPC / CPL / CPO, blended CAC, per-channel cost band
Initiatives — target / op / value / timing / cost, per-row Apply, chart cost-band per initiative, aggregate footer
WOM module — per-product viral coefficient, lag + decay, steady-state multiplier, stability detection, WOM share badge
Time-varying K — initiatives targeting WOM fields shift the cascade from t_start onward
Curves panel — flat surface, per-row Apply, growth models (flat / linear / exponential / derived)
Unified Historic Data panel — matrix for past actuals, sticky labels + totals, spreadsheet paste, derived rows read-only (Phase 7)
Chart overlays + smart multi-axis — measure any whitelisted metric as a thin line; € / % / # axes pop in on demand (Phase 8)
Initiative chart markers + side rail + impact chain — pins per window, Kraken-style rail with toggles + compact chain, ▸ impact chevron (Phase 9)
Honest direction-aware impact chains — direct target change + confident causal consequences with / arrows, op verb on the target only, anchor-aware CPC/CPM, target-only fallback when uncertain (Phase 10)
Unified international number format — period decimal, comma thousands, lenient paste parsing, end to end (Phase 11)
Product lifecycle — per-product start + optional end month (M+N), inactive months contribute zero so revenue / media curves step, WOM tail-off after end, runs forever by default (Phase 12)
Channel ↔ product connector — “Drives product” link + a fourth CHANNELS anchor mode; anti-double-count keeps channel-anchored media off the CRR curve (Phase 13)
Historic funnel metrics per channel — historic CTR / CPC / CPM / clicks / impressions / orders (+ leads / CPL on b2b), missing metrics derived where possible, blank otherwise, never fabricated (Phase 14)
Chart-hero layout + collapsible panels + focus mode — the chart grows as panels collapse to slim summary bars; the rail collapses to a spine; Focus (F) hides everything but the curve; layout persists across reloads (Phase 15)
True fullscreen immersive mode — browser Fullscreen API; the chart fills the screen as a trading-terminal cockpit, every control tucked into edge drawers slid in from a left icon-rail (Shift+F, Esc to exit); coexists with the normal webpage, lossless both ways (Phase 16)
Honest curves — no invented values — monotone-cubic interpolation so the line never overshoots between two real points; every-month gridlines (Phase 17)
Info-ⓘ tooltips on every field — a tiny ⓘ next to every input / header / chip / toggle; hover or focus for a plain-language explanation + a deeplink back into this wiki (Phase 18)
Fullscreen drawers render content + wider drawers + open/close sounds — the immersive edge-drawers reliably populate, are wide enough to work in, and play a subtle window open/close flourish (Phase 19 + 20)
Fullscreen save path + global save-state indicator — one always-visible Saved / Saving / Unsaved / Error signal in both top bars (so saves are visible in fullscreen too); “Saved” means persisted and applied to the chart; portaled colour/delete dialogs no longer break fullscreen (Phase 21)
HISTORY / FUTURE / BOTH view toggle — a segmented control in the chart header clamps the visible x-window to the past, the future, or all of it, with the y-axis auto-fitting the visible data; pure view window (no data filtered), persisted across reloads, identical in fullscreen (Phase 22)
Scheduled product price changes — per-product price (AOV) schedule of From M+X → To M+Y (or ∞ indefinite) segments that override the base price for the covered months; later-starting segment wins on overlap; revenue steps at each change and threads through MRR / CRR media / budget + profit anchors / WOM / channel revenue (Phase 23)
Auth-gated wiki — mirrors the /sim/ auth, redirects to admin on a missing token; this very page
Multi-tenant scoping — master sees all, client/viewer locked to their client_id
· Scenario compare — two sims side by side, diff overlay on the chart, A/B KPI strip
· CSV / Excel export of the resolved time-series
· Public read-only share link for prospects + lead-gen scenarios
· Product clustering / categories — group many SKUs for e-commerce catalogues
· Per-initiative ramp curve — gradual ramp over N months instead of an instant set / × / + at t_start
· Manual per-month curve editor UI — the data model + API already support manual curves; the editor isn't built yet
· Pin clustering for > 5 initiatives — group dense markers so the chart top stays legible

Changelog.

Last 25 commits touching sim files. Baked at deploy.

(pending) · 2026-05-20 · feat(sim): scheduled product price changes over time (Phase 23)
(pending) · 2026-05-20 · feat(sim): history/future/both chart view toggle (Phase 22)
(pending) · 2026-05-20 · fix(sim): fullscreen save path + global save-state indicator (Phase 21)
a515678 · 2026-05-20 · feat(sim): wider fullscreen drawers + curves header wrap fix + open/close sounds (Phase 20)
4c18c9d · 2026-05-20 · fix(sim): fullscreen drawers render content (Phase 19)
dfea4d6 · 2026-05-20 · feat(sim): info tooltips on every field + wiki deeplinks (Phase 18)
ec666b9 · 2026-05-20 · fix(sim): no-overshoot interpolation + every-month gridlines (Phase 17)
5e680a6 · 2026-05-20 · feat(sim): true fullscreen immersive mode with edge-drawer controls (Phase 16)
9cc744e · 2026-05-20 · feat(sim): chart-hero layout + collapsible panels + focus mode (Phase 15)
62560f0 · 2026-05-20 · feat(sim): historic funnel metrics per channel (Phase 14)
70dab82 · 2026-05-20 · feat(sim): channel↔product connector + channels anchor mode (Phase 13)
b2ff8ae · 2026-05-20 · feat(sim): product lifecycle (start/end month) (Phase 12)
b973f6d · 2026-05-20 · fix(sim): unify all number formatting to international (period decimal, comma thousands) (Phase 11)
5b4071b · 2026-05-20 · fix(sim): honest direction-aware impact chains (Phase 10)
1f713e6 · 2026-05-19 · feat(sim): initiative chart markers + side rail + impact-chain explainer (Phase 9)
f743f0a · 2026-05-19 · feat(sim): chart overlays + smart multi-axis (Phase 8)
527bd62 · 2026-05-19 · feat(sim): unified historic data table (Phase 7)
9bd5ca9 · 2026-05-19 · docs(sim): comprehensive wiki overhaul (Phase 6)
e54fa3e · 2026-05-19 · polish(sim): full English UI + extended initiative target fields (Phase 5b)
8fffe9a · 2026-05-19 · feat(sim): WOM module with viral coefficient per product (Phase 5)
c7a1ee5 · 2026-05-19 · feat(sim): initiatives with target/op/timing/cost (Phase 3)
e700aa1 · 2026-05-19 · feat(sim): acquisition channels with multi-anchor funnel (Phase 2)
608b9d9 · 2026-05-19 · feat(sim): history vs projection split with TODAY divider
004d204 · 2026-05-19 · feat(sim): stack cost curves + brutal P/L gap between revenue and cost-stack-top
6c8a80a · 2026-05-19 · feat(sim): brutal profit/loss zones + flatten Advanced into defaults under chart
7275357 · 2026-05-19 · feat(sim): per-product anchor-mode switch (orders / media-budget / profit-target) + dev wiki
93a4386 · 2026-05-19 · feat(sim): per-row Apply button in Advanced curves editor
7ff774e · 2026-05-19 · feat(sim): derive media-cost from product-level Media CRR %
d1a8976 · 2026-05-19 · fix(sim): force [hidden] attribute to win over .login-gate display:flex
5eba42b · 2026-05-19 · fix(sim): bust client cache with ?v= on imports + script src
811b18d · 2026-05-19 · fix(sim): preserve admin token when /sim/ auth check fails
4431699 · 2026-05-19 · fix(sim): never block UI on auth — render empty state for anon visitors