diff --git a/app/Domain/Reports/Templates/partials/stakeholder/deck.blade.php b/app/Domain/Reports/Templates/partials/stakeholder/deck.blade.php
index 0127a9c427..fd35c7fe9c 100644
--- a/app/Domain/Reports/Templates/partials/stakeholder/deck.blade.php
+++ b/app/Domain/Reports/Templates/partials/stakeholder/deck.blade.php
@@ -375,7 +375,7 @@ class="rd-picker-opt @if ($period->preset === ReportPeriod::PRESET_NEXT_QUARTER)
{{-- ═══ Page 2 — Logic Model read-out ═════════════════ --}}
- @include('reports::partials.stakeholder.page-lm', compact('logicModel', 'hasLM', 'report'))
+ @include('reports::partials.stakeholder.page-lm', compact('logicModel', 'hasLM', 'report', 'programRows'))
{{-- ═══ Page 3 — Resources & Coverage ═════════════════ --}}
diff --git a/app/Domain/Reports/Templates/partials/stakeholder/page-lm.blade.php b/app/Domain/Reports/Templates/partials/stakeholder/page-lm.blade.php
index dd31ab0af0..33923c7579 100644
--- a/app/Domain/Reports/Templates/partials/stakeholder/page-lm.blade.php
+++ b/app/Domain/Reports/Templates/partials/stakeholder/page-lm.blade.php
@@ -143,8 +143,88 @@
.rd-scope .p2-drift b{color:var(--rd-text-1);font-weight:600;}
-@if (! $hasLM)
- {{ __('stakeholder.lm.no_canvas') }}
+@php
+ // Empty-state trigger is keyed on ITEM COUNT, not just board existence.
+ // A blank Logic Model board (0 items) makes $hasLM true but leaves the
+ // read-out hollow; the reverse flow itself creates a board on start, so
+ // gating only on board-existence would strand users in an empty skeleton.
+ // Treat "no board" and "board with no items" identically — both land on
+ // the populate-from-your-work empty-state below.
+ $lmStages = $hasLM ? ($logicModel['coverageMatrix']['stages'] ?? []) : [];
+ $lmHasContent = false;
+ foreach ($lmStages as $lmStage) {
+ if (count($lmStage['items'] ?? []) > 0) {
+ $lmHasContent = true;
+ break;
+ }
+ }
+
+ // Existing linked work in this strategy, for the empty-state's "we found
+ // your work" line. programRows carry type + projectCount; program rows
+ // count as programs, and projectCount sums to total leaf projects (direct
+ // + under programs). Empty at program scope, so the line self-hides there.
+ $lmProgramCount = 0;
+ $lmProjectCount = 0;
+ foreach ($programRows ?? [] as $lmRow) {
+ if (($lmRow['type'] ?? '') === 'program') {
+ $lmProgramCount++;
+ }
+ $lmProjectCount += (int) ($lmRow['projectCount'] ?? 0);
+ }
+ // Bold the counts so the totals read as totals. Every piece is server-side
+ // (ints + translated nouns, both e()-escaped), so the {!! !!} render below
+ // carries no user input.
+ $lmFoundParts = [];
+ if ($lmProgramCount > 0) {
+ $lmFoundParts[] = ''.$lmProgramCount.' '.e(__($lmProgramCount === 1 ? 'stakeholder.lm.found_program' : 'stakeholder.lm.found_programs'));
+ }
+ if ($lmProjectCount > 0) {
+ $lmFoundParts[] = ''.$lmProjectCount.' '.e(__($lmProjectCount === 1 ? 'stakeholder.lm.found_project' : 'stakeholder.lm.found_projects'));
+ }
+ $lmFoundStr = implode('·', $lmFoundParts);
+@endphp
+
+@if (! $lmHasContent)
+
+
+
+
+
+
{{ __('stakeholder.lm.empty_title') }}
+
{{ __('stakeholder.lm.empty_body') }}
+ @if (($scope ?? '') === 'strategy')
+ @if ($lmFoundStr !== '')
+
+
+ {!! sprintf(e(__('stakeholder.lm.empty_found')), $lmFoundStr) !!}
+
+ @endif
+
+ {{ __('stakeholder.lm.empty_cta') }}
+
+
{{ __('stakeholder.lm.empty_hint') }}
+ @endif
+
+
+
@else
@php
$stages = $logicModel['coverageMatrix']['stages'] ?? [];
diff --git a/app/Language/en-US.ini b/app/Language/en-US.ini
index 0cd68cd6e9..2e89ad3185 100644
--- a/app/Language/en-US.ini
+++ b/app/Language/en-US.ini
@@ -3001,7 +3001,15 @@ stakeholder.kpi.hours_logged = "Hours logged"
stakeholder.kpi.this_period = "this period"
stakeholder.overview.coming_title = "Peak this period · Needs attention · ToC narrative · Theory-health strip"
stakeholder.overview.coming_hint = "The recommend-and-override hero, execution-lens needs-attention block, Theory-of-Change sentence, and theory-health strip land next."
-stakeholder.lm.no_canvas = "No Logic Model canvas authored yet. Build one on the Board to see it read out here."
+stakeholder.lm.empty_title = "Build your Logic Model"
+stakeholder.lm.empty_body = "A Logic Model connects your programs, goals, and milestones into one story — what you do, what changes, and why it matters. It powers this page and the coverage read-out."
+stakeholder.lm.empty_cta = "Build a Logic Model"
+stakeholder.lm.empty_hint = "We'll scan the work already in this strategy and suggest what maps to each stage — you pick what fits."
+stakeholder.lm.empty_found = "We found %s in this strategy"
+stakeholder.lm.found_program = "program"
+stakeholder.lm.found_programs = "programs"
+stakeholder.lm.found_project = "project"
+stakeholder.lm.found_projects = "projects"
stakeholder.lm.coming_title = "5-stage read-out with task-card standard + connection-health badges"
stakeholder.lm.coming_hint = "Cards per stage with assumption/hypothesis, linked projects, and a fold-out \"this period\" read-out. Connection badges between stages from zp_logicmodel_health."
stakeholder.rc.coming_title = "Resource summary + resource-backed coverage matrix"