@retiregolden/planner-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +181 -0
  3. package/package.json +77 -0
  4. package/src/App.tsx +246 -0
  5. package/src/RouteErrorBoundary.tsx +45 -0
  6. package/src/assets/hero.png +0 -0
  7. package/src/assets/react.svg +1 -0
  8. package/src/assets/vite.svg +1 -0
  9. package/src/data/fedInvestClient.ts +113 -0
  10. package/src/data/localStore.ts +42 -0
  11. package/src/data/planOrigin.ts +24 -0
  12. package/src/data/planStore.ts +165 -0
  13. package/src/data/v2Backup.ts +101 -0
  14. package/src/import/ImportPage.tsx +347 -0
  15. package/src/import/ReviewChecklistView.tsx +38 -0
  16. package/src/import/brokerCsv.ts +395 -0
  17. package/src/import/csv.ts +133 -0
  18. package/src/import/genericCsv.ts +224 -0
  19. package/src/import/projectionLab.ts +350 -0
  20. package/src/import/reviewChecklist.ts +33 -0
  21. package/src/import/tenForty.ts +275 -0
  22. package/src/index.css +630 -0
  23. package/src/index.ts +16 -0
  24. package/src/learn/ArticleBody.tsx +78 -0
  25. package/src/learn/ArticlePage.tsx +57 -0
  26. package/src/learn/GlossaryPage.tsx +33 -0
  27. package/src/learn/LearnAboutScreen.tsx +41 -0
  28. package/src/learn/LearnCards.tsx +41 -0
  29. package/src/learn/LearnLink.tsx +91 -0
  30. package/src/learn/LearningCenterPage.tsx +114 -0
  31. package/src/learn/SourcesPage.tsx +98 -0
  32. package/src/learn/components/ArticleFigure.tsx +34 -0
  33. package/src/learn/components/ArticleShell.tsx +86 -0
  34. package/src/learn/components/ComparisonTable.tsx +42 -0
  35. package/src/learn/components/FormulaBlock.tsx +34 -0
  36. package/src/learn/components/PurchasingPowerChart.tsx +41 -0
  37. package/src/learn/components/RelatedArticles.tsx +27 -0
  38. package/src/learn/components/ScenarioCard.tsx +24 -0
  39. package/src/learn/components/SourceList.tsx +23 -0
  40. package/src/learn/components/charts.tsx +21 -0
  41. package/src/learn/content/about-retiregolden.ts +100 -0
  42. package/src/learn/content/aca-premium-tax-credits-and-magi.ts +103 -0
  43. package/src/learn/content/account-types-overview.ts +106 -0
  44. package/src/learn/content/after-tax-estate.ts +111 -0
  45. package/src/learn/content/agi-magi-and-taxable-income.ts +112 -0
  46. package/src/learn/content/appealing-irmaa-ssa-44.ts +95 -0
  47. package/src/learn/content/assumption-general-inflation.ts +82 -0
  48. package/src/learn/content/assumption-healthcare-inflation.ts +85 -0
  49. package/src/learn/content/assumption-heir-tax-rate.ts +79 -0
  50. package/src/learn/content/assumption-investment-returns.ts +90 -0
  51. package/src/learn/content/assumption-longevity-planning-age.ts +78 -0
  52. package/src/learn/content/assumption-recent-magi.ts +83 -0
  53. package/src/learn/content/assumption-social-security-cola.ts +89 -0
  54. package/src/learn/content/assumption-social-security-trust-fund.ts +83 -0
  55. package/src/learn/content/assumption-state-tax-override.ts +79 -0
  56. package/src/learn/content/beneficiaries-and-account-titling.ts +99 -0
  57. package/src/learn/content/break-even-useful-lens.ts +94 -0
  58. package/src/learn/content/building-a-retirement-spending-budget.ts +100 -0
  59. package/src/learn/content/cola-and-inflation-protection.ts +102 -0
  60. package/src/learn/content/divorced-spousal-and-survivor-records.ts +104 -0
  61. package/src/learn/content/dynamic-spending-guardrails.ts +90 -0
  62. package/src/learn/content/earnings-test-before-fra.ts +100 -0
  63. package/src/learn/content/employer-match-and-contribution-order.ts +104 -0
  64. package/src/learn/content/examplePlanArticles.ts +525 -0
  65. package/src/learn/content/fees-expense-ratios-and-compounding-drag.ts +98 -0
  66. package/src/learn/content/fi-number-and-four-percent-rule.ts +64 -0
  67. package/src/learn/content/filling-a-tax-bracket-with-roth-conversions.ts +98 -0
  68. package/src/learn/content/funded-ratio.ts +70 -0
  69. package/src/learn/content/healthcare-after-65.ts +103 -0
  70. package/src/learn/content/healthcare-before-65.ts +104 -0
  71. package/src/learn/content/historical-vs-random-return-models.ts +101 -0
  72. package/src/learn/content/how-assumptions-change-the-answer.ts +105 -0
  73. package/src/learn/content/how-much-can-i-spend.ts +105 -0
  74. package/src/learn/content/how-social-security-is-taxed.ts +95 -0
  75. package/src/learn/content/how-the-optimizer-thinks.ts +102 -0
  76. package/src/learn/content/how-the-optimizer-values-after-tax-estate.ts +97 -0
  77. package/src/learn/content/how-to-model-accumulation.ts +67 -0
  78. package/src/learn/content/how-to-read-a-retirement-projection.ts +115 -0
  79. package/src/learn/content/hsas-and-qualified-medical-expenses.ts +108 -0
  80. package/src/learn/content/hsas-as-retirement-accounts.ts +101 -0
  81. package/src/learn/content/inflation-risk.ts +98 -0
  82. package/src/learn/content/inherited-ira-10-year-rule.ts +105 -0
  83. package/src/learn/content/insurance-in-your-retirement-plan.ts +103 -0
  84. package/src/learn/content/irmaa-two-year-lookback.ts +99 -0
  85. package/src/learn/content/long-term-care-costs-and-insurance.ts +103 -0
  86. package/src/learn/content/long-term-care-insurance-as-risk-transfer.ts +98 -0
  87. package/src/learn/content/longevity-risk.ts +99 -0
  88. package/src/learn/content/marginal-vs-effective-tax-rate.ts +98 -0
  89. package/src/learn/content/medicare-part-b-vs-part-d-irmaa.ts +102 -0
  90. package/src/learn/content/mortality-weighted-social-security.ts +113 -0
  91. package/src/learn/content/moving-to-retiregolden.ts +86 -0
  92. package/src/learn/content/niit-high-income-investment-tax.ts +98 -0
  93. package/src/learn/content/ordinary-income-vs-capital-gains.ts +103 -0
  94. package/src/learn/content/paying-conversion-taxes-taxable-vs-ira.ts +102 -0
  95. package/src/learn/content/pensions-and-annuities.ts +101 -0
  96. package/src/learn/content/permanent-life-insurance-in-a-plan.ts +106 -0
  97. package/src/learn/content/pia-aime-and-bend-points.ts +103 -0
  98. package/src/learn/content/planner-overview.ts +106 -0
  99. package/src/learn/content/planning-for-couples-and-survivor-years.ts +108 -0
  100. package/src/learn/content/privacy-what-stays-in-your-browser.ts +99 -0
  101. package/src/learn/content/qcds-qualified-charitable-distributions.ts +101 -0
  102. package/src/learn/content/reading-the-results-page.ts +96 -0
  103. package/src/learn/content/reading-the-social-security-analysis-page.ts +106 -0
  104. package/src/learn/content/real-estate-home-equity-and-debt.ts +100 -0
  105. package/src/learn/content/reports-csv-exports-and-sharing.ts +101 -0
  106. package/src/learn/content/risk-based-guardrails.ts +100 -0
  107. package/src/learn/content/rmds-required-minimum-distributions.ts +100 -0
  108. package/src/learn/content/roth-conversion-basics.ts +104 -0
  109. package/src/learn/content/rsus-and-espp.ts +101 -0
  110. package/src/learn/content/rule-of-55-and-72t.ts +107 -0
  111. package/src/learn/content/savings-rate-biggest-lever.ts +66 -0
  112. package/src/learn/content/seed-your-plan-from-your-tax-return.ts +93 -0
  113. package/src/learn/content/sensitivity-testing-what-changes-the-answer.ts +104 -0
  114. package/src/learn/content/sequence-of-returns-risk.ts +98 -0
  115. package/src/learn/content/social-security-bridge.ts +67 -0
  116. package/src/learn/content/social-security-claiming-age-basics.ts +113 -0
  117. package/src/learn/content/social-security-taxes-vs-benefits.ts +76 -0
  118. package/src/learn/content/spending-profiles-and-the-retirement-smile.ts +92 -0
  119. package/src/learn/content/spousal-and-survivor-benefits.ts +120 -0
  120. package/src/learn/content/ssdi-and-retirement-planning.ts +72 -0
  121. package/src/learn/content/standard-deduction-senior-deduction-and-itemizing.ts +97 -0
  122. package/src/learn/content/state-income-taxes-in-retirement.ts +97 -0
  123. package/src/learn/content/step-up-in-basis.ts +102 -0
  124. package/src/learn/content/survivor-planning-for-couples.ts +110 -0
  125. package/src/learn/content/survivor-spending-in-couple-plans.ts +98 -0
  126. package/src/learn/content/tax-cliffs-and-bracket-edges.ts +105 -0
  127. package/src/learn/content/tax-loss-and-gain-harvesting.ts +99 -0
  128. package/src/learn/content/taxable-brokerage-basis-and-capital-gains.ts +99 -0
  129. package/src/learn/content/three-big-questions-spending-time-risk.ts +103 -0
  130. package/src/learn/content/tips-ladders.ts +92 -0
  131. package/src/learn/content/todays-dollars-vs-future-dollars.ts +107 -0
  132. package/src/learn/content/traditional-vs-roth-contributions.ts +113 -0
  133. package/src/learn/content/troubleshooting-surprising-results.ts +105 -0
  134. package/src/learn/content/trust-fund-haircut-scenarios.ts +101 -0
  135. package/src/learn/content/understanding-monte-carlo-success-rate.ts +118 -0
  136. package/src/learn/content/understanding-your-plan-assumptions.ts +134 -0
  137. package/src/learn/content/using-assumptions-and-provenance.ts +98 -0
  138. package/src/learn/content/using-scenarios-to-compare-choices.ts +99 -0
  139. package/src/learn/content/what-changes-when-you-move-states.ts +141 -0
  140. package/src/learn/content/what-is-fire.ts +65 -0
  141. package/src/learn/content/what-monte-carlo-proves.ts +98 -0
  142. package/src/learn/content/what-retiregolden-models.ts +103 -0
  143. package/src/learn/content/what-retirement-healthcare-really-costs.ts +117 -0
  144. package/src/learn/content/why-95-percent-is-not-a-guarantee.ts +98 -0
  145. package/src/learn/content/why-roth-conversions-raise-other-costs.ts +106 -0
  146. package/src/learn/content/why-small-tax-cliffs-can-matter.ts +109 -0
  147. package/src/learn/content/widows-penalty-and-survivor-brackets.ts +106 -0
  148. package/src/learn/content/withdrawal-order-basics.ts +105 -0
  149. package/src/learn/glossary.ts +191 -0
  150. package/src/learn/inlineMarkdown.tsx +54 -0
  151. package/src/learn/learn.css +537 -0
  152. package/src/learn/learningRegistry.ts +502 -0
  153. package/src/longevity/LongevityResults.tsx +85 -0
  154. package/src/longevity/LongevityWizard.tsx +305 -0
  155. package/src/longevity/constants.ts +15 -0
  156. package/src/longevity/factors.ts +125 -0
  157. package/src/longevity/model.ts +31 -0
  158. package/src/longevity/persistedGuard.ts +129 -0
  159. package/src/longevity/storage.ts +40 -0
  160. package/src/mc/messages.ts +118 -0
  161. package/src/mc/monteCarlo.worker.ts +44 -0
  162. package/src/mc/pool.ts +267 -0
  163. package/src/mc/runRequest.ts +125 -0
  164. package/src/optimize/messages.ts +84 -0
  165. package/src/optimize/optimize.worker.ts +29 -0
  166. package/src/optimize/runOptimize.ts +92 -0
  167. package/src/optimize/runSpendingSolve.ts +47 -0
  168. package/src/optimize/runner.ts +21 -0
  169. package/src/optimize/spendingMessages.ts +44 -0
  170. package/src/optimize/spendingRunner.ts +21 -0
  171. package/src/optimize/spendingSolve.worker.ts +18 -0
  172. package/src/planner/AssumptionsCardPage.tsx +136 -0
  173. package/src/planner/BucketLensCard.tsx +114 -0
  174. package/src/planner/ComparePlansPage.tsx +219 -0
  175. package/src/planner/DisclaimerPage.tsx +88 -0
  176. package/src/planner/HowTestedPage.tsx +159 -0
  177. package/src/planner/LiveStatus.tsx +15 -0
  178. package/src/planner/LongevityModal.tsx +55 -0
  179. package/src/planner/Modal.tsx +97 -0
  180. package/src/planner/MonteCarloPage.tsx +907 -0
  181. package/src/planner/OptimizePage.tsx +611 -0
  182. package/src/planner/PlanContext.tsx +198 -0
  183. package/src/planner/PlanPickerPage.tsx +124 -0
  184. package/src/planner/PlanWorkspace.tsx +290 -0
  185. package/src/planner/ProvenancePanel.tsx +45 -0
  186. package/src/planner/RelocationComparePage.tsx +485 -0
  187. package/src/planner/ReportPage.tsx +375 -0
  188. package/src/planner/ResultsPage.tsx +817 -0
  189. package/src/planner/ScenariosPage.tsx +285 -0
  190. package/src/planner/SocialSecuritySection.tsx +556 -0
  191. package/src/planner/SpendingSolverPage.tsx +512 -0
  192. package/src/planner/SsAnalysisPage.tsx +1134 -0
  193. package/src/planner/SurvivalPercentileModal.tsx +161 -0
  194. package/src/planner/SurvivorTransitionPage.tsx +286 -0
  195. package/src/planner/assumptionsExport.ts +371 -0
  196. package/src/planner/bucketLens.ts +89 -0
  197. package/src/planner/chartFrame.ts +8 -0
  198. package/src/planner/chartStyle.ts +11 -0
  199. package/src/planner/dialogViews.tsx +184 -0
  200. package/src/planner/dialogs.tsx +133 -0
  201. package/src/planner/examples/ExampleLibrary.tsx +189 -0
  202. package/src/planner/examples/ExamplePreviewBanner.tsx +55 -0
  203. package/src/planner/examples/ExamplesPage.tsx +25 -0
  204. package/src/planner/examples/OpenExampleButton.tsx +61 -0
  205. package/src/planner/examples/buildAggressiveSaver.ts +102 -0
  206. package/src/planner/examples/buildAnnuityEstate.ts +137 -0
  207. package/src/planner/examples/buildBaristaFire.ts +115 -0
  208. package/src/planner/examples/buildBracketFillRoth.ts +65 -0
  209. package/src/planner/examples/buildBridgeEarlyRetirement.ts +94 -0
  210. package/src/planner/examples/buildBrokerageNoHsa.ts +109 -0
  211. package/src/planner/examples/buildCoastFire.ts +88 -0
  212. package/src/planner/examples/buildContext.ts +20 -0
  213. package/src/planner/examples/buildEarlyCareerMatch.ts +93 -0
  214. package/src/planner/examples/buildEarlyRetireeAca.ts +61 -0
  215. package/src/planner/examples/buildExampleCouple.ts +103 -0
  216. package/src/planner/examples/buildFixedTargetSpending.ts +74 -0
  217. package/src/planner/examples/buildGlidepathAllocation.ts +131 -0
  218. package/src/planner/examples/buildGuardrailsFlex.ts +120 -0
  219. package/src/planner/examples/buildHsaPropertyDepth.ts +109 -0
  220. package/src/planner/examples/buildHsaStealthRetirement.ts +97 -0
  221. package/src/planner/examples/buildLeanFatFire.ts +109 -0
  222. package/src/planner/examples/buildLtcShock.ts +62 -0
  223. package/src/planner/examples/buildMovingStateTax.ts +53 -0
  224. package/src/planner/examples/buildNoAnnuityBrokerage.ts +92 -0
  225. package/src/planner/examples/buildRmdIrmaa.ts +55 -0
  226. package/src/planner/examples/buildSalaryGrowthEscalation.ts +96 -0
  227. package/src/planner/examples/buildStaticAllocationControl.ts +96 -0
  228. package/src/planner/examples/buildSurvivorYears.ts +62 -0
  229. package/src/planner/examples/buildUnderSavedSingle.ts +51 -0
  230. package/src/planner/examples/exampleCopy.ts +23 -0
  231. package/src/planner/examples/loadExample.ts +90 -0
  232. package/src/planner/examples/registry.ts +313 -0
  233. package/src/planner/explainPanels.tsx +233 -0
  234. package/src/planner/fields.tsx +381 -0
  235. package/src/planner/format.ts +33 -0
  236. package/src/planner/home/DataAndPrivacyCard.tsx +56 -0
  237. package/src/planner/home/GettingStartedPaths.tsx +46 -0
  238. package/src/planner/home/GettingStartedReopener.tsx +32 -0
  239. package/src/planner/home/StartHereLinks.tsx +22 -0
  240. package/src/planner/home/WelcomeHero.tsx +39 -0
  241. package/src/planner/home/YourPlans.tsx +72 -0
  242. package/src/planner/home/importErrorMessage.ts +22 -0
  243. package/src/planner/home/startHereSlugs.ts +7 -0
  244. package/src/planner/home/useHomeData.ts +190 -0
  245. package/src/planner/home/useHomeMode.ts +47 -0
  246. package/src/planner/householdActions.ts +22 -0
  247. package/src/planner/insights/InsightCardView.tsx +340 -0
  248. package/src/planner/insights/InsightsPage.tsx +204 -0
  249. package/src/planner/insights/categoryLabels.ts +11 -0
  250. package/src/planner/learnLinks.ts +85 -0
  251. package/src/planner/marketModelPicker.ts +172 -0
  252. package/src/planner/optimizePageChart.ts +40 -0
  253. package/src/planner/optimizePageClaim.ts +64 -0
  254. package/src/planner/planCompleteness.ts +27 -0
  255. package/src/planner/planContextCore.ts +26 -0
  256. package/src/planner/planner.css +2304 -0
  257. package/src/planner/provenanceLinks.ts +25 -0
  258. package/src/planner/sections/AccountFields.tsx +872 -0
  259. package/src/planner/sections/AccountsSection.tsx +89 -0
  260. package/src/planner/sections/AllocationPanel.tsx +261 -0
  261. package/src/planner/sections/AssumptionsSection.tsx +256 -0
  262. package/src/planner/sections/HouseholdSection.tsx +243 -0
  263. package/src/planner/sections/IncomeFloorSection.tsx +418 -0
  264. package/src/planner/sections/IncomeSection.tsx +170 -0
  265. package/src/planner/sections/InsuranceSection.tsx +362 -0
  266. package/src/planner/sections/SpendingSection.tsx +904 -0
  267. package/src/planner/sections/StrategySection.tsx +349 -0
  268. package/src/planner/sections/UpdateBalancesPanel.tsx +182 -0
  269. package/src/planner/sections/sectionHelpers.ts +48 -0
  270. package/src/planner/sections/shared.tsx +15 -0
  271. package/src/planner/sections.tsx +15 -0
  272. package/src/planner/ssAnalysis.ts +325 -0
  273. package/src/planner/successBand.ts +20 -0
  274. package/src/planner/survivorAnalysis.ts +277 -0
  275. package/src/planner/usStates.ts +19 -0
  276. package/src/planner/useMcSuccessRate.ts +77 -0
  277. package/src/planner/useProjection.ts +63 -0
  278. package/src/relocation/messages.ts +21 -0
  279. package/src/relocation/relocation.worker.ts +18 -0
  280. package/src/relocation/runRelocation.ts +17 -0
  281. package/src/relocation/runner.ts +22 -0
  282. package/src/report/brandingContext.ts +15 -0
  283. package/src/report/downloadReport.ts +34 -0
  284. package/src/report/reportHtml.ts +547 -0
  285. package/src/routes/LearnRoutes.tsx +46 -0
  286. package/src/routes/PlanRoutes.tsx +55 -0
  287. package/src/routes/RouteFallback.tsx +9 -0
  288. package/src/socialSecurity/breakEven.ts +107 -0
  289. package/src/socialSecurity/expectedPv.ts +164 -0
  290. package/src/socialSecurity/explain.ts +92 -0
  291. package/src/socialSecurity/ficaReturn.ts +81 -0
  292. package/src/socialSecurity/persistedSsGuard.ts +138 -0
  293. package/src/socialSecurity/ssFormUtils.ts +48 -0
  294. package/src/socialSecurity/ssaStatementXml.ts +156 -0
  295. package/src/socialSecurity/storage.ts +69 -0
  296. package/src/socialSecurity/survivorSwitching.ts +153 -0
  297. package/src/testSupport/samplePlan.ts +2 -0
  298. package/src/workers/run.ts +45 -0
@@ -0,0 +1,2304 @@
1
+ /* Planner workspace styles (v2 cutover UI). Tokens live in index.css. */
2
+
3
+ /* The planner wants room; the shell stays 52rem for legacy pages. */
4
+ .planner-shell {
5
+ max-width: 80rem;
6
+ margin: 0 auto;
7
+ }
8
+
9
+ /* Order-proof copy of the rule above for the app shell itself: .app-shell
10
+ (52rem, index.css) ties this file's .planner-shell on specificity, so the
11
+ winner used to depend on which stylesheet the bundler emitted first — dev
12
+ injected planner.css last (80rem shell), while the production build linked
13
+ it first, quietly capping the whole workspace at 52rem. The compound +
14
+ :not() outranks .app-shell regardless of order, keeps the tighter
15
+ .app-shell--landing column (index.css) in charge of the landing routes,
16
+ and @media screen leaves the print reset (max-width: none, below)
17
+ uncontested. */
18
+ @media screen {
19
+ .app-shell.planner-shell:not(.app-shell--landing) {
20
+ max-width: 80rem;
21
+ }
22
+ }
23
+
24
+ .kpi-value,
25
+ .year-table td,
26
+ .compare-table td {
27
+ font-variant-numeric: tabular-nums;
28
+ }
29
+
30
+ /* --- plan picker ---------------------------------------------------------- */
31
+
32
+ .picker-page {
33
+ text-align: left;
34
+ }
35
+
36
+ /* The shared empty state is centered for in-page sections, but on the picker
37
+ landing page it should sit on the same left edge as the heading and cards. */
38
+ .picker-page .empty-state {
39
+ text-align: left;
40
+ padding: 2rem 0 1.5rem;
41
+ }
42
+
43
+ /* --- planner home redesign ----------------------------------------------- */
44
+
45
+ .home-hero {
46
+ margin-bottom: 2rem;
47
+ }
48
+
49
+ .home-hero h1 {
50
+ margin-bottom: 0.5rem;
51
+ font-size: clamp(1.5rem, 4vw, 2rem);
52
+ line-height: 1.2;
53
+ }
54
+
55
+ .home-hero-subhead {
56
+ margin-bottom: 1rem;
57
+ }
58
+
59
+ .trust-chips {
60
+ display: flex;
61
+ flex-wrap: wrap;
62
+ gap: 0.45rem;
63
+ margin: 0 0 1.25rem;
64
+ padding: 0;
65
+ list-style: none;
66
+ }
67
+
68
+ .trust-chips li {
69
+ font-size: 0.85rem;
70
+ padding: 0.3rem 0.65rem;
71
+ border-radius: 999px;
72
+ border: 1px solid var(--border);
73
+ background: color-mix(in srgb, var(--fg) 4%, var(--surface-1));
74
+ color: var(--muted);
75
+ }
76
+
77
+ .home-hero-cta {
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ gap: 0.6rem;
81
+ align-items: center;
82
+ }
83
+
84
+ @media (max-width: 640px) {
85
+ .home-hero-cta .btn-primary {
86
+ width: 100%;
87
+ }
88
+ }
89
+
90
+ .home-paths {
91
+ margin-bottom: 2rem;
92
+ }
93
+
94
+ .home-paths h2,
95
+ .home-start-here h2 {
96
+ margin-bottom: 0.75rem;
97
+ font-size: 1.15rem;
98
+ }
99
+
100
+ .home-paths-grid {
101
+ margin: 0;
102
+ }
103
+
104
+ .home-path-card {
105
+ text-align: left;
106
+ text-decoration: none;
107
+ color: inherit;
108
+ font: inherit;
109
+ width: 100%;
110
+ }
111
+
112
+ .home-path-card-title {
113
+ font-weight: 650;
114
+ font-size: 1.05rem;
115
+ }
116
+
117
+ .home-path-card-desc {
118
+ color: var(--muted);
119
+ font-size: 0.9rem;
120
+ line-height: 1.45;
121
+ }
122
+
123
+ .home-start-here {
124
+ margin-bottom: 2rem;
125
+ }
126
+
127
+ .home-start-here-list {
128
+ display: flex;
129
+ flex-wrap: wrap;
130
+ gap: 0.5rem 1.25rem;
131
+ margin: 0;
132
+ padding: 0;
133
+ list-style: none;
134
+ }
135
+
136
+ .home-your-plans h1,
137
+ .home-your-plans h2 {
138
+ margin: 0 0 0.25rem;
139
+ }
140
+
141
+ .home-your-plans-head {
142
+ display: flex;
143
+ flex-wrap: wrap;
144
+ align-items: center;
145
+ justify-content: space-between;
146
+ gap: 1rem;
147
+ }
148
+
149
+ .home-returning-actions {
150
+ margin: 0;
151
+ flex-shrink: 0;
152
+ }
153
+
154
+ .home-getting-started-reopener {
155
+ margin: 0 0 1.5rem;
156
+ }
157
+
158
+ .home-reopener-btn {
159
+ display: inline-flex;
160
+ align-items: center;
161
+ gap: 0.35rem;
162
+ padding: 0.45rem 0.65rem;
163
+ border: 1px solid var(--border);
164
+ border-radius: var(--radius);
165
+ background: var(--surface-1);
166
+ color: var(--fg);
167
+ font: inherit;
168
+ font-size: 0.95rem;
169
+ cursor: pointer;
170
+ }
171
+
172
+ .home-reopener-btn:hover {
173
+ border-color: var(--accent);
174
+ }
175
+
176
+ .home-reopener-icon {
177
+ font-size: 0.8rem;
178
+ color: var(--muted);
179
+ }
180
+
181
+ .home-getting-started-panel {
182
+ margin-top: 1.25rem;
183
+ display: flex;
184
+ flex-direction: column;
185
+ gap: 0;
186
+ }
187
+
188
+ .home-privacy-card {
189
+ margin-top: 1.5rem;
190
+ }
191
+
192
+ @media (prefers-reduced-motion: reduce) {
193
+ .home-getting-started-panel {
194
+ transition: none;
195
+ }
196
+ }
197
+
198
+ .example-library {
199
+ margin-top: 2.5rem;
200
+ padding-top: 1.5rem;
201
+ border-top: 1px solid var(--border);
202
+ }
203
+
204
+ .examples-page .example-library {
205
+ margin-top: 0;
206
+ padding-top: 0;
207
+ border-top: none;
208
+ }
209
+
210
+ .examples-back {
211
+ margin-bottom: 1rem;
212
+ font-size: 0.9rem;
213
+ }
214
+
215
+ .examples-back a {
216
+ color: var(--muted);
217
+ text-decoration: none;
218
+ }
219
+
220
+ .examples-back a:hover {
221
+ color: var(--accent);
222
+ text-decoration: underline;
223
+ }
224
+
225
+ .example-library h1,
226
+ .example-library h2 {
227
+ margin-bottom: 0.35rem;
228
+ }
229
+
230
+ .examples-browse-all {
231
+ display: flex;
232
+ justify-content: center;
233
+ margin: 1.5rem 0 0.5rem;
234
+ }
235
+
236
+ .example-card {
237
+ cursor: default;
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: 0.35rem;
241
+ }
242
+
243
+ .example-card-teaches {
244
+ margin: 0;
245
+ font-size: 0.9rem;
246
+ line-height: 1.45;
247
+ color: var(--muted);
248
+ flex: 1;
249
+ }
250
+
251
+ .example-preview-banner {
252
+ margin-bottom: 1rem;
253
+ }
254
+
255
+ .example-preview-banner .picker-actions {
256
+ margin-top: 0.75rem;
257
+ }
258
+
259
+ .plan-grid {
260
+ display: grid;
261
+ grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
262
+ gap: 1rem;
263
+ margin: 1.25rem 0;
264
+ }
265
+
266
+ .plan-card {
267
+ position: relative;
268
+ display: flex;
269
+ flex-direction: column;
270
+ gap: 0.3rem;
271
+ text-align: left;
272
+ background: var(--surface-1);
273
+ border: 1px solid var(--border);
274
+ border-radius: var(--radius);
275
+ box-shadow: var(--shadow-card);
276
+ padding: 1rem 1.1rem;
277
+ color: var(--fg);
278
+ font: inherit;
279
+ transition: border-color 120ms ease, transform 120ms ease;
280
+ }
281
+
282
+ .plan-card:hover {
283
+ border-color: var(--accent);
284
+ transform: translateY(-1px);
285
+ }
286
+
287
+ /* Example cards aren't clickable as a whole (their buttons are) — no lift. */
288
+ .example-card:hover {
289
+ border-color: var(--border);
290
+ transform: none;
291
+ }
292
+
293
+ /* The primary "open" action stretched over the whole card; sibling action
294
+ buttons re-raise themselves above it. */
295
+ .plan-card-open {
296
+ display: block;
297
+ padding: 0;
298
+ border: none;
299
+ background: none;
300
+ color: inherit;
301
+ font: inherit;
302
+ text-align: left;
303
+ cursor: pointer;
304
+ }
305
+
306
+ .plan-card-open::after {
307
+ content: '';
308
+ position: absolute;
309
+ inset: 0;
310
+ border-radius: var(--radius);
311
+ }
312
+
313
+ .plan-card-open:focus-visible {
314
+ outline: none;
315
+ }
316
+
317
+ .plan-card-open:focus-visible::after {
318
+ outline: 2px solid var(--accent);
319
+ outline-offset: 2px;
320
+ }
321
+
322
+ .plan-card-actions {
323
+ position: relative;
324
+ z-index: 1;
325
+ }
326
+
327
+ .plan-card-name {
328
+ font-weight: 650;
329
+ font-size: 1.05rem;
330
+ }
331
+
332
+ .plan-card-meta {
333
+ color: var(--muted);
334
+ font-size: 0.85rem;
335
+ }
336
+
337
+ .picker-actions {
338
+ display: flex;
339
+ flex-wrap: wrap;
340
+ gap: 0.6rem;
341
+ margin: 1rem 0 0.5rem;
342
+ }
343
+
344
+ /* --- workspace shell ------------------------------------------------------ */
345
+
346
+ .workspace {
347
+ display: grid;
348
+ grid-template-columns: 13.5rem minmax(0, 1fr);
349
+ gap: 1.75rem;
350
+ align-items: start;
351
+ text-align: left;
352
+ }
353
+
354
+ @media (max-width: 880px) {
355
+ .workspace {
356
+ grid-template-columns: minmax(0, 1fr);
357
+ }
358
+ }
359
+
360
+ .workspace-rail {
361
+ position: sticky;
362
+ top: 0.75rem;
363
+ display: flex;
364
+ flex-direction: column;
365
+ gap: 0.15rem;
366
+ }
367
+
368
+ @media (max-width: 880px) {
369
+ /* Flattened rail becomes a single scrollable chip strip instead of a
370
+ 16-chip wall that pushes the form below the fold. */
371
+ .workspace-rail {
372
+ position: static;
373
+ flex-direction: row;
374
+ flex-wrap: nowrap;
375
+ overflow-x: auto;
376
+ gap: 0.25rem;
377
+ padding-bottom: 0.35rem;
378
+ -webkit-overflow-scrolling: touch;
379
+ }
380
+ }
381
+
382
+ .rail-group {
383
+ margin: 0.9rem 0 0.25rem;
384
+ font-size: 0.72rem;
385
+ font-weight: 700;
386
+ letter-spacing: 0.08em;
387
+ text-transform: uppercase;
388
+ color: var(--muted);
389
+ }
390
+
391
+ @media (max-width: 880px) {
392
+ /* Group headings read as inline separators in the strip. */
393
+ .rail-group {
394
+ flex-shrink: 0;
395
+ align-self: center;
396
+ margin: 0 0.35rem 0 0.5rem;
397
+ white-space: nowrap;
398
+ }
399
+ }
400
+
401
+ .rail-link {
402
+ display: block;
403
+ padding: 0.42rem 0.7rem;
404
+ border-radius: 8px;
405
+ color: var(--muted);
406
+ text-decoration: none;
407
+ font-size: 0.95rem;
408
+ }
409
+
410
+ @media (max-width: 880px) {
411
+ .rail-link {
412
+ flex-shrink: 0;
413
+ white-space: nowrap;
414
+ }
415
+ }
416
+
417
+ .rail-link:hover {
418
+ color: var(--fg);
419
+ background: color-mix(in srgb, var(--fg) 6%, transparent);
420
+ }
421
+
422
+ .rail-link--active {
423
+ color: var(--accent);
424
+ font-weight: 650;
425
+ background: color-mix(in srgb, var(--accent) 12%, transparent);
426
+ }
427
+
428
+ .workspace-head {
429
+ display: flex;
430
+ flex-wrap: wrap;
431
+ align-items: baseline;
432
+ gap: 0.4rem 1rem;
433
+ margin-bottom: 0.75rem;
434
+ }
435
+
436
+ .workspace-head-main {
437
+ display: flex;
438
+ flex-direction: column;
439
+ gap: 0.15rem;
440
+ flex: 1;
441
+ min-width: 0;
442
+ }
443
+
444
+ .workspace-breadcrumb ol {
445
+ display: flex;
446
+ flex-wrap: wrap;
447
+ align-items: center;
448
+ gap: 0.35rem;
449
+ margin: 0;
450
+ padding: 0;
451
+ list-style: none;
452
+ font-size: 0.85rem;
453
+ color: var(--muted);
454
+ }
455
+
456
+ .workspace-breadcrumb li + li::before {
457
+ content: '/';
458
+ margin-right: 0.35rem;
459
+ color: var(--muted);
460
+ }
461
+
462
+ .workspace-breadcrumb a {
463
+ color: var(--muted);
464
+ text-decoration: none;
465
+ }
466
+
467
+ .workspace-breadcrumb a:hover {
468
+ color: var(--accent);
469
+ text-decoration: underline;
470
+ }
471
+
472
+ .workspace-breadcrumb [aria-current='page'] {
473
+ color: var(--fg);
474
+ font-weight: 550;
475
+ }
476
+
477
+ .rail-link--back {
478
+ margin-bottom: 0.35rem;
479
+ font-weight: 600;
480
+ color: var(--fg);
481
+ border: 1px solid var(--border);
482
+ }
483
+
484
+ .rail-link--back:hover {
485
+ border-color: var(--accent);
486
+ background: color-mix(in srgb, var(--accent) 8%, transparent);
487
+ }
488
+
489
+ @media (max-width: 880px) {
490
+ .rail-link--back {
491
+ flex-basis: auto;
492
+ flex-shrink: 0;
493
+ margin-bottom: 0;
494
+ }
495
+ }
496
+
497
+ .workspace-head h1 {
498
+ margin: 0;
499
+ font-size: 1.45rem;
500
+ }
501
+
502
+ .plan-name-input {
503
+ font: inherit;
504
+ font-size: 1.45rem;
505
+ font-weight: 700;
506
+ color: var(--fg);
507
+ background: transparent;
508
+ border: 1px solid transparent;
509
+ border-radius: 8px;
510
+ padding: 0.1rem 0.4rem;
511
+ margin-left: -0.4rem;
512
+ max-width: 24rem;
513
+ }
514
+
515
+ .plan-name-input:hover,
516
+ .plan-name-input:focus {
517
+ border-color: var(--border);
518
+ background: var(--surface-1);
519
+ }
520
+
521
+ .plan-name-input:focus-visible {
522
+ outline: 2px solid var(--accent);
523
+ outline-offset: 1px;
524
+ }
525
+
526
+ .save-state {
527
+ font-size: 0.85rem;
528
+ color: var(--muted);
529
+ }
530
+
531
+ .save-state--error {
532
+ color: var(--bad);
533
+ }
534
+
535
+ /* --- sticky KPI bar ------------------------------------------------------- */
536
+
537
+ .kpi-bar {
538
+ position: sticky;
539
+ top: 0;
540
+ z-index: 5;
541
+ display: grid;
542
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
543
+ gap: 0.75rem;
544
+ padding: 0.7rem 0.9rem;
545
+ margin-bottom: 1.25rem;
546
+ background: color-mix(in srgb, var(--surface-1) 88%, transparent);
547
+ backdrop-filter: blur(8px);
548
+ border: 1px solid var(--border);
549
+ border-radius: var(--radius);
550
+ box-shadow: var(--shadow-card);
551
+ }
552
+
553
+ .kpi {
554
+ display: flex;
555
+ flex-direction: column;
556
+ gap: 0.05rem;
557
+ min-width: 0;
558
+ }
559
+
560
+ .kpi-label {
561
+ font-size: 0.72rem;
562
+ font-weight: 700;
563
+ letter-spacing: 0.07em;
564
+ text-transform: uppercase;
565
+ color: var(--muted);
566
+ white-space: nowrap;
567
+ }
568
+
569
+ .kpi-value {
570
+ font-size: clamp(1.15rem, 2.2vw, 1.5rem);
571
+ font-weight: 700;
572
+ line-height: 1.15;
573
+ white-space: nowrap;
574
+ }
575
+
576
+ .kpi-value--good { color: var(--good); }
577
+ .kpi-value--bad { color: var(--bad); }
578
+
579
+ /* Getting-started state: no verdict framing while the plan is half-entered. */
580
+ .kpi-value--pending {
581
+ color: var(--muted);
582
+ }
583
+
584
+ .kpi-sub--wrap {
585
+ white-space: normal;
586
+ }
587
+
588
+ /* A KPI value that routes somewhere ("what would change this", Monte Carlo).
589
+ Decoration follows the value's own tone via currentColor. */
590
+ .kpi-value-link {
591
+ text-decoration: underline;
592
+ text-decoration-thickness: 1px;
593
+ text-underline-offset: 3px;
594
+ text-decoration-color: color-mix(in srgb, currentColor 55%, transparent);
595
+ }
596
+
597
+ .kpi-value-link:hover {
598
+ text-decoration-color: currentColor;
599
+ }
600
+
601
+ .kpi-value-link:focus-visible {
602
+ outline: 2px solid var(--accent);
603
+ outline-offset: 2px;
604
+ border-radius: 4px;
605
+ }
606
+
607
+ .kpi-sub {
608
+ font-size: 0.78rem;
609
+ color: var(--muted);
610
+ white-space: nowrap;
611
+ }
612
+
613
+ @media (max-width: 880px) {
614
+ /* Phones and narrow tablets: one sticky row that scrolls horizontally
615
+ instead of a two-row wall that, with the toolbar, pushes the verdict
616
+ below the fold while typing. */
617
+ .kpi-bar {
618
+ grid-template-columns: none;
619
+ grid-auto-flow: column;
620
+ grid-auto-columns: minmax(8.5rem, 1fr);
621
+ overflow-x: auto;
622
+ gap: 0.6rem;
623
+ padding: 0.55rem 0.75rem;
624
+ -webkit-overflow-scrolling: touch;
625
+ }
626
+ }
627
+
628
+ /* --- cards + forms -------------------------------------------------------- */
629
+
630
+ .card {
631
+ background: var(--surface-1);
632
+ border: 1px solid var(--border);
633
+ border-radius: var(--radius);
634
+ box-shadow: var(--shadow-card);
635
+ padding: 1.1rem 1.25rem 1.25rem;
636
+ margin-bottom: 1.25rem;
637
+ }
638
+
639
+ .card > h1,
640
+ .card > h2 {
641
+ margin: 0 0 0.25rem;
642
+ font-size: 1.15rem;
643
+ }
644
+
645
+ .card > h3 {
646
+ margin: 1rem 0 0.25rem;
647
+ font-size: 1rem;
648
+ }
649
+
650
+ .card-hint {
651
+ color: var(--muted);
652
+ font-size: 0.9rem;
653
+ margin: 0 0 0.85rem;
654
+ /* Keep hint lines readable — the home cards were pushing ~122ch. */
655
+ max-width: 70ch;
656
+ }
657
+
658
+ .form-grid {
659
+ display: grid;
660
+ grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr));
661
+ gap: 0.8rem 1.1rem;
662
+ }
663
+
664
+ .form-grid > .field-span-full {
665
+ grid-column: 1 / -1;
666
+ }
667
+
668
+ .form-grid .field {
669
+ margin-top: 0;
670
+ }
671
+
672
+ .nested-form-section {
673
+ border-left: 3px solid var(--accent);
674
+ padding-left: 1rem;
675
+ margin: 0.35rem 0 0.25rem;
676
+ }
677
+
678
+ .nested-form-section > h4 {
679
+ margin: 0 0 0.75rem;
680
+ font-size: 0.98rem;
681
+ }
682
+
683
+ .nested-control-grid,
684
+ .nested-phase-grid {
685
+ grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
686
+ }
687
+
688
+ .nested-phase-row {
689
+ border-bottom: 1px dashed var(--border);
690
+ padding-bottom: 0.75rem;
691
+ margin-bottom: 0.9rem;
692
+ }
693
+
694
+ .nested-phase-row:last-of-type {
695
+ margin-bottom: 0.75rem;
696
+ }
697
+
698
+ .nested-phase-row > button {
699
+ margin-top: 0.6rem;
700
+ }
701
+
702
+ .field-label {
703
+ font-size: 0.85rem;
704
+ font-weight: 600;
705
+ }
706
+
707
+ .field input:not([type='checkbox']):not([type='radio']),
708
+ .field select {
709
+ padding: 0.45rem 0.55rem;
710
+ border-radius: 8px;
711
+ border: 1px solid var(--border);
712
+ background: var(--surface-1);
713
+ color: var(--fg);
714
+ font-size: 0.98rem;
715
+ width: 100%;
716
+ max-width: 100%;
717
+ }
718
+
719
+ /* Safety net: a long option label degrades to an ellipsis instead of clipping
720
+ mid-glyph when the closed control is narrower than the selected text. */
721
+ .field select {
722
+ overflow: hidden;
723
+ text-overflow: ellipsis;
724
+ white-space: nowrap;
725
+ }
726
+
727
+ .field--checkbox input[type='checkbox'] {
728
+ align-self: flex-start;
729
+ width: auto;
730
+ margin: 0;
731
+ cursor: pointer;
732
+ }
733
+
734
+ .field-readonly {
735
+ margin: 0;
736
+ padding: 0.45rem 0.55rem;
737
+ border-radius: 8px;
738
+ border: 1px dashed var(--border);
739
+ background: var(--surface-2);
740
+ color: var(--fg);
741
+ font-size: 0.98rem;
742
+ }
743
+
744
+ .field input:focus-visible,
745
+ .field select:focus-visible,
746
+ .btn:focus-visible,
747
+ .rail-link:focus-visible {
748
+ outline: 2px solid var(--accent);
749
+ outline-offset: 1px;
750
+ }
751
+
752
+ .input-affix {
753
+ display: flex;
754
+ align-items: center;
755
+ border: 1px solid var(--border);
756
+ border-radius: 8px;
757
+ background: var(--surface-1);
758
+ overflow: hidden;
759
+ }
760
+
761
+ .input-affix:focus-within {
762
+ outline: 2px solid var(--accent);
763
+ outline-offset: 1px;
764
+ }
765
+
766
+ .input-affix > span {
767
+ padding: 0 0.55rem;
768
+ color: var(--muted);
769
+ font-size: 0.9rem;
770
+ background: var(--surface-2);
771
+ align-self: stretch;
772
+ display: flex;
773
+ align-items: center;
774
+ }
775
+
776
+ .input-affix > input {
777
+ border: none !important;
778
+ outline: none !important;
779
+ background: transparent !important;
780
+ flex: 1;
781
+ min-width: 0;
782
+ }
783
+
784
+ .item-row {
785
+ border: 1px solid var(--border);
786
+ border-radius: var(--radius);
787
+ background: var(--surface-2);
788
+ padding: 0.9rem 1rem;
789
+ margin-bottom: 0.8rem;
790
+ }
791
+
792
+ .item-row-head {
793
+ display: flex;
794
+ justify-content: space-between;
795
+ align-items: center;
796
+ gap: 0.75rem;
797
+ margin-bottom: 0.6rem;
798
+ }
799
+
800
+ .item-row-title {
801
+ font-weight: 650;
802
+ display: flex;
803
+ align-items: center;
804
+ gap: 0.5rem;
805
+ }
806
+
807
+ .type-chip {
808
+ font-size: 0.72rem;
809
+ font-weight: 700;
810
+ letter-spacing: 0.04em;
811
+ text-transform: uppercase;
812
+ padding: 0.12rem 0.5rem;
813
+ border-radius: 999px;
814
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
815
+ color: var(--accent);
816
+ }
817
+
818
+ .btn-ghost {
819
+ background: transparent;
820
+ color: var(--muted);
821
+ border: 1px solid transparent;
822
+ border-radius: 8px;
823
+ padding: 0.3rem 0.6rem;
824
+ cursor: pointer;
825
+ font-size: 0.88rem;
826
+ transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
827
+ }
828
+
829
+ .btn-ghost:hover {
830
+ color: var(--fg);
831
+ background: color-mix(in srgb, var(--fg) 6%, transparent);
832
+ }
833
+
834
+ .btn-ghost:focus-visible {
835
+ outline: 2px solid var(--accent);
836
+ outline-offset: 1px;
837
+ }
838
+
839
+ .btn-ghost-danger:hover {
840
+ color: var(--bad);
841
+ background: color-mix(in srgb, var(--bad) 10%, transparent);
842
+ }
843
+
844
+ .btn-small {
845
+ font-size: 0.88rem;
846
+ padding: 0.35rem 0.7rem;
847
+ }
848
+
849
+ .add-row {
850
+ display: flex;
851
+ flex-wrap: wrap;
852
+ gap: 0.5rem;
853
+ margin-top: 0.5rem;
854
+ }
855
+
856
+ .issue-list {
857
+ margin: 0.75rem 0 0;
858
+ padding-left: 1.2rem;
859
+ color: var(--bad);
860
+ font-size: 0.9rem;
861
+ }
862
+
863
+ /* Lead verdict on Results: the one-line answer the charts are evidence for. */
864
+ .results-verdict {
865
+ margin: 0 0 1.1rem;
866
+ }
867
+
868
+ .results-verdict h2 {
869
+ margin: 0 0 0.25rem;
870
+ }
871
+
872
+ .results-verdict .muted {
873
+ margin: 0;
874
+ max-width: 70ch;
875
+ }
876
+
877
+ /* Post-delete undo toast — the deleted plan is recoverable for a few seconds. */
878
+ .undo-toast {
879
+ display: flex;
880
+ align-items: center;
881
+ justify-content: space-between;
882
+ gap: 1rem;
883
+ flex-wrap: wrap;
884
+ padding: 0.75rem 1rem;
885
+ margin: 0.9rem 0;
886
+ border: 1px solid var(--border);
887
+ border-radius: var(--radius);
888
+ background: var(--surface-2);
889
+ }
890
+
891
+ .undo-toast-actions {
892
+ display: flex;
893
+ gap: 0.5rem;
894
+ }
895
+
896
+ /* --- callouts ------------------------------------------------------------- */
897
+
898
+ .callout {
899
+ border-radius: var(--radius);
900
+ padding: 0.75rem 1rem;
901
+ margin: 0.9rem 0;
902
+ font-size: 0.92rem;
903
+ text-align: left;
904
+ border: 1px solid;
905
+ }
906
+
907
+ /* The banner box stays full width; its prose still wraps at a readable measure. */
908
+ .callout p,
909
+ .callout li {
910
+ max-width: 75ch;
911
+ }
912
+
913
+ .callout--warn {
914
+ border-color: color-mix(in srgb, var(--warn) 45%, var(--border));
915
+ background: color-mix(in srgb, var(--warn) 10%, var(--surface-1));
916
+ }
917
+
918
+ .callout--info {
919
+ border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
920
+ background: color-mix(in srgb, var(--accent) 8%, var(--surface-1));
921
+ }
922
+
923
+ .callout ul {
924
+ margin: 0.25rem 0 0;
925
+ padding-left: 1.2rem;
926
+ }
927
+
928
+ .ss-explainer {
929
+ margin-top: 0.6rem;
930
+ border: 1px solid var(--border);
931
+ border-radius: var(--radius);
932
+ background: var(--surface-2);
933
+ padding: 0.5rem 0.75rem;
934
+ font-size: 0.9rem;
935
+ }
936
+
937
+ .ss-explainer > summary {
938
+ cursor: pointer;
939
+ font-weight: 600;
940
+ color: var(--fg);
941
+ }
942
+
943
+ .ss-explainer ul {
944
+ margin: 0.5rem 0 0.25rem;
945
+ padding-left: 1.2rem;
946
+ color: var(--muted);
947
+ }
948
+
949
+ /* Explainer prose runs long ("Why this number?" panels) — cap the measure. */
950
+ .ss-explainer p {
951
+ max-width: 75ch;
952
+ }
953
+
954
+ .ss-explainer li {
955
+ margin: 0.2rem 0;
956
+ /* Definition-style items (the column legend) run ~130ch unwrapped. */
957
+ max-width: 75ch;
958
+ }
959
+
960
+ /* --- results -------------------------------------------------------------- */
961
+
962
+ .results-toolbar {
963
+ display: flex;
964
+ flex-wrap: wrap;
965
+ align-items: center;
966
+ gap: 0.75rem;
967
+ margin-bottom: 1rem;
968
+ }
969
+
970
+ /* In-page shortcut to the ledger ~4,000px down; scroll-padding-top (below)
971
+ keeps the target clear of the sticky KPI bar. */
972
+ .results-jump {
973
+ margin: -0.25rem 0 1rem;
974
+ font-size: 0.9rem;
975
+ }
976
+
977
+ /* Anchored and focus-scrolled targets must land below the sticky KPI bar,
978
+ not underneath it. Scoped to pages that actually render the bar. */
979
+ html:has(.kpi-bar) {
980
+ scroll-padding-top: 8rem;
981
+ }
982
+
983
+ #plan-content:focus {
984
+ outline: none;
985
+ }
986
+
987
+ /* The year-table summary carries a real h2 so heading navigation finds the
988
+ ledger; inline display keeps the disclosure marker on the same line. */
989
+ .year-table-summary {
990
+ cursor: pointer;
991
+ margin: 0 0 0.6rem;
992
+ }
993
+
994
+ .year-table-summary h2 {
995
+ display: inline;
996
+ font-size: 1.05rem;
997
+ margin: 0;
998
+ }
999
+
1000
+ /* Recharts' accessibility layer makes each chart surface a focusable
1001
+ application node; give it the app's gold focus signature instead of the
1002
+ browser default. */
1003
+ .chart-frame svg:focus-visible {
1004
+ outline: 2px solid var(--accent);
1005
+ outline-offset: 2px;
1006
+ }
1007
+
1008
+ .seg {
1009
+ display: inline-flex;
1010
+ border: 1px solid var(--border);
1011
+ border-radius: 999px;
1012
+ overflow: hidden;
1013
+ background: var(--surface-1);
1014
+ }
1015
+
1016
+ .seg button {
1017
+ border: none;
1018
+ background: transparent;
1019
+ color: var(--muted);
1020
+ font: inherit;
1021
+ font-size: 0.88rem;
1022
+ padding: 0.32rem 0.85rem;
1023
+ cursor: pointer;
1024
+ }
1025
+
1026
+ .seg button[aria-pressed='true'] {
1027
+ background: var(--accent);
1028
+ color: var(--accent-fg);
1029
+ font-weight: 600;
1030
+ }
1031
+
1032
+ .seg button:focus-visible {
1033
+ outline: 2px solid var(--accent);
1034
+ outline-offset: -2px;
1035
+ position: relative;
1036
+ z-index: 1;
1037
+ }
1038
+
1039
+ .chart-card {
1040
+ background: var(--surface-1);
1041
+ border: 1px solid var(--border);
1042
+ border-radius: var(--radius);
1043
+ box-shadow: var(--shadow-card);
1044
+ padding: 1rem 1.1rem 0.6rem;
1045
+ margin-bottom: 1.25rem;
1046
+ }
1047
+
1048
+ .chart-card h2 {
1049
+ margin: 0 0 0.15rem;
1050
+ font-size: 1.05rem;
1051
+ }
1052
+
1053
+ .chart-card .card-hint {
1054
+ margin-bottom: 0.5rem;
1055
+ }
1056
+
1057
+ /* Recharts 3 portals tooltip and legend into the same wrapper; legend wins by DOM order unless layered. */
1058
+ .recharts-wrapper .recharts-tooltip-wrapper {
1059
+ z-index: 2;
1060
+ }
1061
+
1062
+ .recharts-wrapper .recharts-legend-wrapper {
1063
+ z-index: 1;
1064
+ }
1065
+
1066
+ /* Both axes scroll INSIDE this wrapper: the vertical cap is what lets the
1067
+ sticky thead (top: 0) and sticky first column (left: 0) actually engage —
1068
+ sticky against the page never fires from inside an overflow container.
1069
+ Zero padding so rows can't peek past the sticky edges. */
1070
+ .year-table-wrap {
1071
+ overflow: auto;
1072
+ max-height: min(70vh, 56rem);
1073
+ border: 1px solid var(--border);
1074
+ border-radius: var(--radius);
1075
+ background: var(--surface-1);
1076
+ }
1077
+
1078
+ .year-table {
1079
+ width: 100%;
1080
+ border-collapse: collapse;
1081
+ font-size: 0.86rem;
1082
+ white-space: nowrap;
1083
+ }
1084
+
1085
+ .year-table th,
1086
+ .year-table td {
1087
+ padding: 0.4rem 0.7rem;
1088
+ border-bottom: 1px solid var(--border);
1089
+ text-align: right;
1090
+ }
1091
+
1092
+ .year-table th:first-child,
1093
+ .year-table td:first-child {
1094
+ text-align: left;
1095
+ position: sticky;
1096
+ left: 0;
1097
+ z-index: 1;
1098
+ background: var(--surface-1);
1099
+ font-weight: 600;
1100
+ }
1101
+
1102
+ .year-table thead th {
1103
+ background: var(--surface-2);
1104
+ position: sticky;
1105
+ top: 0;
1106
+ z-index: 2;
1107
+ font-size: 0.78rem;
1108
+ text-transform: uppercase;
1109
+ letter-spacing: 0.04em;
1110
+ color: var(--muted);
1111
+ }
1112
+
1113
+ /* The Year corner cell sticks on both axes and sits above everything. */
1114
+ .year-table thead th:first-child {
1115
+ z-index: 3;
1116
+ background: var(--surface-2);
1117
+ }
1118
+
1119
+ .year-table tbody tr:hover td {
1120
+ background: color-mix(in srgb, var(--accent) 6%, transparent);
1121
+ }
1122
+
1123
+ .row-depleted td {
1124
+ color: var(--bad);
1125
+ }
1126
+
1127
+ /* --- stat tiles + chart grids ---------------------------------------------- */
1128
+
1129
+ /* One vocabulary for big-number tiles (Monte Carlo metrics, Optimize deltas,
1130
+ spending-solver stats) instead of per-page inline styles, and dedicated
1131
+ grids instead of reusing .workspace with inline column overrides. */
1132
+ .stat-grid {
1133
+ display: grid;
1134
+ grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
1135
+ gap: 0.75rem;
1136
+ align-items: start;
1137
+ text-align: left;
1138
+ }
1139
+
1140
+ .stat-grid > .card {
1141
+ margin-bottom: 0;
1142
+ }
1143
+
1144
+ /* A subtle inset panel for a grouped set of metrics inside a card. */
1145
+ .metric-panel {
1146
+ padding: 1rem;
1147
+ margin-bottom: 1rem;
1148
+ background: var(--surface-2);
1149
+ border: 1px solid var(--border);
1150
+ border-radius: 8px;
1151
+ }
1152
+
1153
+ .chart-grid {
1154
+ display: grid;
1155
+ grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
1156
+ gap: 1.25rem;
1157
+ align-items: start;
1158
+ text-align: left;
1159
+ }
1160
+
1161
+ .stat-value {
1162
+ font-size: 1.6rem;
1163
+ font-weight: 650;
1164
+ }
1165
+
1166
+ .stat-value--sm {
1167
+ font-size: 1.1rem;
1168
+ }
1169
+
1170
+ .stat-value--good { color: var(--good); }
1171
+ .stat-value--bad { color: var(--bad); }
1172
+ .stat-value--neutral { color: var(--fg); }
1173
+
1174
+ /* --- monte carlo ---------------------------------------------------------- */
1175
+
1176
+ .model-preset-row {
1177
+ display: grid;
1178
+ grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
1179
+ gap: 0.6rem;
1180
+ }
1181
+
1182
+ .model-preset {
1183
+ display: flex;
1184
+ flex-direction: column;
1185
+ gap: 0.2rem;
1186
+ text-align: left;
1187
+ font: inherit;
1188
+ padding: 0.6rem 0.8rem;
1189
+ border: 1px solid var(--border);
1190
+ border-radius: var(--radius);
1191
+ background: var(--surface-1);
1192
+ color: var(--fg);
1193
+ cursor: pointer;
1194
+ transition: border-color 120ms ease, background-color 120ms ease;
1195
+ }
1196
+
1197
+ .model-preset:hover {
1198
+ border-color: var(--accent);
1199
+ }
1200
+
1201
+ .model-preset:focus-visible {
1202
+ outline: 2px solid var(--accent);
1203
+ outline-offset: 1px;
1204
+ }
1205
+
1206
+ .model-preset[aria-pressed='true'] {
1207
+ border-color: var(--accent);
1208
+ background: color-mix(in srgb, var(--accent) 10%, var(--surface-1));
1209
+ }
1210
+
1211
+ .model-preset-label {
1212
+ font-weight: 650;
1213
+ font-size: 0.95rem;
1214
+ }
1215
+
1216
+ .model-preset-desc {
1217
+ font-size: 0.85rem;
1218
+ color: var(--muted);
1219
+ line-height: 1.4;
1220
+ }
1221
+
1222
+ .model-advanced {
1223
+ margin-top: 0.6rem;
1224
+ }
1225
+
1226
+ .model-advanced-field {
1227
+ max-width: 26rem;
1228
+ margin: 0.5rem 0 0.25rem;
1229
+ }
1230
+
1231
+ /* Shared responsive chart frame — replaces repeated inline
1232
+ width:100%/height wrappers on the Monte Carlo and Results pages. Height comes
1233
+ in via the --chart-frame-h custom property so the frame itself stays reusable. */
1234
+ .chart-frame {
1235
+ --chart-frame-h: 240px;
1236
+ width: 100%;
1237
+ height: var(--chart-frame-h);
1238
+ }
1239
+
1240
+ .chart-frame--spaced {
1241
+ margin-top: 1rem;
1242
+ }
1243
+
1244
+ /* Inline error text (worker/run failures) as a shared token, not a per-site style. */
1245
+ .error-text {
1246
+ color: var(--bad);
1247
+ }
1248
+
1249
+ /* An error message paired with a recovery action (e.g. "Run again"). */
1250
+ .error-recovery {
1251
+ display: flex;
1252
+ align-items: center;
1253
+ gap: 0.75rem;
1254
+ flex-wrap: wrap;
1255
+ margin-top: 0.5rem;
1256
+ }
1257
+
1258
+ .error-recovery .error-text {
1259
+ margin: 0;
1260
+ }
1261
+
1262
+ .mc-hero {
1263
+ display: grid;
1264
+ grid-template-columns: auto minmax(0, 1fr);
1265
+ gap: 1.5rem;
1266
+ align-items: center;
1267
+ margin-bottom: 1.25rem;
1268
+ }
1269
+
1270
+ .mc-hero h2 {
1271
+ margin: 0 0 0.35rem;
1272
+ }
1273
+
1274
+ .mc-hero .muted {
1275
+ margin: 0;
1276
+ max-width: 70ch;
1277
+ }
1278
+
1279
+ @media (max-width: 720px) {
1280
+ .mc-hero {
1281
+ grid-template-columns: minmax(0, 1fr);
1282
+ }
1283
+ }
1284
+
1285
+ /* The handrail under a non-green verdict: one sentence + links to the
1286
+ surfaces that answer "what would change this". */
1287
+ .mc-handrail {
1288
+ margin: 0.75rem 0 0;
1289
+ font-size: 1rem;
1290
+ padding: 0.6rem 0.75rem;
1291
+ border-radius: 8px;
1292
+ background: color-mix(in srgb, var(--accent) 8%, transparent);
1293
+ max-width: 75ch;
1294
+ }
1295
+
1296
+ .mc-handrail a {
1297
+ color: var(--accent);
1298
+ font-weight: 600;
1299
+ }
1300
+
1301
+ .success-gauge {
1302
+ position: relative;
1303
+ width: 11rem;
1304
+ height: 11rem;
1305
+ }
1306
+
1307
+ .success-gauge svg {
1308
+ transform: rotate(-90deg);
1309
+ }
1310
+
1311
+ .success-gauge-label {
1312
+ position: absolute;
1313
+ inset: 0;
1314
+ display: flex;
1315
+ flex-direction: column;
1316
+ align-items: center;
1317
+ justify-content: center;
1318
+ }
1319
+
1320
+ .success-gauge-value {
1321
+ font-size: 2.1rem;
1322
+ font-weight: 750;
1323
+ line-height: 1;
1324
+ font-variant-numeric: tabular-nums;
1325
+ }
1326
+
1327
+ .success-gauge-caption {
1328
+ font-size: 0.78rem;
1329
+ color: var(--muted);
1330
+ margin-top: 0.3rem;
1331
+ }
1332
+
1333
+ .progress-track {
1334
+ height: 6px;
1335
+ border-radius: 999px;
1336
+ background: var(--surface-2);
1337
+ overflow: hidden;
1338
+ margin: 0.6rem 0;
1339
+ }
1340
+
1341
+ .progress-fill {
1342
+ height: 100%;
1343
+ width: 100%;
1344
+ border-radius: 999px;
1345
+ background: linear-gradient(90deg, var(--accent), var(--accent-soft));
1346
+ /* Scale instead of animating width: compositor-only, no layout thrash. */
1347
+ transform-origin: left center;
1348
+ transition: transform 160ms ease;
1349
+ }
1350
+
1351
+ @media (prefers-reduced-motion: reduce) {
1352
+ .progress-fill,
1353
+ .plan-card {
1354
+ transition: none;
1355
+ }
1356
+ }
1357
+
1358
+ .skeleton {
1359
+ border-radius: var(--radius);
1360
+ background: linear-gradient(100deg, var(--surface-2) 40%, color-mix(in srgb, var(--fg) 7%, var(--surface-2)) 50%, var(--surface-2) 60%);
1361
+ background-size: 200% 100%;
1362
+ animation: shimmer 1.4s infinite linear;
1363
+ }
1364
+
1365
+ @media (prefers-reduced-motion: reduce) {
1366
+ .skeleton {
1367
+ animation: none;
1368
+ }
1369
+ }
1370
+
1371
+ @keyframes shimmer {
1372
+ to {
1373
+ background-position: -200% 0;
1374
+ }
1375
+ }
1376
+
1377
+ /* --- scenarios ------------------------------------------------------------ */
1378
+
1379
+ .compare-table {
1380
+ width: 100%;
1381
+ border-collapse: collapse;
1382
+ font-size: 0.92rem;
1383
+ }
1384
+
1385
+ .compare-table th,
1386
+ .compare-table td {
1387
+ padding: 0.55rem 0.8rem;
1388
+ border-bottom: 1px solid var(--border);
1389
+ text-align: right;
1390
+ vertical-align: top;
1391
+ }
1392
+
1393
+ .compare-table th:first-child,
1394
+ .compare-table td:first-child {
1395
+ text-align: left;
1396
+ }
1397
+
1398
+ .compare-table thead th {
1399
+ font-size: 0.78rem;
1400
+ text-transform: uppercase;
1401
+ letter-spacing: 0.04em;
1402
+ color: var(--muted);
1403
+ }
1404
+
1405
+ .diff-chip {
1406
+ display: inline-block;
1407
+ font-size: 0.76rem;
1408
+ padding: 0.08rem 0.5rem;
1409
+ margin: 0.1rem 0.2rem 0.1rem 0;
1410
+ border-radius: 999px;
1411
+ background: var(--surface-2);
1412
+ border: 1px solid var(--border);
1413
+ color: var(--muted);
1414
+ white-space: nowrap;
1415
+ }
1416
+
1417
+ .delta-pos { color: var(--good); }
1418
+ .delta-neg { color: var(--bad); }
1419
+
1420
+ /* --- assumption provenance ------------------------------------------------ */
1421
+
1422
+ .provenance-table {
1423
+ width: 100%;
1424
+ border-collapse: collapse;
1425
+ font-size: 0.92rem;
1426
+ }
1427
+
1428
+ .provenance-table th,
1429
+ .provenance-table td {
1430
+ padding: 0.6rem 0.8rem;
1431
+ border-bottom: 1px solid var(--border);
1432
+ text-align: left;
1433
+ vertical-align: top;
1434
+ }
1435
+
1436
+ .provenance-table thead th {
1437
+ font-size: 0.78rem;
1438
+ font-weight: 600;
1439
+ text-transform: uppercase;
1440
+ letter-spacing: 0.04em;
1441
+ color: var(--muted);
1442
+ }
1443
+
1444
+ .provenance-table th[scope='row'] {
1445
+ font-weight: 400;
1446
+ }
1447
+
1448
+ .provenance-label {
1449
+ display: block;
1450
+ font-weight: 600;
1451
+ }
1452
+
1453
+ .provenance-figures {
1454
+ display: block;
1455
+ margin-top: 0.15rem;
1456
+ line-height: 1.4;
1457
+ }
1458
+
1459
+ .provenance-table td {
1460
+ white-space: nowrap;
1461
+ }
1462
+
1463
+ @media (max-width: 600px) {
1464
+ .provenance-table td {
1465
+ white-space: normal;
1466
+ }
1467
+ }
1468
+
1469
+ .empty-state {
1470
+ text-align: center;
1471
+ padding: 3rem 1rem;
1472
+ color: var(--muted);
1473
+ }
1474
+
1475
+ .empty-state h2 {
1476
+ color: var(--fg);
1477
+ }
1478
+
1479
+ .app-footer {
1480
+ margin-top: 3rem;
1481
+ padding: 1rem 0 0.5rem;
1482
+ border-top: 1px solid var(--border);
1483
+ text-align: center;
1484
+ }
1485
+
1486
+ .app-footer a {
1487
+ color: var(--accent);
1488
+ }
1489
+
1490
+ /* --- help tooltips --------------------------------------------------------- */
1491
+
1492
+ .field-label-row {
1493
+ display: inline-flex;
1494
+ align-items: center;
1495
+ gap: 0.3rem;
1496
+ }
1497
+
1498
+ .help-tip {
1499
+ position: relative;
1500
+ display: inline-flex;
1501
+ }
1502
+
1503
+ .help-tip > button {
1504
+ position: relative;
1505
+ width: 1rem;
1506
+ height: 1rem;
1507
+ padding: 0;
1508
+ border-radius: 50%;
1509
+ border: 1px solid var(--border);
1510
+ background: var(--surface-2);
1511
+ color: var(--muted);
1512
+ font-size: 0.68rem;
1513
+ font-weight: 700;
1514
+ line-height: 1;
1515
+ cursor: pointer;
1516
+ display: inline-flex;
1517
+ align-items: center;
1518
+ justify-content: center;
1519
+ }
1520
+
1521
+ .help-tip > button:hover,
1522
+ .help-tip > button:focus-visible,
1523
+ .help-tip--pinned > button {
1524
+ color: var(--accent);
1525
+ border-color: var(--accent);
1526
+ }
1527
+
1528
+ .help-tip-bubble {
1529
+ /* JS positions this with fixed coordinates clamped to the viewport, so it can
1530
+ never clip at a screen edge or be cut off inside a scrolling panel. */
1531
+ position: fixed;
1532
+ top: 0;
1533
+ left: 0;
1534
+ z-index: 50;
1535
+ display: flex;
1536
+ flex-direction: column;
1537
+ gap: 0.45rem;
1538
+ width: max-content;
1539
+ max-width: min(20rem, calc(100vw - 1rem));
1540
+ background: var(--surface-1);
1541
+ color: var(--fg);
1542
+ border: 1px solid var(--border);
1543
+ border-radius: 8px;
1544
+ box-shadow: var(--shadow-card);
1545
+ padding: 0.55rem 0.7rem;
1546
+ font-size: 0.82rem;
1547
+ font-weight: 400;
1548
+ line-height: 1.45;
1549
+ text-align: left;
1550
+ white-space: normal;
1551
+ /* Hidden state: non-interactive and out of the tab order until revealed. */
1552
+ visibility: hidden;
1553
+ opacity: 0;
1554
+ transition: opacity 100ms ease;
1555
+ }
1556
+
1557
+ .help-tip-bubble--open {
1558
+ visibility: visible;
1559
+ opacity: 1;
1560
+ }
1561
+
1562
+ .help-tip-text {
1563
+ display: flex;
1564
+ flex-direction: column;
1565
+ gap: 0.3rem;
1566
+ }
1567
+
1568
+ /* A short input note (formerly the under-field hint) shown inside the bubble. */
1569
+ .help-tip-hint {
1570
+ color: var(--muted);
1571
+ font-size: 0.78rem;
1572
+ }
1573
+
1574
+ /* The "Learn more" link living at the foot of a help bubble. */
1575
+ .help-tip-bubble .learn-link--tip {
1576
+ align-self: flex-start;
1577
+ font-size: 0.8rem;
1578
+ font-weight: 600;
1579
+ }
1580
+
1581
+ /* Cite-the-authority link (provenance) inside a help bubble. */
1582
+ .help-tip-bubble .help-tip-source {
1583
+ align-self: flex-start;
1584
+ font-size: 0.8rem;
1585
+ font-weight: 600;
1586
+ }
1587
+
1588
+ .field-with-action {
1589
+ display: grid;
1590
+ grid-template-columns: 1fr auto;
1591
+ column-gap: 0.5rem;
1592
+ row-gap: 0.25rem;
1593
+ align-items: end;
1594
+ }
1595
+
1596
+ .field-with-action > .field {
1597
+ display: contents;
1598
+ }
1599
+
1600
+ .field-with-action > .field > .field-label-row {
1601
+ grid-column: 1 / -1;
1602
+ }
1603
+
1604
+ .field-with-action > .field > .input-affix,
1605
+ .field-with-action > .field > input,
1606
+ .field-with-action > .field > select {
1607
+ grid-column: 1;
1608
+ min-width: 0;
1609
+ }
1610
+
1611
+ .field-with-action > button {
1612
+ grid-column: 2;
1613
+ grid-row: 2;
1614
+ margin-bottom: 1px;
1615
+ white-space: nowrap;
1616
+ }
1617
+
1618
+ /* --- modal ----------------------------------------------------------------- */
1619
+
1620
+ .modal-backdrop {
1621
+ position: fixed;
1622
+ inset: 0;
1623
+ z-index: 50;
1624
+ background: rgb(8 10 14 / 0.55);
1625
+ backdrop-filter: blur(3px);
1626
+ display: flex;
1627
+ align-items: flex-start;
1628
+ justify-content: center;
1629
+ padding: 4vh 1rem;
1630
+ overflow-y: auto;
1631
+ }
1632
+
1633
+ .modal-panel {
1634
+ background: var(--bg);
1635
+ border: 1px solid var(--border);
1636
+ border-radius: var(--radius);
1637
+ box-shadow: 0 8px 24px rgb(0 0 0 / 0.45);
1638
+ width: 100%;
1639
+ max-width: 36rem;
1640
+ max-height: 90vh;
1641
+ display: flex;
1642
+ flex-direction: column;
1643
+ outline: none;
1644
+ }
1645
+
1646
+ .modal-head {
1647
+ display: flex;
1648
+ align-items: center;
1649
+ justify-content: space-between;
1650
+ gap: 1rem;
1651
+ padding: 0.9rem 1.25rem;
1652
+ border-bottom: 1px solid var(--border);
1653
+ }
1654
+
1655
+ .modal-head h2 {
1656
+ margin: 0;
1657
+ font-size: 1.1rem;
1658
+ }
1659
+
1660
+ .modal-close:hover {
1661
+ color: var(--fg);
1662
+ background: color-mix(in srgb, var(--fg) 8%, transparent);
1663
+ }
1664
+
1665
+ .modal-body {
1666
+ padding: 1rem 1.25rem 1.25rem;
1667
+ overflow-y: auto;
1668
+ text-align: left;
1669
+ }
1670
+
1671
+ /* --- confirm / prompt / alert dialogs -------------------------------------- */
1672
+
1673
+ .dialog-body {
1674
+ font-size: 0.95rem;
1675
+ line-height: 1.5;
1676
+ }
1677
+
1678
+ .dialog-body p {
1679
+ margin: 0 0 0.6rem;
1680
+ }
1681
+
1682
+ .dialog-body p:last-child {
1683
+ margin-bottom: 0;
1684
+ }
1685
+
1686
+ .dialog-typed-field {
1687
+ margin-top: 0.9rem;
1688
+ }
1689
+
1690
+ .dialog-typed-field input {
1691
+ max-width: 12rem;
1692
+ }
1693
+
1694
+ .dialog-actions {
1695
+ display: flex;
1696
+ flex-wrap: wrap;
1697
+ justify-content: flex-end;
1698
+ gap: 0.6rem;
1699
+ margin-top: 1.25rem;
1700
+ }
1701
+
1702
+ .dialog-actions .dialog-extra-action {
1703
+ margin-right: auto;
1704
+ }
1705
+
1706
+ .dialog-choices {
1707
+ display: flex;
1708
+ flex-direction: column;
1709
+ gap: 0.6rem;
1710
+ margin-top: 0.9rem;
1711
+ }
1712
+
1713
+ .dialog-choice {
1714
+ display: flex;
1715
+ flex-direction: column;
1716
+ gap: 0.2rem;
1717
+ text-align: left;
1718
+ font: inherit;
1719
+ padding: 0.7rem 0.9rem;
1720
+ border: 1px solid var(--border);
1721
+ border-radius: var(--radius);
1722
+ background: var(--surface-1);
1723
+ color: var(--fg);
1724
+ cursor: pointer;
1725
+ transition: border-color 120ms ease, background-color 120ms ease;
1726
+ }
1727
+
1728
+ .dialog-choice:hover {
1729
+ border-color: var(--accent);
1730
+ background: color-mix(in srgb, var(--accent) 6%, var(--surface-1));
1731
+ }
1732
+
1733
+ .dialog-choice:focus-visible {
1734
+ outline: 2px solid var(--accent);
1735
+ outline-offset: 1px;
1736
+ }
1737
+
1738
+ .dialog-choice-label {
1739
+ font-weight: 650;
1740
+ }
1741
+
1742
+ .dialog-choice-desc {
1743
+ font-size: 0.88rem;
1744
+ color: var(--muted);
1745
+ }
1746
+
1747
+ /* --- allocation estimator -------------------------------------------------- */
1748
+
1749
+ .alloc-row {
1750
+ display: grid;
1751
+ grid-template-columns: 5.5rem minmax(0, 1fr) 3.5rem;
1752
+ align-items: center;
1753
+ gap: 0.75rem;
1754
+ margin: 0.5rem 0;
1755
+ font-variant-numeric: tabular-nums;
1756
+ }
1757
+
1758
+ .alloc-result {
1759
+ display: flex;
1760
+ align-items: baseline;
1761
+ gap: 0.75rem;
1762
+ margin-top: 0.9rem;
1763
+ padding: 0.75rem 1rem;
1764
+ border-radius: var(--radius);
1765
+ background: var(--surface-2);
1766
+ }
1767
+
1768
+ .alloc-result strong {
1769
+ font-size: 1.4rem;
1770
+ }
1771
+
1772
+ /* --- SS claim table -------------------------------------------------------- */
1773
+
1774
+ .claim-table {
1775
+ width: 100%;
1776
+ border-collapse: collapse;
1777
+ font-size: 0.9rem;
1778
+ font-variant-numeric: tabular-nums;
1779
+ }
1780
+
1781
+ .claim-table th,
1782
+ .claim-table td {
1783
+ padding: 0.4rem 0.7rem;
1784
+ border-bottom: 1px solid var(--border);
1785
+ text-align: right;
1786
+ }
1787
+
1788
+ .claim-table th:first-child,
1789
+ .claim-table td:first-child {
1790
+ text-align: left;
1791
+ }
1792
+
1793
+ .claim-table thead th {
1794
+ font-size: 0.74rem;
1795
+ text-transform: uppercase;
1796
+ letter-spacing: 0.04em;
1797
+ color: var(--muted);
1798
+ }
1799
+
1800
+ .claim-row--best td {
1801
+ background: color-mix(in srgb, var(--good) 10%, transparent);
1802
+ font-weight: 600;
1803
+ }
1804
+
1805
+ .claim-row--current td:first-child::after {
1806
+ content: ' (current)';
1807
+ color: var(--accent);
1808
+ font-size: 0.78rem;
1809
+ }
1810
+
1811
+ .claim-table.heatmap th {
1812
+ text-align: center;
1813
+ }
1814
+
1815
+ .claim-table.heatmap td {
1816
+ text-align: center;
1817
+ border: 1px solid var(--border);
1818
+ font-size: 0.82rem;
1819
+ }
1820
+
1821
+ .claim-table.heatmap tbody th {
1822
+ font-weight: 600;
1823
+ color: var(--muted);
1824
+ }
1825
+
1826
+ .earnings-entry {
1827
+ margin-top: 0.5rem;
1828
+ }
1829
+
1830
+ /* --- printable report ------------------------------------------------------ */
1831
+
1832
+ .report {
1833
+ max-width: 760px;
1834
+ margin: 1.5rem auto 4rem;
1835
+ text-align: left;
1836
+ }
1837
+
1838
+ .report-head {
1839
+ display: flex;
1840
+ justify-content: space-between;
1841
+ align-items: flex-start;
1842
+ gap: 1rem;
1843
+ border-bottom: 2px solid var(--border);
1844
+ padding-bottom: 0.75rem;
1845
+ }
1846
+
1847
+ .report-head h1 {
1848
+ margin: 0;
1849
+ font-size: 1.6rem;
1850
+ }
1851
+
1852
+ .report-actions {
1853
+ display: flex;
1854
+ gap: 0.5rem;
1855
+ flex-shrink: 0;
1856
+ }
1857
+
1858
+ .report-disclaimer {
1859
+ font-size: 0.82rem;
1860
+ color: var(--muted);
1861
+ margin: 0.75rem 0 0;
1862
+ }
1863
+
1864
+ .report-section {
1865
+ margin-top: 1.75rem;
1866
+ }
1867
+
1868
+ .report-section h2 {
1869
+ font-size: 1.2rem;
1870
+ margin: 0 0 0.5rem;
1871
+ padding-bottom: 0.25rem;
1872
+ border-bottom: 1px solid var(--border);
1873
+ }
1874
+
1875
+ .report-section h3 {
1876
+ font-size: 0.95rem;
1877
+ margin: 1rem 0 0.4rem;
1878
+ color: var(--muted);
1879
+ }
1880
+
1881
+ .report-kpis {
1882
+ display: grid;
1883
+ grid-template-columns: repeat(4, 1fr);
1884
+ gap: 0.75rem;
1885
+ margin-bottom: 1rem;
1886
+ }
1887
+
1888
+ .report-kpi {
1889
+ display: flex;
1890
+ flex-direction: column;
1891
+ gap: 0.1rem;
1892
+ border: 1px solid var(--border);
1893
+ border-radius: var(--radius);
1894
+ padding: 0.6rem 0.75rem;
1895
+ }
1896
+
1897
+ .report-kpi .kpi-value {
1898
+ font-size: 1.25rem;
1899
+ }
1900
+
1901
+ .report-table {
1902
+ width: 100%;
1903
+ border-collapse: collapse;
1904
+ font-size: 0.88rem;
1905
+ font-variant-numeric: tabular-nums;
1906
+ }
1907
+
1908
+ .report-table thead th {
1909
+ text-align: left;
1910
+ font-size: 0.74rem;
1911
+ text-transform: uppercase;
1912
+ letter-spacing: 0.04em;
1913
+ color: var(--muted);
1914
+ padding: 0.3rem 0.6rem;
1915
+ border-bottom: 1px solid var(--border);
1916
+ }
1917
+
1918
+ .report-chart {
1919
+ overflow-x: auto;
1920
+ }
1921
+
1922
+ .report-appendix-table {
1923
+ font-size: 0.78rem;
1924
+ }
1925
+
1926
+ @media print {
1927
+ :root {
1928
+ --bg: #fff;
1929
+ --fg: #111;
1930
+ --muted: #555;
1931
+ --border: #bbb;
1932
+ --surface-1: #fff;
1933
+ --surface-2: #f2f2f2;
1934
+ }
1935
+ .app-header,
1936
+ .app-footer,
1937
+ .no-print {
1938
+ display: none !important;
1939
+ }
1940
+ .app-shell,
1941
+ .planner-shell {
1942
+ max-width: none;
1943
+ margin: 0;
1944
+ padding: 0;
1945
+ }
1946
+ .report {
1947
+ margin: 0;
1948
+ max-width: none;
1949
+ }
1950
+ .report-section {
1951
+ break-inside: avoid;
1952
+ }
1953
+ .report-appendix {
1954
+ break-inside: auto;
1955
+ }
1956
+ .report-appendix-table tr {
1957
+ break-inside: avoid;
1958
+ }
1959
+ .report-chart {
1960
+ break-inside: avoid;
1961
+ }
1962
+ /* Recharts renders SVG; keep colors in print. */
1963
+ * {
1964
+ -webkit-print-color-adjust: exact;
1965
+ print-color-adjust: exact;
1966
+ }
1967
+ }
1968
+
1969
+ .plan-card-actions,
1970
+ .workspace-head-actions,
1971
+ .compare-selectors {
1972
+ display: flex;
1973
+ gap: 0.75rem;
1974
+ align-items: center;
1975
+ flex-wrap: wrap;
1976
+ }
1977
+
1978
+ .workspace-head-actions {
1979
+ justify-content: flex-end;
1980
+ }
1981
+
1982
+ .compare-selectors {
1983
+ align-items: flex-end;
1984
+ margin-bottom: 1rem;
1985
+ }
1986
+
1987
+ .compare-selectors label {
1988
+ display: grid;
1989
+ gap: 0.35rem;
1990
+ min-width: min(22rem, 100%);
1991
+ font-weight: 650;
1992
+ }
1993
+
1994
+ .compare-table th:first-child {
1995
+ min-width: 12rem;
1996
+ }
1997
+
1998
+ /* --- insights ------------------------------------------------------------- */
1999
+
2000
+ .insight-optimizer-row {
2001
+ display: flex;
2002
+ flex-wrap: wrap;
2003
+ gap: 1rem;
2004
+ margin-bottom: 1.25rem;
2005
+ }
2006
+
2007
+ .insight-optimizer-row > .card {
2008
+ flex: 1 1 17.5rem;
2009
+ margin-bottom: 0;
2010
+ }
2011
+
2012
+ .insight-category-group {
2013
+ margin-bottom: 1.5rem;
2014
+ }
2015
+
2016
+ /* Structural heading only — the toggle button carries all the styling, so the
2017
+ wrapping h2 resets to inherited type and spacing. */
2018
+ .insight-category-heading {
2019
+ margin: 0;
2020
+ font: inherit;
2021
+ }
2022
+
2023
+ .insight-category-header {
2024
+ display: flex;
2025
+ align-items: center;
2026
+ justify-content: space-between;
2027
+ gap: 0.75rem;
2028
+ width: 100%;
2029
+ padding: 0.75rem 1rem;
2030
+ border: 1px solid var(--border);
2031
+ border-radius: 8px;
2032
+ background: var(--surface-2);
2033
+ color: var(--fg);
2034
+ font: inherit;
2035
+ font-weight: 600;
2036
+ text-align: left;
2037
+ cursor: pointer;
2038
+ transition: background-color 0.2s ease;
2039
+ }
2040
+
2041
+ .insight-category-header:hover {
2042
+ background: color-mix(in srgb, var(--fg) 8%, var(--surface-2));
2043
+ }
2044
+
2045
+ .insight-category-header:focus-visible {
2046
+ outline: 2px solid var(--accent);
2047
+ outline-offset: 1px;
2048
+ }
2049
+
2050
+ .insight-cards-list {
2051
+ display: grid;
2052
+ gap: 0.75rem;
2053
+ margin-top: 0.75rem;
2054
+ }
2055
+
2056
+ .insight-card {
2057
+ position: relative;
2058
+ margin-bottom: 0;
2059
+ transition: transform 0.2s ease, border-color 0.2s ease;
2060
+ }
2061
+
2062
+ .insight-card:hover {
2063
+ transform: translateY(-1px);
2064
+ }
2065
+
2066
+ .insight-dismiss {
2067
+ position: absolute;
2068
+ top: 0.5rem;
2069
+ right: 0.5rem;
2070
+ }
2071
+
2072
+ .insight-badges {
2073
+ display: flex;
2074
+ flex-wrap: wrap;
2075
+ gap: 0.5rem;
2076
+ margin-bottom: 0.6rem;
2077
+ /* Keep chips clear of the absolutely positioned dismiss button. */
2078
+ padding-right: 2.25rem;
2079
+ }
2080
+
2081
+ .type-chip--good {
2082
+ background: color-mix(in srgb, var(--good) 14%, transparent);
2083
+ color: var(--good);
2084
+ }
2085
+
2086
+ .type-chip--warn {
2087
+ background: color-mix(in srgb, var(--warn) 14%, transparent);
2088
+ color: var(--warn);
2089
+ }
2090
+
2091
+ .type-chip--muted {
2092
+ background: color-mix(in srgb, var(--muted) 16%, transparent);
2093
+ color: var(--muted);
2094
+ }
2095
+
2096
+ .insight-card-title {
2097
+ margin: 0 0 0.5rem;
2098
+ font-size: 1.1rem;
2099
+ font-weight: 600;
2100
+ }
2101
+
2102
+ .insight-rationale {
2103
+ margin: 0 0 1rem;
2104
+ font-size: 0.95rem;
2105
+ line-height: 1.45;
2106
+ max-width: 75ch;
2107
+ }
2108
+
2109
+ .insight-impact-box {
2110
+ background: var(--surface-2);
2111
+ border-radius: 8px;
2112
+ padding: 0.75rem;
2113
+ margin-bottom: 1rem;
2114
+ font-size: 0.9rem;
2115
+ }
2116
+
2117
+ .insight-impact-box p {
2118
+ margin: 0 0 0.5rem;
2119
+ max-width: 75ch;
2120
+ }
2121
+
2122
+ .insight-impact-grid {
2123
+ display: grid;
2124
+ grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
2125
+ gap: 0.5rem;
2126
+ }
2127
+
2128
+ .insight-impact-box .delta-pos,
2129
+ .insight-impact-box .delta-neg {
2130
+ font-weight: 600;
2131
+ }
2132
+
2133
+ .insight-impact-box .delta-pos {
2134
+ color: var(--good);
2135
+ }
2136
+
2137
+ /* A negative delta on this surface is a caution, not a failure. */
2138
+ .insight-impact-box .delta-neg {
2139
+ color: var(--warn);
2140
+ }
2141
+
2142
+ .insight-impact-note {
2143
+ margin-top: 0.5rem;
2144
+ font-size: 0.8rem;
2145
+ color: var(--muted);
2146
+ }
2147
+
2148
+ .insight-error {
2149
+ margin: 0 0 1rem;
2150
+ font-size: 0.85rem;
2151
+ }
2152
+
2153
+ .insight-actions {
2154
+ display: flex;
2155
+ align-items: center;
2156
+ justify-content: space-between;
2157
+ flex-wrap: wrap;
2158
+ gap: 0.5rem;
2159
+ }
2160
+
2161
+ .insight-actions-links {
2162
+ display: flex;
2163
+ align-items: center;
2164
+ gap: 0.75rem;
2165
+ }
2166
+
2167
+ .insight-actions-buttons {
2168
+ display: flex;
2169
+ align-items: center;
2170
+ gap: 0.5rem;
2171
+ }
2172
+
2173
+ .insight-advisory-note {
2174
+ font-size: 0.85rem;
2175
+ color: var(--muted);
2176
+ font-style: italic;
2177
+ }
2178
+
2179
+ .insight-restore-row {
2180
+ text-align: center;
2181
+ margin-top: 2rem;
2182
+ }
2183
+
2184
+ .insight-empty-note {
2185
+ max-width: 26rem;
2186
+ margin: 0 auto 1rem;
2187
+ }
2188
+
2189
+ @media (prefers-reduced-motion: reduce) {
2190
+ .insight-card,
2191
+ .insight-category-header {
2192
+ transition: none;
2193
+ }
2194
+
2195
+ .insight-card:hover {
2196
+ transform: none;
2197
+ }
2198
+ }
2199
+
2200
+ /* --- touch ergonomics ------------------------------------------------------ */
2201
+
2202
+ /* Grow tap targets to ≥44px effective on coarse pointers while keeping the
2203
+ visual glyph sizes unchanged on desktop. The ⓘ button gets an invisible
2204
+ 44px hit circle; text controls get taller padding. */
2205
+ @media (pointer: coarse) {
2206
+ .help-tip > button::after {
2207
+ content: '';
2208
+ position: absolute;
2209
+ left: 50%;
2210
+ top: 50%;
2211
+ width: 2.75rem;
2212
+ height: 2.75rem;
2213
+ transform: translate(-50%, -50%);
2214
+ border-radius: 50%;
2215
+ }
2216
+
2217
+ .btn {
2218
+ padding-top: 0.6rem;
2219
+ padding-bottom: 0.6rem;
2220
+ }
2221
+
2222
+ .model-preset,
2223
+ .dialog-choice {
2224
+ padding-top: 0.8rem;
2225
+ padding-bottom: 0.8rem;
2226
+ }
2227
+
2228
+ .seg button {
2229
+ padding-top: 0.75rem;
2230
+ padding-bottom: 0.75rem;
2231
+ }
2232
+
2233
+ .btn-small {
2234
+ padding-top: 0.68rem;
2235
+ padding-bottom: 0.68rem;
2236
+ }
2237
+
2238
+ .btn-ghost {
2239
+ padding-top: 0.65rem;
2240
+ padding-bottom: 0.65rem;
2241
+ }
2242
+
2243
+ .insight-dismiss {
2244
+ padding: 0.85rem;
2245
+ }
2246
+
2247
+ .rail-link {
2248
+ padding-top: 0.7rem;
2249
+ padding-bottom: 0.7rem;
2250
+ }
2251
+ }
2252
+
2253
+
2254
+ /* ---- Import & migrate wizard (/import) + review checklist ---------------- */
2255
+
2256
+ .import-page {
2257
+ display: grid;
2258
+ gap: 1rem;
2259
+ align-content: start;
2260
+ }
2261
+
2262
+ .import-page > .card-hint {
2263
+ max-width: 75ch;
2264
+ }
2265
+
2266
+ .import-review {
2267
+ margin-top: 0.9rem;
2268
+ border-top: 1px solid var(--border);
2269
+ padding-top: 0.75rem;
2270
+ }
2271
+
2272
+ .import-review-group {
2273
+ margin-top: 0.75rem;
2274
+ }
2275
+
2276
+ .import-review-group h4 {
2277
+ margin: 0 0 0.3rem;
2278
+ font-size: 0.95rem;
2279
+ }
2280
+
2281
+ .import-review-group ul {
2282
+ margin: 0;
2283
+ padding-left: 1.2rem;
2284
+ max-width: 78ch;
2285
+ }
2286
+
2287
+ .import-review-group li {
2288
+ margin: 0.25rem 0;
2289
+ font-size: 0.92rem;
2290
+ }
2291
+
2292
+ /* Attention colors mirror the callout tones: unmapped needs a hand, defaulted needs a look. */
2293
+ .import-review-group--unmapped h4 {
2294
+ color: var(--warn);
2295
+ }
2296
+
2297
+ .import-review-group--defaulted h4 {
2298
+ color: var(--accent);
2299
+ }
2300
+
2301
+ .import-review-group--skipped h4,
2302
+ .import-review-group--skipped li {
2303
+ color: var(--muted);
2304
+ }