diff --git a/README.md b/README.md
index c73a19c2bc5ca1687fcf1b4545d4b34ec0cbd95a..225ae7d74ddf2b264183e92e15b54286a083afa5 100644
--- a/README.md
+++ b/README.md
@@ -58,18 +58,18 @@ Ajouter en haut du fichier :
 Et ensuite utiliser un test :
 
 ```js
-{#if !$billActive}
+{#if !billActive}
   "COUCOU qui s'affiche si le PLF n'est pas activé"
 {/if}
 ```
 
 ```js
-{#if $billActive}
+{#if billActive}
   "COUCOU qui s'affiche si le PLF est activé"
 {/if}
 ```
 
-$billActive => plf activé
+billActive => plf activé
 
 ### Ajouter une variable calculée dans le simulateur
 
diff --git a/package-lock.json b/package-lock.json
index 3da99dfb0866bc2da527fa1a13993473abd3d943..03f82505fb5eaa81acf2b6303a75b3f07eac654c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -58,7 +58,7 @@
         "sanitize-filename": "^1.6.3",
         "scroll-into-view-if-needed": "^3.0.10",
         "slug": "^10.0.0",
-        "svelte": "^5.0.0",
+        "svelte": "^5.1.4",
         "svelte-check": "^4.0.1",
         "svelte-dnd-action": "^0.9.8",
         "svelte-floating-ui": "^1.5.3",
@@ -6189,11 +6189,10 @@
       }
     },
     "node_modules/svelte": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.1.3.tgz",
-      "integrity": "sha512-Sl8UFHlBvF54aK8MElFvyvaUfPE2REOz6LnhR2pBClCL11MU4qpn4V+KgAggaXxDyrP2iQixvHbtpHqL/zXlSQ==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.1.4.tgz",
+      "integrity": "sha512-qgHDV7AyvBZa2pbf+V0tnvWrN1LKD8LdUsBkR/SSYVVN6zXexiXnOy5Pjcjft2y/2NJJVa8ORUHFVn3oiWCLVQ==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@ampproject/remapping": "^2.3.0",
         "@jridgewell/sourcemap-codec": "^1.5.0",
diff --git a/package.json b/package.json
index a9eb13e766a8102ec035f0a0980251432c3b83ce..ec93f406646fe16cf0a9ee129bfe7e5e70ab6f4d 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,7 @@
     "sanitize-filename": "^1.6.3",
     "scroll-into-view-if-needed": "^3.0.10",
     "slug": "^10.0.0",
-    "svelte": "^5.0.0",
+    "svelte": "^5.1.4",
     "svelte-check": "^4.0.1",
     "svelte-dnd-action": "^0.9.8",
     "svelte-floating-ui": "^1.5.3",
diff --git a/src/lib/calculations.svelte.ts b/src/lib/calculations.svelte.ts
index 85ad0fed083d416dfbd319dfb1b98cfcca3cae1c..5ecd8540fd324c515f18f6e7d97981a8b3543486 100644
--- a/src/lib/calculations.svelte.ts
+++ b/src/lib/calculations.svelte.ts
@@ -1,13 +1,11 @@
 import type { Evaluation } from "$lib/decompositions"
 import type { ParametricReform } from "$lib/reforms"
+import publicConfig from "$lib/public_config"
+import { calculateTestCases } from "$lib/shared.svelte"
 import type { VariableValueByCalculationName } from "$lib/variables"
-import { entityByKey } from "./entities"
-import publicConfig from "./public_config"
-import type { SituationWithAxes } from "./situations"
 
 export type CalculationName = "amendment" | "bill" | "law" | "revaluation"
 
-const { reformName, revaluationName } = publicConfig
 export const calculationNames: CalculationName[] = [
   "law",
   "revaluation",
@@ -29,276 +27,6 @@ export let requestedCalculations = $state({
   situationIndexByCalculationName: {},
 }) as RequestedCalculations
 
-function calculateTestCases({}: {
-  situationIndexByCalculationName: RequestedSituationIndexByCalculationName
-}) {
-  const aggregatedSituation: SituationWithAxes = {}
-  const axesData: { situationIndex: number; variables: string[] } =
-    $axes.reduce(
-      (
-        result: { situationIndex?: number; variables: string[] },
-        parallelAxes,
-      ) => {
-        for (const axis of parallelAxes) {
-          result.situationIndex = axis.situationIndex
-          if (result.variables.includes(axis.name)) {
-            continue
-          }
-          result.variables.push(axis.name)
-        }
-        return result
-      },
-      { variables: [] },
-    )
-  const entities = Object.values(entityByKey)
-  if (
-    Object.values(situationIndexByCalculationName).some(
-      (situationIndex) => situationIndex === null,
-    )
-  ) {
-    let personIndex = -1
-    // Some of the calculations are requested to be done for every situations.
-    // Aggregate every situations into a single one without calculated variables.
-    for (const [situationIndex, situation] of $testCases.entries()) {
-      const inputInstantsByVariableName =
-        $inputInstantsByVariableNameArray[situationIndex]
-      const situationPrefix = `Cas type n°${situationIndex + 1} | `
-      for (const entity of entities) {
-        let entitySituation = situation[entity.key_plural as string]
-        if (entitySituation === undefined) {
-          continue
-        }
-        let aggregatedEntitySituation =
-          aggregatedSituation[entity.key_plural as string]
-        if (aggregatedEntitySituation === undefined) {
-          aggregatedEntitySituation = aggregatedSituation[
-            entity.key_plural as string
-          ] = {}
-        }
-        const reservedKeys = getPopulationReservedKeys(entity)
-        for (const [populationId, population] of Object.entries(
-          entitySituation,
-        ).sort(([populationId1], [populationId2]) =>
-          populationId1.localeCompare(populationId2),
-        )) {
-          const transformedPopulation: PopulationWithoutId = {}
-          if (!entity.is_person) {
-            for (const role of (entity as GroupEntity).roles) {
-              const personsIdKey = getRolePersonsIdKey(role)
-              const personsId = population[personsIdKey] as string[] | undefined
-              if (personsId === undefined) {
-                continue
-              }
-              transformedPopulation[personsIdKey] = personsId.map(
-                (personId) => situationPrefix + personId,
-              )
-            }
-          } else {
-            personIndex++
-          }
-          for (const [variableName, variableValueByInstant] of Object.entries(
-            population,
-          )) {
-            if (
-              reservedKeys.has(variableName) ||
-              (entity.is_person &&
-                axesData.situationIndex === personIndex &&
-                axesData.variables.includes(variableName))
-            ) {
-              continue
-            }
-            const inputVariableValueByInstant: {
-              [instant: string]: VariableValue | null
-            } = {}
-            const inputInstants =
-              inputInstantsByVariableName[variableName] ?? new Set<string>()
-            for (const [instant, variableValue] of Object.entries(
-              variableValueByInstant as {
-                [instant: string]: VariableValue | null
-              },
-            )) {
-              if (!inputInstants.has(instant)) {
-                // Ignore calculated value.
-                continue
-              }
-              inputVariableValueByInstant[instant] = variableValue
-            }
-            if (Object.keys(inputVariableValueByInstant).length > 0) {
-              transformedPopulation[variableName] = inputVariableValueByInstant
-            }
-          }
-          aggregatedEntitySituation[situationPrefix + populationId] =
-            transformedPopulation
-        }
-      }
-    }
-
-    if ($axes.length > 0) {
-      aggregatedSituation.axes = $axes
-    }
-  }
-
-  const message = {
-    period: $year.toString(),
-  }
-  const newCalculationByName: CalculationByName = {}
-
-  const lawSituationIndex = situationIndexByCalculationName.law
-  if (lawSituationIndex !== undefined) {
-    const calculation: Calculation = (newCalculationByName.law = {
-      running: true,
-    })
-    let situation: SituationWithAxes
-    if (lawSituationIndex === null) {
-      situation = aggregatedSituation
-    } else {
-      calculation.situationIndex = lawSituationIndex
-      situation = cleanSituation($testCases[lawSituationIndex], $axes)
-    }
-    calculation.input = {
-      ...message,
-      situation,
-      variables: [
-        ...summaryCalculatedVariablesName,
-        ...otherCalculatedVariablesName,
-        ...nonVirtualVariablesName,
-      ],
-    }
-    sendTestCasesSimulation("law", calculation.input) // Don't wait for result.
-  }
-
-  const revaluationSituationIndex = situationIndexByCalculationName.revaluation
-  if (
-    revaluationSituationIndex !== undefined &&
-    revaluationName !== undefined
-  ) {
-    const calculation: Calculation = (newCalculationByName.revaluation = {
-      running: true,
-    })
-    let situation: SituationWithAxes
-    if (revaluationSituationIndex === null) {
-      situation = aggregatedSituation
-    } else {
-      calculation.situationIndex = revaluationSituationIndex
-      situation = cleanSituation($testCases[revaluationSituationIndex], $axes)
-    }
-    calculation.input = {
-      ...message,
-      reform: revaluationName,
-      situation,
-      variables: [
-        ...summaryCalculatedVariablesName,
-        ...otherCalculatedVariablesName,
-        ...(nonVirtualVariablesNameByReformName[revaluationName] ??
-          nonVirtualVariablesName),
-      ],
-    }
-    sendTestCasesSimulation("revaluation", calculation.input) // Don't wait for result.
-  }
-
-  const billSituationIndex = situationIndexByCalculationName.bill
-  if (billSituationIndex !== undefined && $billActive) {
-    const calculation: Calculation = (newCalculationByName.bill = {
-      running: true,
-    })
-    let situation: SituationWithAxes
-    if (billSituationIndex === null) {
-      situation = aggregatedSituation
-    } else {
-      calculation.situationIndex = billSituationIndex
-      situation = cleanSituation($testCases[billSituationIndex], $axes)
-    }
-    calculation.input = {
-      ...message,
-      reform: reformName,
-      situation,
-      variables: [
-        ...summaryCalculatedVariablesName,
-        ...otherCalculatedVariablesName,
-        ...(nonVirtualVariablesNameByReformName[reformName] ??
-          nonVirtualVariablesName),
-      ],
-    }
-    sendTestCasesSimulation("bill", calculation.input) // Don't wait for result.
-  }
-
-  const amendmentSituationIndex = situationIndexByCalculationName.amendment
-  if (amendmentSituationIndex !== undefined) {
-    if (Object.keys($parametricReform).length === 0) {
-      // Remove amendment evaluations from decompositions.
-      $evaluationByNameArray = $evaluationByNameArray.map(
-        (evaluationByName, situationIndex): EvaluationByName => {
-          const updatedEvaluationByName = Object.fromEntries(
-            Object.entries(evaluationByName).map(
-              ([variableName, evaluation]) => {
-                const calculationEvaluationByName = {
-                  ...evaluation.calculationEvaluationByName,
-                }
-                delete calculationEvaluationByName["amendment"]
-                return [
-                  variableName,
-                  { ...evaluation, calculationEvaluationByName },
-                ]
-              },
-            ),
-          )
-          return updateEvaluations(
-            $decompositionByName,
-            updatedEvaluationByName,
-            $testCases[situationIndex].slider?.vectorIndex ?? 0,
-            $vectorLength,
-            waterfalls,
-          )
-        },
-      )
-
-      // Remove amendment values.
-      $valuesByCalculationNameByVariableNameArray =
-        $valuesByCalculationNameByVariableNameArray.map(
-          (valuesByCalculationNameByVariableName) =>
-            Object.fromEntries(
-              Object.entries(valuesByCalculationNameByVariableName).map(
-                ([variableName, valuesByCalculationName]) => {
-                  const updatedValuesByCalculationName = {
-                    ...valuesByCalculationName,
-                  }
-                  delete updatedValuesByCalculationName["amendment"]
-                  return [variableName, updatedValuesByCalculationName]
-                },
-              ),
-            ),
-        )
-    } else {
-      const calculation: Calculation = (newCalculationByName.amendment = {
-        running: true,
-      })
-      let situation: SituationWithAxes
-      if (amendmentSituationIndex === null) {
-        situation = aggregatedSituation
-      } else {
-        calculation.situationIndex = amendmentSituationIndex
-        situation = cleanSituation($testCases[amendmentSituationIndex], $axes)
-      }
-      calculation.input = {
-        ...message,
-        parametric_reform: $parametricReform,
-        reform: reformName ?? revaluationName, // Will be removed when reformName and revaluationName are undefined.
-        situation,
-        variables: [
-          ...summaryCalculatedVariablesName,
-          ...otherCalculatedVariablesName,
-          ...(nonVirtualVariablesNameByReformName[reformName as string] ??
-            nonVirtualVariablesNameByReformName[revaluationName as string] ??
-            nonVirtualVariablesName),
-        ],
-      }
-      sendTestCasesSimulation("amendment", calculation.input) // Don't wait for result.
-    }
-  }
-
-  $calculationByName = newCalculationByName
-}
-
 export function isNullVariableValueByCalculationName(
   variableValueByCalculationName: VariableValueByCalculationName,
 ): boolean {
@@ -318,9 +46,10 @@ export function requestAllBudgetCalculations(variableName: string): void {
   }
 }
 
-export function requestAllTestCasesCalculations(
+export async function requestAllTestCasesCalculations(
   requestedSituationIndex: number | null,
-): void {
+): Promise<void> {
+  $inspect("1")
   if (
     calculationNames.some((calculationName) => {
       const situationIndex =
@@ -330,6 +59,7 @@ export function requestAllTestCasesCalculations(
       )
     })
   ) {
+    $inspect("2")
     calculateTestCases(
       Object.fromEntries(
         calculationNames.map((calculationName) => {
@@ -348,42 +78,31 @@ export function requestAllTestCasesCalculations(
 }
 
 export function requestBudgetCalculation(
-  requestedCalculations: RequestedCalculations,
   variableName: string,
   calculationName: CalculationName,
-): RequestedCalculations {
+): void {
   const budgetCalculationNames =
     variableName === requestedCalculations.budgetVariableName
       ? (requestedCalculations.budgetCalculationNames ??
         new Set<CalculationName>())
       : new Set<CalculationName>()
   if (!budgetCalculationNames.has(calculationName)) {
-    requestedCalculations = {
-      ...requestedCalculations,
-      budgetCalculationNames: budgetCalculationNames.add(calculationName),
-      budgetVariableName: variableName,
-    }
+    requestedCalculations.budgetCalculationNames =
+      budgetCalculationNames.add(calculationName)
+    requestedCalculations.budgetVariableName = variableName
   }
-  return requestedCalculations
 }
 
 export function requestTestCasesCalculation(
-  requestedCalculations: RequestedCalculations,
   calculationName: CalculationName,
   requestedSituationIndex: number | null,
-): RequestedCalculations {
+): void {
   const situationIndex =
     requestedCalculations.situationIndexByCalculationName[calculationName]
   if (situationIndex !== null && situationIndex !== requestedSituationIndex) {
-    requestedCalculations = {
-      ...requestedCalculations,
-      situationIndexByCalculationName: {
-        ...requestedCalculations.situationIndexByCalculationName,
-        [calculationName]: requestedSituationIndex,
-      },
-    }
+    requestedCalculations.situationIndexByCalculationName[calculationName] =
+      requestedSituationIndex
   }
-  return requestedCalculations
 }
 
 export function variableValueByCalculationNameFromEvaluation(
diff --git a/src/lib/components/BudgetConnexionModal.svelte b/src/lib/components/BudgetConnexionModal.svelte
index 7c3f49cfa34f72d636b2e6b22fa6a2c06e5faf4b..ba2e07c9289073a28d73b726a2240d81ac0a3e50 100644
--- a/src/lib/components/BudgetConnexionModal.svelte
+++ b/src/lib/components/BudgetConnexionModal.svelte
@@ -1,17 +1,13 @@
 <script lang="ts">
-  import { run } from "svelte/legacy"
-
   import { Dialog } from "bits-ui"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
-  import { browser } from "$app/environment"
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
   import {
     trackBudgetPublicSimulation,
     trackBudgetSignInButton,
   } from "$lib/matomo"
+  import { shared } from "$lib/shared.svelte"
   import type { CachedSimulation } from "$lib/simulations"
 
   interface Props {
@@ -23,12 +19,6 @@
   let cachedSimulations: CachedSimulation[] = $state([])
   let email = $state("")
   let emailValid = $state(true)
-  const requestedSimulationEmail = getContext(
-    "requestedSimulationEmail",
-  ) as Writable<string | undefined>
-  const requestedSimulationSent = getContext(
-    "requestedSimulationSent",
-  ) as Writable<boolean>
 
   async function fetchCachedSimulations() {
     const res = await fetch("/budgets/simulations/index", {
@@ -47,17 +37,17 @@
     if (!emailValid) {
       return
     }
-    $requestedSimulationEmail = email
+    shared.requestedSimulationEmail = email
     email = ""
   }
-  run(() => {
-    if (browser && isOpen) {
+  $effect(() => {
+    if (isOpen) {
       fetchCachedSimulations()
     }
   })
-  run(() => {
-    if ($requestedSimulationEmail !== undefined) {
-      $requestedSimulationSent = true
+  $effect(() => {
+    if (shared.requestedSimulationEmail !== undefined) {
+      shared.requestedSimulationSent = true
     }
   })
 </script>
@@ -89,10 +79,10 @@
             class="flex items-center gap-2 rounded-md bg-le-bleu px-5 py-2 text-sm font-bold uppercase tracking-[0.085em] text-white shadow-lg hover:bg-blue-800 active:bg-blue-900"
             onclick={() => {
               /*login(
-                      $displayMode,
-                      $inputInstantsByVariableNameArray,
-                      $parametricReform,
-                      $testCases,
+                      shared.displayMode,
+                      shared.inputInstantsByVariableNameArray,
+                      shared.parametricReform,
+                      shared.testCases,
                       encodeURIComponent($page.url.toString()),
                     )*/
               goto("/auth/prepare?action=login")
@@ -136,7 +126,7 @@
               la simulation sera rendue publique. Vous serez alors informé par
               e-mail :
             </p>
-            {#if !$requestedSimulationSent}
+            {#if !shared.requestedSimulationSent}
               <span class="py-2 pl-10 text-sm font-bold"
                 >Votre adresse e-mail :</span
               >
diff --git a/src/lib/components/BudgetSimulationSharingModal.svelte b/src/lib/components/BudgetSimulationSharingModal.svelte
index f192ebaf15f487f78c3a3b1587da49e8a6c8fdcc..5e8018c236dc7636ab89ad85d0ced1f604fb5b59 100644
--- a/src/lib/components/BudgetSimulationSharingModal.svelte
+++ b/src/lib/components/BudgetSimulationSharingModal.svelte
@@ -1,15 +1,14 @@
 <script lang="ts">
+  import { Dialog } from "bits-ui"
   import { run } from "svelte/legacy"
 
-  import { Dialog } from "bits-ui"
-  import { getContext, mount, unmount } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { mount, unmount } from "svelte"
 
-  import type { BudgetSimulation } from "$lib/budgets"
+  import { page } from "$app/stores"
   import CopyClipboard from "$lib/components/CopyClipboard.svelte"
   import type { DisplayMode } from "$lib/displays"
   import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
+  import { shared } from "$lib/shared.svelte"
   import { budgetEditableParametersName } from "$lib/variables"
 
   interface Props {
@@ -18,25 +17,20 @@
   }
 
   const { baseUrl } = publicConfig
+
   let { displayMode, isOpen = $bindable(false) }: Props = $props()
 
-  const budgetSimulation = getContext("budgetSimulation") as Writable<
-    BudgetSimulation | undefined
-  >
   let clipboardElement: HTMLElement = $state()
   let hasClickedCopy = $state(false)
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
 
   let isSimulationShared
   run(() => {
-    isSimulationShared = $budgetSimulation?.isPublic
+    isSimulationShared = shared.budgetSimulation?.isPublic
   })
 
   let url = $derived(
     new URL(
-      `/budgets/simulations/${$budgetSimulation?.hash}`,
+      `/budgets/simulations/${shared.budgetSimulation?.hash}`,
       baseUrl,
     ).toString(),
   )
@@ -77,13 +71,18 @@
   }
 
   async function onChange() {
+    if (shared.budgetSimulation === undefined) {
+      console.error("shared.budgetSimulation is undefined!")
+      return
+    }
+
     const urlString = "/budgets/simulations"
     const res = await fetch(urlString, {
       body: JSON.stringify({
         displayMode,
-        hash: $budgetSimulation?.hash,
+        hash: shared.budgetSimulation.hash,
         parametricReform: Object.fromEntries(
-          Object.entries($parametricReform).filter(([parameterName]) =>
+          Object.entries(shared.parametricReform).filter(([parameterName]) =>
             budgetEditableParametersName.has(parameterName),
           ),
         ),
@@ -102,10 +101,7 @@
       )
       return
     }
-    $budgetSimulation = {
-      ...$budgetSimulation,
-      isPublic: true,
-    }
+    shared.budgetSimulation.isPublic = true
   }
 
   function onClose() {
diff --git a/src/lib/components/ModificationsPanel.svelte b/src/lib/components/ModificationsPanel.svelte
index 77aa46605ef13befc782a077323346dbc7347d40..a6a02a288461d549fcc6ff88382aa6ba130e7b26 100644
--- a/src/lib/components/ModificationsPanel.svelte
+++ b/src/lib/components/ModificationsPanel.svelte
@@ -1,13 +1,10 @@
 <script lang="ts">
   import { ParameterClass, walkParameters } from "@openfisca/json-model"
   import deepEqual from "deep-equal"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import {
     requestAllBudgetCalculations,
     requestAllTestCasesCalculations,
-    type RequestedCalculations,
   } from "$lib/calculations.svelte"
   import PersistentPopover from "$lib/components/PersistentPopover.svelte"
   import ReformsChanges from "$lib/components/ReformsChanges.svelte"
@@ -16,51 +13,26 @@
     type DecompositionByName,
     decompositionCoreByName,
     decompositionCoreByNameByReformName,
-    type EvaluationByName,
   } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { rootParameter, rootParameterByReformName } from "$lib/parameters"
-  import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
+  import { billName, revaluationName, shared } from "$lib/shared.svelte"
   import {
     extractInputInstantsFromTestCases,
-    type Situation,
     testCasesCore,
   } from "$lib/situations"
   import {
     budgetEditableParametersName,
     budgetVariablesName,
-    type ValuesByCalculationNameByVariableName,
   } from "$lib/variables"
 
   interface Props {
     displayMode: DisplayMode
   }
 
-  const { reformName, revaluationName } = publicConfig
   let { displayMode }: Props = $props()
 
-  const decompositionByName = getContext(
-    "decompositionByName",
-  ) as Writable<DecompositionByName>
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
   let isUserModificationsOpen = $state(false)
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
 
   function latestValue(values) {
     return Object.entries(values ?? {}).sort(([instant1], [instant2]) =>
@@ -71,19 +43,20 @@
   function reset(): void {
     isUserModificationsOpen = false
 
-    $testCases = structuredClone(testCasesCore)
-    $decompositionByName = buildDecompositionByNameFromCore(
-      reformName === undefined
+    shared.testCases = structuredClone(testCasesCore)
+    shared.decompositionByName = buildDecompositionByNameFromCore(
+      billName === undefined
         ? decompositionCoreByName
-        : (decompositionCoreByNameByReformName[reformName] ??
+        : (decompositionCoreByNameByReformName[billName] ??
             decompositionCoreByName),
     ) as DecompositionByName
-    $evaluationByNameArray = new Array($testCases.length).fill({})
-    $inputInstantsByVariableNameArray =
-      extractInputInstantsFromTestCases($testCases)
-    $parametricReform = {}
-    $valuesByCalculationNameByVariableNameArray = new Array(
-      $testCases.length,
+    shared.evaluationByNameArray = new Array(shared.testCases.length).fill({})
+    shared.inputInstantsByVariableNameArray = extractInputInstantsFromTestCases(
+      shared.testCases,
+    )
+    shared.parametricReform = {}
+    shared.valuesByCalculationNameByVariableNameArray = new Array(
+      shared.testCases.length,
     ).fill({})
 
     if (
@@ -139,9 +112,9 @@
         ),
   )
   let billParametersFiltered = $derived(
-    reformName === undefined
+    billName === undefined
       ? []
-      : [...walkParameters(rootParameterByReformName[reformName])].filter(
+      : [...walkParameters(rootParameterByReformName[billName])].filter(
           (parameter) => {
             if (parameter.name?.startsWith("inflateurs")) {
               return false
@@ -165,7 +138,7 @@
   )
   let billModificationsCount = $derived(billParametersFiltered.length)
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
   let modificationsCount = $derived(
     modificationsAmendmentCount + billModificationsCount,
@@ -175,7 +148,7 @@
   )
   let showBudgetParametersError = $derived(
     displayMode.budget &&
-      Object.keys($parametricReform).some(
+      Object.keys(shared.parametricReform).some(
         (parameterName) => !budgetEditableParametersName.has(parameterName),
       ),
   )
diff --git a/src/lib/components/NavBar.svelte b/src/lib/components/NavBar.svelte
index e90de7f269b586bd573be6ad4a4e76e5d5453061..648d62bd41bbc04e88e08f1df6710200252cc6b8 100644
--- a/src/lib/components/NavBar.svelte
+++ b/src/lib/components/NavBar.svelte
@@ -1,15 +1,12 @@
 <script lang="ts">
-  import { run } from "svelte/legacy"
-
   // import {
   //   Menu,
   //   MenuButton,
   //   MenuItem,
   //   MenuItems,
   // } from "@rgossiaux/svelte-headlessui"
+  import { DropdownMenu } from "bits-ui"
   import type { SearchResult } from "minisearch"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
   import { fade } from "svelte/transition"
 
   import { browser } from "$app/environment"
@@ -19,16 +16,13 @@
   import { withLinkedVariableNames } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { trackSearchVariable } from "$lib/matomo"
-  import type { NavbarConfig } from "$lib/navbar"
   import publicConfig from "$lib/public_config"
   import WithLinkedVariablesSearchWorker from "$lib/search/search_worker_variables_with_linked?worker"
+  import { billActive, shared, yearPLF } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
 
   const { portalUrl } = publicConfig
-  const billActive = getContext("billActive") as Writable<boolean>
-  const displayMode = getContext("displayMode") as Writable<
-    DisplayMode | undefined
-  >
+
   const dispositifsTypes = [
     {
       title: "Impôt sur le revenu",
@@ -72,20 +66,13 @@
       parametersVariableName: "exoneration_cotisations_employeur_tode",
     },
   ]
-  const searchActive = getContext("searchActive") as Writable<boolean>
   let isSearchInProgress = false
   let focused = $state(false)
   let pendingQuery: string | null = null
   let preventBlur = $state(false)
-  const searchVariableName = getContext("searchVariableName") as Writable<
-    string | undefined
-  >
   let searchQuery = $state("")
   let searchResults: SearchResult[] = $state([])
   let searchWorker: Worker | undefined = undefined
-  const showTutorial = getContext("showTutorial") as Writable<boolean>
-  const navbarConfig = getContext("navbarConfig") as Writable<NavbarConfig>
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   if (browser) {
     searchWorker = new WithLinkedVariablesSearchWorker()
@@ -108,18 +95,18 @@
   function help() {
     if ($page.route.id === "/") {
       if (
-        $displayMode?.parametersVariableName === undefined ||
-        ($displayMode?.testCasesIndex.length ?? 0) === 0
+        shared.displayMode?.parametersVariableName === undefined ||
+        (shared.displayMode?.testCasesIndex.length ?? 0) === 0
       ) {
         goto(
           newSimulationUrl({
-            ...$displayMode,
+            ...shared.displayMode,
             parametersVariableName:
-              $displayMode?.parametersVariableName ?? "irpp_economique",
+              shared.displayMode?.parametersVariableName ?? "irpp_economique",
             testCasesIndex:
-              ($displayMode?.testCasesIndex.length ?? 0) === 0
+              (shared.displayMode?.testCasesIndex.length ?? 0) === 0
                 ? [0]
-                : $displayMode?.testCasesIndex,
+                : shared.displayMode?.testCasesIndex,
           } as DisplayMode),
         )
       }
@@ -131,7 +118,7 @@
         } as DisplayMode),
       )
     }
-    $showTutorial = true
+    shared.showTutorial = true
     localStorage.removeItem("hideTutorial")
   }
 
@@ -152,19 +139,22 @@
   let { authenticationEnabled, user } = $derived(data)
   let loginUrl = $derived(`/auth/prepare?action=login`)
   let logoutUrl = $derived(`/auth/prepare?action=logout`)
-  run(() => {
-    if ($searchActive) {
+  $effect(() => {
+    if (shared.searchActive) {
       search(searchQuery)
     } else {
       searchResults = []
     }
   })
+
+  let isAccueilDropdownOpen = $state(false)
+  let isTutorielDropdownOpen = $state(false)
 </script>
 
-<!--class:relative={$navbarConfig.position === "relative"}-->
+<!--class:relative={shared.navbarConfig.position === "relative"}-->
 <nav
   class="z-50 w-full md:top-0"
-  class:fixed={$navbarConfig.position === "fixed"}
+  class:fixed={shared.navbarConfig.position === "fixed"}
 >
   <div
     class="mx-auto bg-le-jaune-very-dark px-2 shadow-md md:h-12 md:px-3 2xl:h-14"
@@ -182,15 +172,15 @@
             alt="Logo de l'Assemblée nationale"
           />
 
-          <!-- Tutoriel Dropdown -->
-          <!-- <Menu let:open>
-            <MenuButton
+          <!-- Accueil Dropdown -->
+          <DropdownMenu.Root bind:open={isAccueilDropdownOpen}>
+            <DropdownMenu.Trigger
               class="cursor-pointer overflow-hidden rounded-lg text-sm uppercase text-white hover:bg-gray-400 hover:bg-opacity-20 focus:outline-none active:bg-gray-400 active:bg-opacity-40"
             >
               <div
                 class="py-2 pl-2 pr-3 lg:pl-4"
-                class:bg-gray-400={open}
-                class:bg-opacity-40={open}
+                class:bg-gray-400={isAccueilDropdownOpen}
+                class:bg-opacity-40={isAccueilDropdownOpen}
               >
                 <span class="flex items-center gap-1.5">
                   <span class="flex-col items-center">
@@ -201,39 +191,48 @@
                   </span><iconify-icon
                     class="mr-1 flex align-[-0.2rem] text-lg lg:hidden"
                     icon="ri:home-2-fill"
-                  />
-                  <iconify-icon class="text-2xl" icon="ri:arrow-down-s-line" />
+                  ></iconify-icon>
+                  <iconify-icon class="text-2xl" icon="ri:arrow-down-s-line"
+                  ></iconify-icon>
                 </span>
               </div>
-            </MenuButton>
-            <MenuItems
-              class="absolute left-5 top-0 z-50 mr-6 mt-14 w-64 rounded bg-white text-black shadow-xl ring-1 ring-black ring-opacity-5 focus:outline-none"
+            </DropdownMenu.Trigger>
+            <DropdownMenu.Content
+              class="absolute z-50 mr-6 mt-2 w-64 -translate-x-1/2 rounded bg-white text-black shadow-xl ring-1 ring-black ring-opacity-5 focus:outline-none"
             >
-              <MenuItem
-                as="a"
-                class="block cursor-pointer  border-b px-4 py-3 text-center text-sm uppercase tracking-wider hover:bg-gray-100"
-                href="/accueil"
-              >
-                Accueil simulateur
-              </MenuItem>
+              <DropdownMenu.Item>
+                {#snippet child({ props })}
+                  <a
+                    class="block cursor-pointer border-b px-4 py-3 text-center text-sm uppercase tracking-wider hover:bg-gray-100"
+                    href="/accueil"
+                    {...props}
+                  >
+                    Accueil simulateur
+                  </a>
+                {/snippet}
+              </DropdownMenu.Item>
 
-              <MenuItem
-                as="a"
-                class="block cursor-pointer border-b px-4 py-3 text-center hover:bg-gray-100"
-                href={portalUrl}
-              >
-                <iconify-icon
-                  class="mr-1 align-[-0.2rem] text-lg"
-                  icon="ri:home-2-line"
-                />Accueil LexImpact<iconify-icon
-                  class="align-[-0.25rem] text-xl"
-                  icon="ri:arrow-right-up-line"
-                />
-              </MenuItem>
-            </MenuItems>
-          </Menu> -->
+              <DropdownMenu.Item>
+                {#snippet child({ props })}
+                  <a
+                    class="block cursor-pointer border-b px-4 py-3 text-center hover:bg-gray-100"
+                    href={portalUrl}
+                    {...props}
+                  >
+                    <iconify-icon
+                      class="mr-1 align-[-0.2rem] text-lg"
+                      icon="ri:home-2-line"
+                    ></iconify-icon>Accueil LexImpact<iconify-icon
+                      class="align-[-0.25rem] text-xl"
+                      icon="ri:arrow-right-up-line"
+                    ></iconify-icon>
+                  </a>
+                {/snippet}
+              </DropdownMenu.Item>
+            </DropdownMenu.Content>
+          </DropdownMenu.Root>
         </div>
-        {#if $navbarConfig.showSearch}
+        {#if shared.navbarConfig.showSearch}
           <!-- Logo -->
           <a
             href="/"
@@ -255,12 +254,12 @@
                 Socio-Fiscal
               </span>
             </div>
-            {#if $billActive}
+            {#if billActive}
               <div
                 class="m-1 flex -rotate-6 flex-col rounded-sm bg-white p-0.5 px-1 pt-0 text-[0.62rem] text-le-gris-dispositif-dark shadow-lg"
               >
                 <span class="leading-4">Prévisions</span><span
-                  class="text-[1.2rem] font-bold leading-4">{$yearPLF}</span
+                  class="text-[1.2rem] font-bold leading-4">{yearPLF}</span
                 >
               </div>
             {/if}
@@ -268,14 +267,14 @@
         {/if}
       </div>
 
-      {#if $navbarConfig.showSearch}
+      {#if shared.navbarConfig.showSearch}
         <div
           in:fade={{ duration: 100, delay: 100 }}
           out:fade={{ duration: 100 }}
         >
           <!-- Bloc centre pour la barre de recherche -->
           <NavBarSearch
-            bind:active={$searchActive}
+            bind:active={shared.searchActive}
             bind:query={searchQuery}
             on:blur={() => {
               if (!preventBlur) {
@@ -287,7 +286,7 @@
         </div>
       {/if}
 
-      {#if !$navbarConfig.showSearch}
+      {#if !shared.navbarConfig.showSearch}
         <div
           class="pointer-events-none absolute inset-0 mx-auto flex h-full items-center justify-center gap-2 uppercase text-white"
           in:fade={{ duration: 100, delay: 150 }}
@@ -312,83 +311,101 @@
       <!-- Bloc droite pour les commandes avancées-->
       <ul class="flex basis-1/3 items-center justify-end gap-2 pr-2 xl:gap-5">
         <!-- Tutoriel Dropdown -->
-        <!-- <Menu let:open>
-          <MenuButton
+        <DropdownMenu.Root bind:open={isTutorielDropdownOpen}>
+          <DropdownMenu.Trigger
             class="cursor-pointer overflow-hidden rounded-lg text-sm uppercase text-white hover:bg-gray-400 hover:bg-opacity-20 focus:outline-none active:bg-gray-400 active:bg-opacity-40"
           >
             <div
               class="py-2 pl-4 pr-3"
-              class:bg-gray-400={open}
-              class:bg-opacity-40={open}
+              class:bg-gray-400={isTutorielDropdownOpen}
+              class:bg-opacity-40={isTutorielDropdownOpen}
             >
               <span class="flex items-center gap-1.5">
                 <iconify-icon
                   class="align-[-0.3rem] text-xl"
                   icon="ri-question-fill"
-                /> <span class="hidden xl:inline-flex">Tutoriel</span>
-                <iconify-icon class="text-2xl" icon="ri:arrow-down-s-line" />
+                ></iconify-icon>
+                <span class="hidden xl:inline-flex">Tutoriel</span>
+                <iconify-icon class="text-2xl" icon="ri:arrow-down-s-line"
+                ></iconify-icon>
               </span>
             </div>
-          </MenuButton>
-          <MenuItems
-            class="absolute right-0 top-0 z-50 mr-6 mt-14 w-64 rounded bg-white text-black shadow-xl ring-1 ring-black ring-opacity-5 focus:outline-none"
+          </DropdownMenu.Trigger>
+          <DropdownMenu.Content
+            class="absolute z-50 mr-6 mt-2 w-64 -translate-x-1/2 rounded bg-white text-black shadow-xl ring-1 ring-black ring-opacity-5 focus:outline-none"
           >
-            <MenuItem
-              as="a"
-              class="block cursor-pointer border-b px-4 py-3 hover:bg-gray-100"
-              href="/accueil#impacts-budgetaires"
-            >
-              <iconify-icon
-                class="mr-1 align-[-0.25rem] text-xl"
-                icon="ri-list-check-3"
-              /> Présentation des fonctionnalités
-            </MenuItem>
-            <MenuItem
-              as="a"
-              class="group hidden cursor-pointer border-b px-4 py-3 hover:bg-gray-100 md:block"
-              on:click={help}
-            >
-              <iconify-icon
-                class="mr-1 align-[-0.25rem] text-xl"
-                icon="ri:drag-drop-line"
-              />Tutoriel interactif
-              <br /><span
-                class="lx-link-uppercase hidden group-hover:flex group-hover:underline"
-                >commencer<iconify-icon
-                  class="mr-1 align-[-0.25rem] text-xl"
-                  icon="ri:arrow-right-line"
-                /></span
-              >
-            </MenuItem>
-            <MenuItem
-              as="a"
-              class="block cursor-pointer border-b px-4 py-3 hover:bg-gray-100"
-              aria-label="Tutoriels vidéos sur le site Dailymotion"
-              href="https://www.dailymotion.com/leximpact.an.fr"
-              target="_blank"
-            >
-              <iconify-icon
-                class="mr-1 align-[-0.25rem] text-xl"
-                icon="ri:video-line"
-              />
-              Tutoriels vidéos
-              <iconify-icon
-                class="ml-0.5 align-[-0.15rem] text-base"
-                icon="ri:external-link-line"
-              />
-            </MenuItem>
-            <MenuItem
-              as="a"
-              class="block cursor-pointer border-b px-4 py-3 hover:bg-gray-100"
-              href="/fonctionnement"
-            >
-              <iconify-icon
-                class="mr-1 align-[-0.25rem] text-xl"
-                icon="ri-database-line"
-              />Méthode de calcul et traitement des données
-            </MenuItem>
-          </MenuItems>
-        </Menu> -->
+            <DropdownMenu.Item>
+              {#snippet child({ props })}
+                <a
+                  class="block cursor-pointer border-b px-4 py-3 hover:bg-gray-100"
+                  href="/accueil#impacts-budgetaires"
+                  {...props}
+                >
+                  <iconify-icon
+                    class="mr-1 align-[-0.25rem] text-xl"
+                    icon="ri-list-check-3"
+                  ></iconify-icon> Présentation des fonctionnalités
+                </a>
+              {/snippet}
+            </DropdownMenu.Item>
+            <DropdownMenu.Item>
+              {#snippet child({ props })}
+                <button
+                  class="group hidden w-full cursor-pointer border-b px-4 py-3 text-start hover:bg-gray-100 md:block"
+                  onclick={help}
+                  {...props}
+                >
+                  <iconify-icon
+                    class="mr-1 align-[-0.25rem] text-xl"
+                    icon="ri:drag-drop-line"
+                  />Tutoriel interactif
+                  <br /><span
+                    class="lx-link-uppercase hidden group-hover:flex group-hover:underline"
+                    >commencer<iconify-icon
+                      class="mr-1 align-[-0.25rem] text-xl"
+                      icon="ri:arrow-right-line"
+                    /></span
+                  >
+                </button>
+              {/snippet}
+            </DropdownMenu.Item>
+            <DropdownMenu.Item>
+              {#snippet child({ props })}
+                <a
+                  class="block cursor-pointer border-b px-4 py-3 hover:bg-gray-100"
+                  aria-label="Tutoriels vidéos sur le site Dailymotion"
+                  href="https://www.dailymotion.com/leximpact.an.fr"
+                  target="_blank"
+                  {...props}
+                >
+                  <iconify-icon
+                    class="mr-1 align-[-0.25rem] text-xl"
+                    icon="ri:video-line"
+                  />
+                  Tutoriels vidéos
+                  <iconify-icon
+                    class="ml-0.5 align-[-0.15rem] text-base"
+                    icon="ri:external-link-line"
+                  />
+                </a>
+              {/snippet}
+            </DropdownMenu.Item>
+            <DropdownMenu.Item>
+              {#snippet child({ props })}
+                <a
+                  class="block cursor-pointer border-b px-4 py-3 hover:bg-gray-100"
+                  href="/fonctionnement"
+                  {...props}
+                >
+                  <iconify-icon
+                    class="mr-1 align-[-0.25rem] text-xl"
+                    icon="ri-database-line"
+                  />Méthode de calcul et traitement des données
+                </a>
+              {/snippet}
+            </DropdownMenu.Item>
+          </DropdownMenu.Content>
+        </DropdownMenu.Root>
 
         <!-- Bouton se connecter -->
 
@@ -471,12 +488,12 @@
             <span class="font-light leading-4">LexImpact</span>
             <span class="text-lg leading-5">Socio-Fiscal</span>
           </div>
-          {#if $billActive}
+          {#if billActive}
             <div
               class="m-1 flex -rotate-6 flex-col rounded-sm bg-white p-0.5 px-1 py-0 text-[0.62rem] text-le-gris-dispositif-dark shadow-lg"
             >
               <span class="leading-4">Prévisions</span><span
-                class="text-[1.2rem] font-bold leading-4">{$yearPLF}</span
+                class="text-[1.2rem] font-bold leading-4">{yearPLF}</span
               >
             </div>
           {/if}
@@ -606,7 +623,7 @@
       </div>
 
       <NavBarSearch
-        bind:active={$searchActive}
+        bind:active={shared.searchActive}
         bind:query={searchQuery}
         on:blur={() => {
           if (!preventBlur) {
@@ -618,14 +635,14 @@
     </div>
   </div>
 
-  {#if focused || $searchActive}
+  {#if focused || shared.searchActive}
     <div
       class="absolute inset-0 -z-10 bg-[rgba(0,0,0,.3)] transition-all"
     ></div>
     <div
       class="absolute top-24 w-full overflow-hidden rounded-b-lg border bg-white shadow-lg md:left-[calc((100%-350px)/2)] md:top-12 md:w-[350px] lg:left-[calc((100%-500px)/2)] lg:w-[500px] 2xl:left-[calc((100%-600px)/2)] 2xl:top-14 2xl:w-[600px]"
     >
-      {#if $searchActive}
+      {#if shared.searchActive}
         <ul class="max-h-56 list-none overflow-y-auto py-2 md:max-h-[80vh]">
           {#if searchResults.length > 0}
             {#each searchResults as variable, index (`found_variable_$${index}`)}
@@ -639,7 +656,7 @@
                       searchResults.length,
                     )
                     searchQuery = ""
-                    $searchVariableName = variable.name
+                    shared.searchVariableName = variable.name
                   }}
                 >
                   <span
@@ -670,7 +687,7 @@
               <button
                 class="flex w-full items-center gap-3 px-3 py-1 transition hover:bg-gray-200/70 active:bg-gray-200 2xl:py-3"
                 onclick={() => {
-                  $searchVariableName = dispositif.parametersVariableName
+                  shared.searchVariableName = dispositif.parametersVariableName
                   focused = false
                 }}
                 onmousedown={() => (preventBlur = true)}
diff --git a/src/lib/components/ReformsChanges.svelte b/src/lib/components/ReformsChanges.svelte
index c8f5d9a514cf33547983bef448a013ba25cde861..179d9a64faf97d52e6e1b01be5afc617f6b70e75 100644
--- a/src/lib/components/ReformsChanges.svelte
+++ b/src/lib/components/ReformsChanges.svelte
@@ -10,11 +10,8 @@
     ParameterClass,
     type Variable,
   } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import Tooltip from "$lib/components/Tooltip.svelte"
-  import type { DecompositionByName } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import {
     asValueParameter,
@@ -22,11 +19,15 @@
     rootParameter,
     rootParameterByReformName,
   } from "$lib/parameters"
-  import publicConfig from "$lib/public_config"
+  import { ParameterReformChangeType } from "$lib/reforms"
   import {
-    ParameterReformChangeType,
-    type ParametricReform,
-  } from "$lib/reforms"
+    billActive,
+    billName,
+    budgetDate,
+    revaluationName,
+    shared,
+    yearPLF,
+  } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
   import { formatValue } from "$lib/values"
   import {
@@ -41,24 +42,14 @@
     revaluationParametersFiltered: Parameter[]
   }
 
-  const { reformName, revaluationName } = publicConfig
   let {
     billParametersFiltered,
     displayMode,
     revaluationParametersFiltered,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
   let billParametersListOpen = $state(false)
-  const budgetDate = getContext("budgetDate") as Writable<string>
-  const decompositionByName = getContext(
-    "decompositionByName",
-  ) as Writable<DecompositionByName>
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
   let revaluationParametersListOpen = $state(false)
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   function buildVariableByParameter(parameterById: {
     [id: string]: Parameter
@@ -108,13 +99,13 @@
       : undefined
   }
   // $: billChanges =
-  //   reformName === undefined ? undefined : reformChangesByName[reformName]
+  //   billName === undefined ? undefined : reformChangesByName[$billName]
 
   // Note: A reform parameters tree is always more complete than a parameters tree before reform.
   // And the children of a reform node parameter always contain the children of the node parameter
   // before reform (albeit with some different value parameters).
   let billRootParameter = $derived(
-    rootParameterByReformName[reformName] ?? rootParameter,
+    rootParameterByReformName[billName] ?? rootParameter,
   )
   // function* walkParametersChangeName(parameterChange, ids: string[] = []) {
   //   if (Object.keys(parameterChange).length === 1) {
@@ -141,11 +132,11 @@
   // Note: A reform variable is always more complete than a variable before reform.
   // But it may contain different formulas, with different parameters & variables.
   let billVariableSummaryByName = $derived(
-    variableSummaryByNameByReformName[reformName] ?? variableSummaryByName,
+    variableSummaryByNameByReformName[billName] ?? variableSummaryByName,
   )
   let decompositionVariableSummaryByName = $derived(
     Object.fromEntries(
-      Object.keys($decompositionByName).reduce(
+      Object.keys(shared.decompositionByName).reduce(
         (arr: [string, Variable][], variableName: string) => {
           const variableSummary: Variable | undefined =
             billVariableSummaryByName[variableName]
@@ -163,7 +154,7 @@
   //   Object.entries(decompositionVariableSummaryByName)
   //     .map(([variableName, variableSummary]) => {
   //       const parametersName = new Set(
-  //         iterVariableParametersName(variableSummary, $budgetDate),
+  //         iterVariableParametersName(variableSummary, budgetDate),
   //       )
   //       const rootParameterById = mergeParameters(
   //         [...parametersName].map((name) =>
@@ -188,7 +179,7 @@
       Object.entries(decompositionVariableSummaryByName)
         .map(([variableName, variableSummary]) => {
           const directParametersName = new Set(
-            getVariableFormula(variableSummary, $budgetDate)?.parameters ?? [],
+            getVariableFormula(variableSummary, budgetDate)?.parameters ?? [],
           )
           const rootDirectParameterById = mergeParameters(
             [...directParametersName].map((name) =>
@@ -245,12 +236,12 @@
   )
 </script>
 
-{#if $billActive}
+{#if billActive}
   <div class="p-2 lg:px-4">
     {#if revaluationParametersFiltered.length !== 0}
       <div class="mb-4">
         <h4 class="text-sm font-bold text-le-gris-dispositif-dark lg:text-sm">
-          Droit attendu en {$yearPLF}&nbsp;:
+          Droit attendu en {yearPLF}&nbsp;:
         </h4>
         <button
           class="mt-1 text-left text-xs text-le-gris-dispositif-dark"
@@ -379,7 +370,7 @@
     {/if}
 
     <h4 class="text-sm font-bold text-le-rouge-bill lg:text-sm">
-      PLF et PLFSS {$yearPLF}&nbsp;:
+      PLF et PLFSS {yearPLF}&nbsp;:
     </h4>
 
     <button
@@ -485,9 +476,9 @@
                     {parameter?.titles?.filter(Boolean).join(" > ")}
                     <br /><br />
                     <span>
-                      Indexation d'usage par le PLF {$yearPLF} à {getInflatorLatestValueFormatted(
+                      Indexation d'usage par le PLF {yearPLF} à {getInflatorLatestValueFormatted(
                         parameter,
-                        reformName,
+                        billName,
                       )}
                     </span>
                   </div>
@@ -503,7 +494,7 @@
       ></div>
     {/if}
     <!-- <h5 class="text-sm">
-      {reformMetadataByName[reformName].label}&nbsp;:
+      {reformMetadataByName[billName].label}&nbsp;:
     </h5>
     <ul class="list-inside">
       {#each Object.values(billChanges?.editable_processed_parameters ?? {}) as rootParameterChange}
@@ -538,7 +529,7 @@
     Votre <span class="bg-le-jaune">réforme&nbsp;:</span>
   </h4>
 
-  {#if Object.keys($parametricReform).length === 0}
+  {#if Object.keys(shared.parametricReform).length === 0}
     <p
       class="my-3 bg-gray-200 text-center text-xs italic leading-relaxed text-gray-600 lg:text-sm"
     >
@@ -546,7 +537,7 @@
     </p>
   {:else}
     <ul class="list-inside">
-      {#each Object.entries($parametricReform) as [parameterName, parameterReform]}
+      {#each Object.entries(shared.parametricReform) as [parameterName, parameterReform]}
         {@const parameter = getParameter(billRootParameter, parameterName)}
         {@const tooltipId = `modification-reforme-${parameterName.replace(
           /\./g,
diff --git a/src/lib/components/TestComponent.svelte b/src/lib/components/TestComponent.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..7dfcd36cdb64553693558a1d9a22c4eef77a9479
--- /dev/null
+++ b/src/lib/components/TestComponent.svelte
@@ -0,0 +1,14 @@
+<script lang="ts">
+  let { variable } = $props()
+
+  const yFromQuantile = (_variableA: string = variable.a) => {
+    return _variableA
+  }
+
+  const arr = [0, 1, 2]
+</script>
+
+{#each arr as item}
+  {@const val = yFromQuantile()}
+  {val}
+{/each}
diff --git a/src/lib/components/ValueChange.svelte b/src/lib/components/ValueChange.svelte
index 28f49c4f0366ec804399f4dc31222a88dfc40f45..c5ab00eb2401a48fb845cb4948dc1301bc1f2f25 100644
--- a/src/lib/components/ValueChange.svelte
+++ b/src/lib/components/ValueChange.svelte
@@ -1,9 +1,5 @@
 <script lang="ts">
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
-  import type { ParametricReform } from "$lib/reforms"
-  import { type CalculationByName } from "$lib/situations"
+  import { billActive, shared, yearPLF } from "$lib/shared.svelte"
   import { valueFormatter } from "$lib/values"
   import type { VariableValueByCalculationName } from "$lib/variables"
 
@@ -27,15 +23,6 @@
     valueByCalculationName,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const yearPLF = getContext("yearPLF") as Writable<number>
-
   function mustShowAmendmentValue(
     amendmentValueFormatted: string | undefined,
     billValueFormatted: string | undefined,
@@ -72,12 +59,12 @@
   )
   let format = $derived(valueFormatter(baseValue, unitName, compact))
   let runningCalculationNames = $derived(
-    Object.entries($calculationByName)
+    Object.entries(shared.calculationByName)
       .filter(([, calculation]) => calculation.running)
       .map(([calculationName]) => calculationName),
   )
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
   let amendmentValueFormatted = $derived(
     amendmentValue === undefined ? undefined : format(amendmentValue),
@@ -125,11 +112,11 @@
         class="w-24 text-xs font-normal underline decoration-dotted"
         class:block={!inline}
         title={billValue
-          ? `Droit attendu en ${$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS ${$yearPLF}.`
-          : `Droit en vigueur en ${$yearPLF - 1}`}
+          ? `Droit attendu en ${yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS ${yearPLF}.`
+          : `Droit en vigueur en ${yearPLF - 1}`}
       >
-        {#if $billActive}
-          Droit {$yearPLF} <br />sans PLF/PLSS
+        {#if billActive}
+          Droit {yearPLF} <br />sans PLF/PLSS
         {:else}
           Droit&nbsp;en&nbsp;vigueur
         {/if}
@@ -153,11 +140,11 @@
         class="w-24 text-xs font-normal underline decoration-dotted"
         class:block={!inline}
         title={billValue
-          ? `Droit attendu en ${$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS ${$yearPLF}.`
-          : `Droit en vigueur en ${$yearPLF - 1}`}
+          ? `Droit attendu en ${yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS ${yearPLF}.`
+          : `Droit en vigueur en ${yearPLF - 1}`}
       >
-        {#if $billActive}
-          Droit {$yearPLF} <br />sans PLF/PLSS
+        {#if billActive}
+          Droit {yearPLF} <br />sans PLF/PLSS
         {:else}
           Droit&nbsp;en&nbsp;vigueur
         {/if}
@@ -178,7 +165,7 @@
         class="text-xs font-normal text-le-rouge-bill"
         class:block={!inline}
       >
-        PLF/PLFSS {$yearPLF}
+        PLF/PLFSS {yearPLF}
         <br />
       </span>
     {/if}
@@ -197,7 +184,7 @@
         class="text-xs font-normal text-le-rouge-bill"
         class:block={!inline}
       >
-        PLF/PLFSS {$yearPLF}
+        PLF/PLFSS {yearPLF}
         <br />
       </span>
     {/if}
diff --git a/src/lib/components/ValueChangeCompare.svelte b/src/lib/components/ValueChangeCompare.svelte
index f7e305282d9456b1f398eacef2273d4ed495ffbb..c8f6d45ee949e40e3dd015af0ab3ed6faeb896df 100644
--- a/src/lib/components/ValueChangeCompare.svelte
+++ b/src/lib/components/ValueChangeCompare.svelte
@@ -1,9 +1,5 @@
 <script lang="ts">
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
-  import type { ParametricReform } from "$lib/reforms"
-  import type { CalculationByName } from "$lib/situations"
+  import { billActive, shared, yearPLF } from "$lib/shared.svelte"
   import { valueFormatter } from "$lib/values"
   import type { VariableValueByCalculationName } from "$lib/variables"
 
@@ -23,15 +19,6 @@
     valueByCalculationName1,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const yearPLF = getContext("yearPLF") as Writable<number>
-
   function mustShowAmendmentValue(
     amendmentValueFormatted: string | undefined,
     billValueFormatted: string | undefined,
@@ -147,12 +134,12 @@
   let showLawValue0 = $derived(lawValue0Formatted !== undefined)
   let showLawValue1 = $derived(lawValue1Formatted !== undefined)
   let runningCalculationNames = $derived(
-    Object.entries($calculationByName)
+    Object.entries(shared.calculationByName)
       .filter(([, calculation]) => calculation.running)
       .map(([calculationName]) => calculationName),
   )
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
 </script>
 
@@ -165,10 +152,10 @@
       {#if legend}
         <div
           class="ml-1 text-xs font-normal underline decoration-dotted"
-          title="Droit attendu en {$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {$yearPLF}"
+          title="Droit attendu en {yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {yearPLF}"
         >
-          {#if $billActive}
-            Droit {$yearPLF} <br />sans PLF/PLSS
+          {#if billActive}
+            Droit {yearPLF} <br />sans PLF/PLSS
           {:else}
             Droit&nbsp;en&nbsp;vigueur
           {/if}
@@ -192,10 +179,10 @@
         {#if legend}
           <div
             class="ml-1 text-xs font-normal underline decoration-dotted"
-            title="Droit attendu en {$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {$yearPLF}"
+            title="Droit attendu en {yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {yearPLF}"
           >
-            {#if $billActive}
-              Droit {$yearPLF} <br />sans PLF/PLSS
+            {#if billActive}
+              Droit {yearPLF} <br />sans PLF/PLSS
             {:else}
               Droit&nbsp;en&nbsp;vigueur
             {/if}
@@ -219,10 +206,10 @@
           {#if legend}
             <div
               class="ml-1 self-center text-xs font-normal text-gray-500 underline decoration-dotted"
-              title="Droit attendu en {$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {$yearPLF}."
+              title="Droit attendu en {yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {yearPLF}."
             >
-              {#if $billActive}
-                Droit {$yearPLF} <br />sans PLF/PLSS
+              {#if billActive}
+                Droit {yearPLF} <br />sans PLF/PLSS
               {:else}
                 Droit&nbsp;en&nbsp;vigueur
               {/if}
@@ -244,10 +231,10 @@
           {#if legend}
             <div
               class="ml-1 self-center text-xs font-normal text-gray-500 underline decoration-dotted"
-              title="Droit attendu en {$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {$yearPLF}."
+              title="Droit attendu en {yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {yearPLF}."
             >
-              {#if $billActive}
-                Droit {$yearPLF} <br />sans PLF/PLSS
+              {#if billActive}
+                Droit {yearPLF} <br />sans PLF/PLSS
               {:else}
                 Droit&nbsp;en&nbsp;vigueur
               {/if}
@@ -265,7 +252,7 @@
       </div>
       {#if legend}
         <div class="ml-1 text-xs font-normal text-le-rouge-bill">
-          PLF/PLFSS {$yearPLF}
+          PLF/PLFSS {yearPLF}
           <br />
         </div>
       {/if}
@@ -283,7 +270,7 @@
         </div>
         {#if legend}
           <div class="ml-1 text-xs font-normal text-le-rouge-bill">
-            PLF/PLFSS {$yearPLF}
+            PLF/PLFSS {yearPLF}
             <br />
           </div>
         {/if}
@@ -301,7 +288,7 @@
             <div
               class="ml-1 self-center text-xs font-normal text-le-rouge-bill"
             >
-              PLF/PLFSS {$yearPLF}
+              PLF/PLFSS {yearPLF}
               <br />
             </div>
           {/if}
@@ -317,7 +304,7 @@
             <div
               class="ml-1 self-center text-xs font-normal text-le-rouge-bill"
             >
-              PLF/PLFSS {$yearPLF}
+              PLF/PLFSS {yearPLF}
               <br />
             </div>
           {/if}
diff --git a/src/lib/components/ValueChangeGagnantsPerdants.svelte b/src/lib/components/ValueChangeGagnantsPerdants.svelte
index 634f513ddb8f3c4427f7a8ab5e194454c781a931..e0f64744d5577df213d5136fee2184cc165f5bd2 100644
--- a/src/lib/components/ValueChangeGagnantsPerdants.svelte
+++ b/src/lib/components/ValueChangeGagnantsPerdants.svelte
@@ -1,13 +1,11 @@
 <script lang="ts">
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
   import Tooltip from "$lib/components/Tooltip.svelte"
   import { valueFormatter } from "$lib/values"
   import type {
     BudgetVariableType,
     VariableValueByCalculationName,
   } from "$lib/variables"
+  import { yearPLF } from "$lib/shared.svelte"
 
   interface Props {
     augmentation?: boolean
@@ -33,7 +31,6 @@
   let entityTypeName = variableType === "prestation" ? "ménage" : "foyer fiscal"
   let entitiesTypeName =
     variableType === "prestation" ? "ménages" : "foyers fiscaux"
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   let amendmentLawValue = $derived(
     valueByCalculationName.amendment_law as number | undefined | null,
@@ -129,7 +126,7 @@
         >
 
         <span class="text-sm underline decoration-dotted"
-          >par rapport au droit {$yearPLF} sans PLF</span
+          >par rapport au droit {yearPLF} sans PLF</span
         >.
         <br />
         {#if showAmendmentValue}
@@ -161,11 +158,11 @@
             ></iconify-icon></span
           >
           <span class="text-sm underline decoration-dotted"
-            >par rapport au droit {$yearPLF} sans PLF</span
+            >par rapport au droit {yearPLF} sans PLF</span
           >.
         {:else if showAmendmentValue}
           <span class="text-sm underline decoration-dotted"
-            >par rapport au droit {$yearPLF} sans PLF</span
+            >par rapport au droit {yearPLF} sans PLF</span
           >.
         {/if}
       {:else}
@@ -181,7 +178,7 @@
           ></iconify-icon></span
         >
         <span class="text-sm underline decoration-dotted"
-          >par rapport au droit en vigueur {$yearPLF}</span
+          >par rapport au droit en vigueur {yearPLF}</span
         >.
       {/if}
     </p>
@@ -212,7 +209,7 @@
             {/if}
 
             <span class="underline decoration-2 underline-offset-2"
-              >par rapport au droit {$yearPLF} sans PLF</span
+              >par rapport au droit {yearPLF} sans PLF</span
             >.
           </p>
 
@@ -238,7 +235,7 @@
             {#if showAmendmentValue && showBillValue}
               <span
                 class="underline decoration-le-rouge-bill decoration-2 underline-offset-2"
-                >par rapport au droit {$yearPLF} avec PLF.</span
+                >par rapport au droit {yearPLF} avec PLF.</span
               ><br />
               <span class="bg-le-jaune"
                 >{amendmentLawValue === null
@@ -257,11 +254,11 @@
                 un impact nul ou inférieur à 5% {variableLabels.ofThe}
               {/if}
               <span class="underline decoration-2 underline-offset-2"
-                >par rapport au droit {$yearPLF} sans PLF</span
+                >par rapport au droit {yearPLF} sans PLF</span
               >.
             {:else}
               <span class="underline decoration-2 underline-offset-2"
-                >par rapport au droit {$yearPLF} sans PLF</span
+                >par rapport au droit {yearPLF} sans PLF</span
               >.
             {/if}
           {/if}
@@ -285,7 +282,7 @@
           {/if}
           <span
             class="underline decoration-black decoration-2 underline-offset-2"
-            >par rapport au droit en vigueur {$yearPLF}.</span
+            >par rapport au droit en vigueur {yearPLF}.</span
           ><br />
         {/if}
       </div>
diff --git a/src/lib/components/ValueChangeGraph.svelte b/src/lib/components/ValueChangeGraph.svelte
index 9f54a1f6d641641d2b96ca613eb85fb1153b6acd..be3307134c0d506034afd57a909ab89d8ac713ae 100644
--- a/src/lib/components/ValueChangeGraph.svelte
+++ b/src/lib/components/ValueChangeGraph.svelte
@@ -1,9 +1,5 @@
 <script lang="ts">
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
-  import type { ParametricReform } from "$lib/reforms"
-  import { type CalculationByName } from "$lib/situations"
+  import { shared } from "$lib/shared.svelte"
   import { valueFormatter } from "$lib/values"
   import type { VariableValueByCalculationName } from "$lib/variables"
 
@@ -21,13 +17,6 @@
     children,
   }: Props = $props()
 
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-
   function mustShowAmendmentValue(
     amendmentValueFormatted: string | undefined,
     billValueFormatted: string | undefined,
@@ -64,12 +53,12 @@
   )
   let format = $derived(valueFormatter(baseValue, unitName))
   let runningCalculationNames = $derived(
-    Object.entries($calculationByName)
+    Object.entries(shared.calculationByName)
       .filter(([, calculation]) => calculation.running)
       .map(([calculationName]) => calculationName),
   )
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
   let amendmentValueFormatted = $derived(
     amendmentValue === undefined ? undefined : format(amendmentValue),
diff --git a/src/lib/components/WaterfallCompareView.svelte b/src/lib/components/WaterfallCompareView.svelte
index 4802d5f447824a3cae563a2293d675516ccdfcc1..87ccc6d29d76aa9c3011eaed4d5fb6912fade49b 100644
--- a/src/lib/components/WaterfallCompareView.svelte
+++ b/src/lib/components/WaterfallCompareView.svelte
@@ -1,28 +1,21 @@
 <script lang="ts">
   import { preventDefault } from "svelte/legacy"
 
-  import type { VariableByName, Waterfall } from "@openfisca/json-model"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import type { VariableByName } from "@openfisca/json-model"
 
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
   import Tooltip from "$lib/components/Tooltip.svelte"
-  import type {
-    DecompositionByName,
-    EvaluationByName,
-  } from "$lib/decompositions"
+  import type { EvaluationByName } from "$lib/decompositions"
   import { buildVisibleDecompositionsForComparison } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { entityByKey } from "$lib/entities"
-  import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
-  import type { CalculationByName, Situation } from "$lib/situations"
+  import { shared } from "$lib/shared.svelte"
+  import type { Situation } from "$lib/situations"
   import { newSimulationUrl } from "$lib/urls"
   import { removeNegativeZero } from "$lib/values"
 
   interface Props {
-    decompositionByName: DecompositionByName
     displayMode: DisplayMode
     evaluationByNameArray: EvaluationByName[]
     situations: Situation[]
@@ -32,9 +25,7 @@
     year: number
   }
 
-  const { revaluationName } = publicConfig
   let {
-    decompositionByName = $bindable(),
     displayMode,
     evaluationByNameArray,
     situations,
@@ -44,9 +35,6 @@
     year,
   }: Props = $props()
 
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
     .format
   const deltaFormatter = (value: number): string =>
@@ -57,33 +45,28 @@
       signDisplay: "never",
       style: "currency",
     }).format(removeNegativeZero(value))
-  const dispatch = createEventDispatcher()
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const showNulls = getContext("showNulls") as Writable<boolean>
-  const vectorLength = getContext("vectorLength") as Writable<number>
-  const waterfall = getContext("waterfall") as Writable<Waterfall>
 
-  let useRevaluationInsteadOfLaw = revaluationName !== undefined
+  let useRevaluationInsteadOfLaw = $derived(
+    $page.data.revaluationName !== undefined,
+  )
 
   let firstCalculationName = $derived(
     useRevaluationInsteadOfLaw ? "revaluation" : "law",
   )
 
   let runningCalculationNames = $derived(
-    Object.entries($calculationByName)
+    Object.entries(shared.calculationByName)
       .filter(([, calculation]) => calculation.running)
       .map(([calculationName]) => calculationName),
   )
 
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
 
   let visibleDecompositions = $derived(
     buildVisibleDecompositionsForComparison(
-      decompositionByName,
+      shared.decompositionByName,
       entityByKey,
       situationsToCompareIndex.map(
         (situationIndex) => evaluationByNameArray[situationIndex],
@@ -92,10 +75,10 @@
         (situationIndex) => situations[situationIndex],
       ),
       variableSummaryByName,
-      $waterfall,
-      $showNulls,
+      shared.waterfall,
+      shared.showNulls,
       useRevaluationInsteadOfLaw,
-      $vectorLength,
+      shared.vectorLength,
       year,
     ),
   )
@@ -116,11 +99,10 @@
     }
     let decomposition = visibleDecomposition.decomposition
     if (!decomposition.open) {
-      decompositionByName = {
-        ...decompositionByName,
-        [decomposition.name]: { ...decomposition, open: true },
+      shared.decompositionByName[decomposition.name] = {
+        ...decomposition,
+        open: true,
       }
-      dispatch("changeDecompositionByName", decompositionByName)
       return
     }
   }
@@ -135,11 +117,10 @@
     }
     let decomposition = visibleDecomposition.decomposition
     if (decomposition.open) {
-      decompositionByName = {
-        ...decompositionByName,
-        [decomposition.name]: { ...decomposition, open: false },
+      shared.decompositionByName[decomposition.name] = {
+        ...decomposition,
+        open: false,
       }
-      dispatch("changeDecompositionByName", decompositionByName)
       return
     }
   }
@@ -598,7 +579,7 @@
     >
       <label class="inline-flex text-xs leading-none text-gray-600">
         <input
-          bind:checked={$showNulls}
+          bind:checked={shared.showNulls}
           class="checked rounded bg-gray-100 accent-gray-500"
           type="checkbox"
         />
diff --git a/src/lib/components/WaterfallPlainView.svelte b/src/lib/components/WaterfallPlainView.svelte
index b1a91d3f6aae00180630b2fbbacd06735a19370b..c5f1b4b37975a07028c4692b4a2e69f53ccf817a 100644
--- a/src/lib/components/WaterfallPlainView.svelte
+++ b/src/lib/components/WaterfallPlainView.svelte
@@ -12,7 +12,7 @@
     decompositionCoreByNameByReformName,
     waterfalls,
   } from "$lib/decompositions"
-  import publicConfig from "$lib/public_config"
+  import { billName } from "$lib/shared.svelte"
   import {
     variableSummaryByName,
     variableSummaryByNameByReformName,
@@ -22,7 +22,6 @@
     compact?: boolean
   }
 
-  const { reformName } = publicConfig
   let { compact = false }: Props = $props()
 
   const dispatch = createEventDispatcher()
@@ -31,9 +30,9 @@
 
   let decompositionByName = $derived(
     buildDecompositionByNameFromCore(
-      reformName === undefined
+      billName === undefined
         ? decompositionCoreByName
-        : (decompositionCoreByNameByReformName[reformName] ??
+        : (decompositionCoreByNameByReformName[billName] ??
             decompositionCoreByName),
     ) as DecompositionByName,
   )
@@ -41,7 +40,7 @@
   // Note: A reform variable is always more complete than a variable before reform.
   // But it may contain different formulas, with different parameters & variables.
   let billVariableSummaryByName = $derived(
-    variableSummaryByNameByReformName[reformName] ?? variableSummaryByName,
+    variableSummaryByNameByReformName[billName] ?? variableSummaryByName,
   )
 
   let waterfallsDecompositions = $derived(
diff --git a/src/lib/components/WaterfallView.svelte b/src/lib/components/WaterfallView.svelte
index 69d918b7a5b8c342d94578d0313337f798e5e316..df0f985ec0e44f6585061412e801299ced6cf4b6 100644
--- a/src/lib/components/WaterfallView.svelte
+++ b/src/lib/components/WaterfallView.svelte
@@ -1,25 +1,20 @@
 <script lang="ts">
-  import type { VariableByName, Waterfall } from "@openfisca/json-model"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import type { VariableByName } from "@openfisca/json-model"
+  import { createEventDispatcher } from "svelte"
 
   import { goto } from "$app/navigation"
   import TestCaseGraph from "$lib/components/test_cases/TestCaseGraph.svelte"
   import Tooltip from "$lib/components/Tooltip.svelte"
   import ValueChange from "$lib/components/ValueChange.svelte"
-  import type {
-    DecompositionByName,
-    EvaluationByName,
-  } from "$lib/decompositions"
+  import type { EvaluationByName } from "$lib/decompositions"
   import { buildVisibleDecompositions } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { entityByKey, personEntityKey } from "$lib/entities"
   import { trackTestCaseGraph } from "$lib/matomo"
   import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
+  import { revaluationName, shared } from "$lib/shared.svelte"
   import {
     type ActiveSlider,
-    type CalculationByName,
     getCalculatedVariableValueByCalculationName,
     getSituationVariableValue,
     setSituationVariableValue,
@@ -33,7 +28,6 @@
   } from "$lib/variables"
 
   interface Props {
-    decompositionByName: DecompositionByName
     displayMode: DisplayMode
     evaluationByName: EvaluationByName
     highlightDecomposition?: boolean
@@ -45,9 +39,9 @@
     year: number
   }
 
-  const { householdEntityKey, revaluationName } = publicConfig
+  const { householdEntityKey } = publicConfig
+
   let {
-    decompositionByName = $bindable(),
     displayMode,
     evaluationByName,
     highlightDecomposition = false,
@@ -59,9 +53,6 @@
     year,
   }: Props = $props()
 
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
     .format
   const deltaFormatter = (value: number): string =>
@@ -73,9 +64,6 @@
       style: "currency",
     }).format(removeNegativeZero(value))
   const dispatch = createEventDispatcher()
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
   const firstDeltaFormatter = (value: number): string =>
     new Intl.NumberFormat("fr-FR", {
       currency: "EUR",
@@ -84,41 +72,35 @@
       style: "currency",
     }).format(removeNegativeZero(value))
   const householdEntity = entityByKey[householdEntityKey]
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
   const personEntity = entityByKey[personEntityKey]
-  const showNulls = getContext("showNulls") as Writable<boolean>
-  const vectorLength = getContext("vectorLength") as Writable<number>
-  const waterfall = getContext("waterfall") as Writable<Waterfall>
 
-  let useRevaluationInsteadOfLaw = revaluationName !== undefined
+  let useRevaluationInsteadOfLaw = $derived(revaluationName !== undefined)
 
   let firstCalculationName = $derived(
     useRevaluationInsteadOfLaw ? "revaluation" : "law",
   )
 
   let runningCalculationNames = $derived(
-    Object.entries($calculationByName)
+    Object.entries(shared.calculationByName)
       .filter(([, calculation]) => calculation.running)
       .map(([calculationName]) => calculationName),
   )
 
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
 
   let visibleDecompositions = $derived(
     buildVisibleDecompositions(
-      decompositionByName,
+      shared.decompositionByName,
       entityByKey,
       evaluationByName,
       situation,
       variableSummaryByName,
-      $waterfall,
-      $showNulls,
+      shared.waterfall,
+      shared.showNulls,
       useRevaluationInsteadOfLaw,
-      $vectorLength,
+      shared.vectorLength,
       year,
     ),
   )
@@ -282,11 +264,10 @@
     }
     let decomposition = visibleDecomposition.decomposition
     if (!decomposition.open) {
-      decompositionByName = {
-        ...decompositionByName,
-        [decomposition.name]: { ...decomposition, open: true },
+      shared.decompositionByName[decomposition.name] = {
+        ...decomposition,
+        open: true,
       }
-      dispatch("changeDecompositionByName", decompositionByName)
       return
     }
   }
@@ -301,11 +282,10 @@
     }
     let decomposition = visibleDecomposition.decomposition
     if (decomposition.open) {
-      decompositionByName = {
-        ...decompositionByName,
-        [decomposition.name]: { ...decomposition, open: false },
+      shared.decompositionByName[decomposition.name] = {
+        ...decomposition,
+        open: false,
       }
-      dispatch("changeDecompositionByName", decompositionByName)
       return
     }
   }
@@ -425,7 +405,11 @@
                       class="cursor-pointer overflow-x-hidden text-ellipsis font-serif text-base hover:z-20 hover:overflow-x-visible hover:bg-white hover:text-le-gris-dispositif hover:underline"
                       onclick={() => {
                         // Non-leaf decomposition node in variable inputs mode => no-link
-                        decomposition.open ? zoomOut(index) : zoomIn(index)
+                        if (decomposition.open) {
+                          zoomOut(index)
+                        } else {
+                          zoomIn(index)
+                        }
 
                         // Leaf decomposition node with parameters in parameters mode => link
                         if (displayMode.edit === undefined) {
@@ -600,7 +584,7 @@
           type="checkbox"
           value=""
           class="peer sr-only"
-          bind:checked={$showNulls}
+          bind:checked={shared.showNulls}
         />
         <div
           class="peer relative h-6 w-11 shrink-0 rounded-full bg-gray-400 after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:transition-all after:content-[''] peer-checked:bg-le-vert-500 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-0"
@@ -612,7 +596,7 @@
     </div>
 
     <!--AJout de la variable niveau de vie-->
-    {#if $waterfall.name === "brut_to_disponible"}
+    {#if shared.waterfall.name === "brut_to_disponible"}
       <div
         class="relative ml-10 mt-10 flex flex-col border-t-2 border-neutral-500"
       >
@@ -759,18 +743,17 @@
         ></iconify-icon>
       </button>
       <TestCaseGraph
-        {decompositionByName}
         {displayMode}
         {evaluationByName}
-        evaluationByNameArray={$evaluationByNameArray}
+        evaluationByNameArray={shared.evaluationByNameArray}
         on:changeSituation
         {situation}
         {situationIndex}
         {useRevaluationInsteadOfLaw}
         {valuesByCalculationNameByVariableName}
         {variableSummaryByName}
-        vectorLength={$vectorLength}
-        waterfall={$waterfall}
+        vectorLength={shared.vectorLength}
+        waterfall={shared.waterfall}
         {year}
       />
     {/if}
diff --git a/src/lib/components/budget/BudgetDetailView.svelte b/src/lib/components/budget/BudgetDetailView.svelte
index fa2602bcd7ac9bff734c299412fdca67792af2e5..2dcf33e29ebb22dd3c04f590cbc2645c6f58f145 100644
--- a/src/lib/components/budget/BudgetDetailView.svelte
+++ b/src/lib/components/budget/BudgetDetailView.svelte
@@ -1,8 +1,6 @@
 <script lang="ts">
   import { scaleBand } from "d3-scale"
   import { Html, LayerCake, Svg } from "layercake"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import type {
     BudgetQuantile,
@@ -18,6 +16,7 @@
   import Tooltip from "$lib/components/Tooltip.svelte"
   import ValueChange from "$lib/components/ValueChange.svelte"
   import type { DisplayMode } from "$lib/displays"
+  import { yearPLF } from "$lib/shared.svelte"
   import { removeNegativeZero } from "$lib/values"
   import {
     type BudgetVariable,
@@ -71,7 +70,6 @@
     ["one", "er"],
   ])
   let yBase = $state(yBaseZoomed)
-  const yearPLF = getContext("yearPLF") as Writable<number>
   let zoomed = $state(true)
 
   function buildBudgetChartLegend(
@@ -109,7 +107,7 @@
 
     legend.push({
       id: "law_base",
-      label: `${baseVariable.labels.default} ${$yearPLF}`,
+      label: `${baseVariable.labels.default} ${yearPLF}`,
       pattern: {
         backgroundClass: "bg-gray-700",
       },
@@ -118,7 +116,7 @@
     if (hasAllegementCustomization) {
       legend.push({
         id: "law_allegement",
-        label: `${budgetVariable.labels.default} ${$yearPLF}`,
+        label: `${budgetVariable.labels.default} ${yearPLF}`,
         pattern: {
           backgroundClass: "bg-gray-700",
           foreground: `data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-opacity='1' fill-rule='evenodd'%3E%3Cpath d='M 40,30 30,40 H 40 Z M 40,10 10,40 H 20 L 40,20 Z M 30,0 0,30 V 40 L 40,0 Z M 10,0 0,10 V 20 L 20,0 Z'/%3E%3C/g%3E%3C/svg%3E`,
@@ -850,6 +848,7 @@
                       ? law.revenus_menage_sum
                       : law.rfr_sum}
                   />
+                  <!-- TODO svelte5: fix -->
                   <Column
                     fill="#404040"
                     on:click={() => changeQuantileIndex(index)}
diff --git a/src/lib/components/budget/BudgetLayout.svelte b/src/lib/components/budget/BudgetLayout.svelte
index 7a0030ccf9b016be6910cd6252b6fd3817c5d23e..cf08897ae9a54200e30792980fa19457a1b51816 100644
--- a/src/lib/components/budget/BudgetLayout.svelte
+++ b/src/lib/components/budget/BudgetLayout.svelte
@@ -1,13 +1,10 @@
 <script lang="ts">
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
   import type { BudgetSimulation } from "$lib/budgets"
   import BudgetDetailView from "$lib/components/budget/BudgetDetailView.svelte"
   import GagnantsPerdantsView from "$lib/components/budget/GagnantsPerdantsView.svelte"
   import Tooltip from "$lib/components/Tooltip.svelte"
-  import type { DecompositionByName } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
+  import { billActive, shared } from "$lib/shared.svelte"
   import {
     budgetVariableNameByVariableName,
     budgetVariablesConfig,
@@ -23,32 +20,27 @@
 
   let { blur = false, budgetSimulation, displayMode }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
-  const decompositionByName = getContext(
-    "decompositionByName",
-  ) as Writable<DecompositionByName>
-
   let budgetVariableName = $derived(
     displayMode.parametersVariableName !== undefined
       ? budgetVariableNameByVariableName[displayMode.parametersVariableName]
       : undefined,
   )
 
-  let budgetVariable = $derived(
-    (budgetVariableName
+  let budgetVariable:
+    | (BudgetVariable & { label: string; name: string })
+    | undefined = $derived(
+    budgetVariableName
       ? {
           ...budgetVariablesConfig[budgetVariableName],
           label:
-            $decompositionByName[budgetVariableName]?.short_label ??
+            shared.decompositionByName[budgetVariableName]?.short_label ??
             variableSummaryByName[budgetVariableName]?.short_label ??
-            $decompositionByName[budgetVariableName]?.label ??
+            shared.decompositionByName[budgetVariableName]?.label ??
             variableSummaryByName[budgetVariableName]?.label ??
             budgetVariableName,
           name: budgetVariableName,
         }
-      : undefined) as
-      | (BudgetVariable & { label: string; name: string })
-      | undefined,
+      : undefined,
   )
 </script>
 
@@ -196,7 +188,7 @@
                   </div>
                 {/snippet}
               </Tooltip>.
-              {#if $billActive}
+              {#if billActive}
                 <br />
                 <span class="rounded-sm bg-red-200 px-1 py-0.5 text-black">
                   ⚠️ En attente des prévisions 2025 ! Montants actuels
@@ -249,7 +241,7 @@
                   </div>
                 {/snippet}
               </Tooltip>.
-              {#if $billActive}
+              {#if billActive}
                 <br />
                 <span class="rounded-sm bg-red-200 px-1 py-0.5 text-black">
                   ⚠️ En attente des prévisions 2025 ! Montants actuels
@@ -292,7 +284,7 @@
                 {/snippet}
               </Tooltip>
               du rapport des comptes de la Sécurité sociale.
-              {#if $billActive}
+              {#if billActive}
                 <br />
                 <span class="rounded-sm bg-red-200 px-1 py-0.5 text-black">
                   ⚠️ En attente des prévisions 2025 ! Montants actuels
@@ -340,7 +332,7 @@
                   {/snippet}
                 </Tooltip>
                 du rapport des comptes de la Sécurité sociale.
-                {#if $billActive}
+                {#if billActive}
                   <br />
                   <span class="rounded-sm bg-red-200 px-1 py-0.5 text-black">
                     ⚠️ En attente des prévisions 2025 ! Montants actuels
@@ -349,7 +341,7 @@
                 {/if}
               </span>
             {:else if budgetVariable.name === "vieillesse_salarie" || budgetVariable.name === "vieillesse_deplafonnee_salarie" || budgetVariable.name === "vieillesse_plafonnee_salarie" || budgetVariable.name === "vieillesse_employeur" || budgetVariable.name === "vieillesse_deplafonnee_employeur" || budgetVariable.name === "vieillesse_plafonnee_employeur"}
-              {#if $billActive}
+              {#if billActive}
                 Hypothèse de calcul basée sur l'évolution des recettes du PLFSS
                 2025.
                 <br />
@@ -399,7 +391,7 @@
                 du rapport des comptes de la Sécurité sociale.
               {/if}
             {:else if budgetVariable.name === "mmid_employeur_net_allegement" || budgetVariable.name === "mmid_employeur" || budgetVariable.name === "famille_net_allegement" || budgetVariable.name === "famille"}
-              {#if $billActive}
+              {#if billActive}
                 Hypothèse de calcul basée sur l'évolution des recettes du PLFSS
                 2025.
                 <br />
@@ -465,7 +457,7 @@
                 du PLFSS pour 2024 et du REPSS 2022.
               {/if}
             {:else if budgetVariable.name === "contribution_solidarite_autonomie"}
-              {#if $billActive}
+              {#if billActive}
                 Hypothèse de calcul basée sur l'évolution des recettes du PLFSS
                 2025.
                 <br />
@@ -513,7 +505,7 @@
                 du PLFSS pour 2024.
               {/if}
             {:else if budgetVariable.name === "allegement_cotisation_allocations_familiales" || budgetVariable.name === "allegement_cotisation_maladie" || budgetVariable.name === "allegement_general"}
-              {#if $billActive}
+              {#if billActive}
                 Hypothèse de calcul basée sur les recettes d'allègements
                 indiquées dans le PLFSS 2025.
                 <br />
@@ -595,7 +587,7 @@
                 {/snippet}
               </Tooltip>
               du PLF pour 2024.
-              {#if $billActive}
+              {#if billActive}
                 <br />
                 <span class="rounded-sm bg-red-200 px-1 py-0.5 text-black">
                   ⚠️ En attente des prévisions 2025 ! Montants actuels
@@ -636,7 +628,7 @@
                 {/snippet}
               </Tooltip>
               du PLF pour 2024.
-              {#if $billActive}
+              {#if billActive}
                 <br />
                 <span class="rounded-sm bg-red-200 px-1 py-0.5 text-black">
                   ⚠️ En attente des prévisions 2025 ! Montants actuels
diff --git a/src/lib/components/layercake/Column.svelte b/src/lib/components/layercake/Column.svelte
index 2fe2f7811a17d7d3a25937d956f4ab8c98bf5cb2..a77558f99a5d163a92e8247d32f663a3aae3e380 100644
--- a/src/lib/components/layercake/Column.svelte
+++ b/src/lib/components/layercake/Column.svelte
@@ -40,6 +40,8 @@
   let yScaled = $derived($yScale(y))
 
   let columnWidth = $derived(xScale.bandwidth())
+
+  $effect(() => $inspect("!", xScale.range(), xScale.bandwidth()))
 </script>
 
 {#if columnHeight > 0}
diff --git a/src/lib/components/parameters/ParameterView.svelte b/src/lib/components/parameters/ParameterView.svelte
index 5870e069f87fe14aaabaa2b53a43c3da871742ec..2f25568780503f1d35412dcd20410cee43fbb302 100644
--- a/src/lib/components/parameters/ParameterView.svelte
+++ b/src/lib/components/parameters/ParameterView.svelte
@@ -8,11 +8,9 @@
     type Parameter,
   } from "@openfisca/json-model"
   import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import { goto } from "$app/navigation"
   import ScaleView from "$lib/components/parameters/ScaleView.svelte"
-  import type { DisplayMode } from "$lib/displays"
   import { metadata } from "$lib/metadata"
   import {
     asAmountScaleParameter,
@@ -22,6 +20,7 @@
     labelFromValueType,
   } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
+  import { shared } from "$lib/shared.svelte"
   import { getUnitByName, getUnitShortLabel } from "$lib/units"
   import { type SelfTargetAProps, newSimulationUrl } from "$lib/urls"
 
@@ -31,13 +30,11 @@
   }
 
   const { openfiscaRepository } = publicConfig
+
   let { date, parameter }: Props = $props()
 
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
     .format
-  const displayMode = getContext("displayMode") as Writable<
-    DisplayMode | undefined
-  >
   const newSelfTargetAProps = getContext("newSelfTargetAProps") as (
     url: string,
   ) => SelfTargetAProps
@@ -54,7 +51,11 @@
     <button
       class="ml-10 mt-5 inline-flex cursor-pointer items-center rounded bg-gray-200 p-2 pr-3 text-sm text-black shadow-md hover:bg-gray-300 active:bg-gray-400"
       onclick={() =>
-        goto($displayMode === undefined ? "/" : newSimulationUrl($displayMode))}
+        goto(
+          shared.displayMode === undefined
+            ? "/"
+            : newSimulationUrl(shared.displayMode),
+        )}
     >
       <iconify-icon class="text-2xl" icon="ri-arrow-left-line"></iconify-icon>
       <span class="ml-3">Retour au simulateur</span>
diff --git a/src/lib/components/test_cases/TestCaseCompareModal.svelte b/src/lib/components/test_cases/TestCaseCompareModal.svelte
index 86fd34e02cbf822baf73baee0bd80242a2d438d3..666c1383af8ee6e21caee5e7aeb52a6dc02aeba2 100644
--- a/src/lib/components/test_cases/TestCaseCompareModal.svelte
+++ b/src/lib/components/test_cases/TestCaseCompareModal.svelte
@@ -1,11 +1,8 @@
 <script lang="ts">
   import { Dialog } from "bits-ui"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { createEventDispatcher } from "svelte"
 
-  import type { EvaluationByName } from "$lib/decompositions"
-  import type { Situation } from "$lib/situations"
-  import type { ValuesByCalculationNameByVariableName } from "$lib/variables"
+  import { shared } from "$lib/shared.svelte"
 
   interface Props {
     isOpen?: boolean
@@ -14,66 +11,50 @@
   let { isOpen = $bindable(false) }: Props = $props()
 
   const dispatch = createEventDispatcher()
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
-  let selectedTestCaseIndex = $state($testCasesIndex[1])
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
+  let selectedTestCaseIndex = $state(shared.testCasesIndex[1])
 
   function closeModal() {
     isOpen = false
-    dispatch("changeTestCasesIndex", $testCasesIndex)
+    dispatch("changeTestCasesIndex", shared.testCasesIndex)
   }
 
   function duplicateTestCaseAndCloseModal() {
-    $testCasesIndex = [$testCasesIndex[0], $testCases.length]
-    const duplicatedTestCase = structuredClone($testCases[$testCasesIndex[0]])
+    shared.testCasesIndex = [shared.testCasesIndex[0], shared.testCases.length]
+    const duplicatedTestCase = structuredClone(
+      shared.testCases[shared.testCasesIndex[0]],
+    )
     duplicatedTestCase.title = `Copie de ${duplicatedTestCase.title}`
-    $testCases = [...$testCases, duplicatedTestCase]
+    shared.testCases.push(duplicatedTestCase)
 
     const duplicatedEvaluationByName = structuredClone(
-      $evaluationByNameArray[$testCasesIndex[0]],
+      shared.evaluationByNameArray[shared.testCasesIndex[0]],
     )
-    $evaluationByNameArray = [
-      ...$evaluationByNameArray,
-      duplicatedEvaluationByName,
-    ]
+    shared.evaluationByNameArray.push(duplicatedEvaluationByName)
 
     const duplicatedInputInstantsByVariableName = structuredClone(
-      $inputInstantsByVariableNameArray[$testCasesIndex[0]],
+      shared.inputInstantsByVariableNameArray[shared.testCasesIndex[0]],
     )
-    $inputInstantsByVariableNameArray = [
-      ...$inputInstantsByVariableNameArray,
+    shared.inputInstantsByVariableNameArray.push(
       duplicatedInputInstantsByVariableName,
-    ]
+    )
 
     const duplicatedValuesByCalculationNameByVariableName = structuredClone(
-      $valuesByCalculationNameByVariableNameArray[$testCasesIndex[0]],
+      shared.valuesByCalculationNameByVariableNameArray[
+        shared.testCasesIndex[0]
+      ],
     )
-    $valuesByCalculationNameByVariableNameArray = [
-      ...$valuesByCalculationNameByVariableNameArray,
+    shared.valuesByCalculationNameByVariableNameArray.push(
       duplicatedValuesByCalculationNameByVariableName,
-    ]
+    )
 
     isOpen = false
-    dispatch("changeTestCasesIndex", $testCasesIndex)
+    dispatch("changeTestCasesIndex", shared.testCasesIndex)
   }
 
   function selectTestCaseAndCloseModal() {
-    $testCasesIndex = [$testCasesIndex[0], selectedTestCaseIndex]
+    shared.testCasesIndex = [shared.testCasesIndex[0], selectedTestCaseIndex]
     isOpen = false
-    dispatch("changeTestCasesIndex", $testCasesIndex)
+    dispatch("changeTestCasesIndex", shared.testCasesIndex)
   }
 </script>
 
@@ -115,10 +96,10 @@
               disabled
               value={undefined}>Choisissez un cas type…</option
             >
-            {#each $testCases as situation, situationIndex}
+            {#each shared.testCases as situation, situationIndex}
               <option
                 class="w-full bg-white py-1 text-sm"
-                disabled={situationIndex === $testCasesIndex[0]}
+                disabled={situationIndex === shared.testCasesIndex[0]}
                 value={situationIndex}
               >
                 {situation.title}
@@ -128,7 +109,7 @@
           <button
             class="mb-5 mt-2 inline-flex items-center rounded bg-gray-300 px-2 py-1 text-base uppercase enabled:text-black enabled:shadow-lg enabled:hover:bg-gray-400 disabled:text-gray-500"
             disabled={selectedTestCaseIndex === undefined ||
-              selectedTestCaseIndex === $testCasesIndex[0]}
+              selectedTestCaseIndex === shared.testCasesIndex[0]}
             type="button"
             onclick={selectTestCaseAndCloseModal}
             >Comparer <iconify-icon
diff --git a/src/lib/components/test_cases/TestCaseCompareView.svelte b/src/lib/components/test_cases/TestCaseCompareView.svelte
index 14087cb3084f4e0043bae6c00805b45274f94531..4027424adb50a83c9d38faa58382bef221e34be5 100644
--- a/src/lib/components/test_cases/TestCaseCompareView.svelte
+++ b/src/lib/components/test_cases/TestCaseCompareView.svelte
@@ -1,58 +1,30 @@
 <script lang="ts">
-  import type { DecompositionReference, Waterfall } from "@openfisca/json-model"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import type { DecompositionReference } from "@openfisca/json-model"
+  import { createEventDispatcher } from "svelte"
 
   import type { CalculationName } from "$lib/calculations.svelte"
   import TestCaseSummary from "$lib/components/test_cases/TestCaseSummary.svelte"
   import ValueChangeCompare from "$lib/components/ValueChangeCompare.svelte"
   import WaterfallCompareView from "$lib/components/WaterfallCompareView.svelte"
-  import {
-    type DecompositionByName,
-    type EvaluationByName,
-    waterfalls,
-  } from "$lib/decompositions"
+  import { type EvaluationByName, waterfalls } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
-  import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
-  import type { Situation } from "$lib/situations"
+  import { billName, revaluationName, shared } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
-  import {
-    type ValuesByCalculationNameByVariableName,
-    variableSummaryByName,
-  } from "$lib/variables"
+  import { variableSummaryByName } from "$lib/variables"
 
   interface Props {
-    decompositionByName: DecompositionByName
     displayMode: DisplayMode
     situationsToCompareIndex: number[]
     year: number
   }
 
-  const { reformName, revaluationName } = publicConfig
-  let {
-    decompositionByName,
-    displayMode,
-    situationsToCompareIndex,
-    year,
-  }: Props = $props()
+  let { displayMode, situationsToCompareIndex, year }: Props = $props()
 
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
-  const waterfall = getContext("waterfall") as Writable<Waterfall>
+  const dispatch = createEventDispatcher()
 
   let situationsToCompare = $derived(
     situationsToCompareIndex.map(
-      (situationIndex) => $testCases[situationIndex],
+      (situationIndex) => shared.testCases[situationIndex],
     ),
   )
 
@@ -93,7 +65,7 @@
       <button
         class="text-sm uppercase text-gray-600 hover:text-black"
         onclick={() =>
-          dispatch("changeTestCasesIndex", $testCasesIndex.slice(0, 1))}
+          dispatch("changeTestCasesIndex", shared.testCasesIndex.slice(0, 1))}
         type="button"
         title="Fermer la comparaison des deux cas types"
       >
@@ -122,9 +94,8 @@
             mode="compare"
             {situation}
             {situationIndex}
-            valuesByCalculationNameByVariableName={$valuesByCalculationNameByVariableNameArray[
-              situationIndex
-            ]}
+            valuesByCalculationNameByVariableName={shared
+              .valuesByCalculationNameByVariableNameArray[situationIndex]}
             {year}
           />
         </div>
@@ -146,7 +117,7 @@
             >
               <div class="mb-4 w-full flex-col text-gray-700">
                 <p class="mb-1 text-base font-medium">
-                  {$waterfall.totalLabel}<svg
+                  {shared.waterfall.totalLabel}<svg
                     aria-hidden="true"
                     class="mx-1 inline-flex h-4 w-4 fill-current text-white"
                     viewBox="0 0 24 22"
@@ -169,72 +140,84 @@
                   unitName="currency-EUR"
                   valueByCalculationName0={{
                     amendment:
-                      Object.keys($parametricReform).length === 0
+                      Object.keys(shared.parametricReform).length === 0
                         ? undefined
                         : calculateTotal(
-                            $evaluationByNameArray[situationsToCompareIndex[0]],
+                            shared.evaluationByNameArray[
+                              situationsToCompareIndex[0]
+                            ],
                             "amendment",
-                            $waterfall.root,
-                            $waterfall.total,
+                            shared.waterfall.root,
+                            shared.waterfall.total,
                           ),
                     bill:
-                      reformName === undefined
+                      billName === undefined
                         ? undefined
                         : calculateTotal(
-                            $evaluationByNameArray[situationsToCompareIndex[0]],
+                            shared.evaluationByNameArray[
+                              situationsToCompareIndex[0]
+                            ],
                             "bill",
-                            $waterfall.root,
-                            $waterfall.total,
+                            shared.waterfall.root,
+                            shared.waterfall.total,
                           ),
                     law: calculateTotal(
-                      $evaluationByNameArray[situationsToCompareIndex[0]],
+                      shared.evaluationByNameArray[situationsToCompareIndex[0]],
                       "law",
-                      $waterfall.root,
-                      $waterfall.total,
+                      shared.waterfall.root,
+                      shared.waterfall.total,
                     ),
                     revaluation:
                       revaluationName === undefined
                         ? undefined
                         : calculateTotal(
-                            $evaluationByNameArray[situationsToCompareIndex[0]],
+                            shared.evaluationByNameArray[
+                              situationsToCompareIndex[0]
+                            ],
                             "revaluation",
-                            $waterfall.root,
-                            $waterfall.total,
+                            shared.waterfall.root,
+                            shared.waterfall.total,
                           ),
                   }}
                   valueByCalculationName1={{
                     amendment:
-                      Object.keys($parametricReform).length === 0
+                      Object.keys(shared.parametricReform).length === 0
                         ? undefined
                         : calculateTotal(
-                            $evaluationByNameArray[situationsToCompareIndex[1]],
+                            shared.evaluationByNameArray[
+                              situationsToCompareIndex[1]
+                            ],
                             "amendment",
-                            $waterfall.root,
-                            $waterfall.total,
+                            shared.waterfall.root,
+                            shared.waterfall.total,
                           ),
                     bill:
-                      reformName === undefined
+                      billName === undefined
                         ? undefined
                         : calculateTotal(
-                            $evaluationByNameArray[situationsToCompareIndex[1]],
+                            shared.evaluationByNameArray[
+                              situationsToCompareIndex[1]
+                            ],
                             "bill",
-                            $waterfall.root,
-                            $waterfall.total,
+                            shared.waterfall.root,
+                            shared.waterfall.total,
                           ),
                     law: calculateTotal(
-                      $evaluationByNameArray[situationsToCompareIndex[1]],
+                      shared.evaluationByNameArray[situationsToCompareIndex[1]],
                       "law",
-                      $waterfall.root,
-                      $waterfall.total,
+                      shared.waterfall.root,
+                      shared.waterfall.total,
                     ),
                     revaluation:
                       revaluationName === undefined
                         ? undefined
                         : calculateTotal(
-                            $evaluationByNameArray[situationsToCompareIndex[1]],
+                            shared.evaluationByNameArray[
+                              situationsToCompareIndex[1]
+                            ],
                             "revaluation",
-                            $waterfall.root,
-                            $waterfall.total,
+                            shared.waterfall.root,
+                            shared.waterfall.total,
                           ),
                   }}
                 />
@@ -250,13 +233,15 @@
                 </p>
               </div> -->
             </div>
-            {#if displayMode.parametersVariableName !== undefined && decompositionByName[displayMode.parametersVariableName] !== undefined}
+            {#if displayMode.parametersVariableName !== undefined && shared.decompositionByName[displayMode.parametersVariableName] !== undefined}
               <div class="mt-2 flex-col">
                 <p class="mb-1 text-lg font-black">
-                  {decompositionByName[displayMode.parametersVariableName]
-                    .short_label ??
-                    decompositionByName[displayMode.parametersVariableName]
-                      .label ??
+                  {shared.decompositionByName[
+                    displayMode.parametersVariableName
+                  ].short_label ??
+                    shared.decompositionByName[
+                      displayMode.parametersVariableName
+                    ].label ??
                     displayMode.parametersVariableName}&nbsp;:
                 </p>
                 <div class="text-2xl font-semibold">
@@ -264,30 +249,31 @@
                     unitName="currency-EUR"
                     valueByCalculationName0={{
                       amendment:
-                        Object.keys($parametricReform).length === 0
+                        Object.keys(shared.parametricReform).length === 0
                           ? undefined
-                          : ($evaluationByNameArray[
+                          : (shared.evaluationByNameArray[
                               situationsToCompareIndex[0]
                             ][displayMode.parametersVariableName]
                               ?.calculationEvaluationByName["amendment"]
                               ?.deltaAtVectorIndex ?? 0),
                       bill:
-                        reformName === undefined
+                        billName === undefined
                           ? undefined
-                          : ($evaluationByNameArray[
+                          : (shared.evaluationByNameArray[
                               situationsToCompareIndex[0]
                             ][displayMode.parametersVariableName]
                               ?.calculationEvaluationByName["bill"]
                               ?.deltaAtVectorIndex ?? 0),
                       law:
-                        $evaluationByNameArray[situationsToCompareIndex[0]][
-                          displayMode.parametersVariableName
-                        ]?.calculationEvaluationByName["law"]
+                        shared.evaluationByNameArray[
+                          situationsToCompareIndex[0]
+                        ][displayMode.parametersVariableName]
+                          ?.calculationEvaluationByName["law"]
                           ?.deltaAtVectorIndex ?? 0,
                       revaluation:
                         revaluationName === undefined
                           ? undefined
-                          : ($evaluationByNameArray[
+                          : (shared.evaluationByNameArray[
                               situationsToCompareIndex[0]
                             ][displayMode.parametersVariableName]
                               ?.calculationEvaluationByName["revaluation"]
@@ -295,30 +281,31 @@
                     }}
                     valueByCalculationName1={{
                       amendment:
-                        Object.keys($parametricReform).length === 0
+                        Object.keys(shared.parametricReform).length === 0
                           ? undefined
-                          : ($evaluationByNameArray[
+                          : (shared.evaluationByNameArray[
                               situationsToCompareIndex[1]
                             ][displayMode.parametersVariableName]
                               ?.calculationEvaluationByName["amendment"]
                               ?.deltaAtVectorIndex ?? 0),
                       bill:
-                        reformName === undefined
+                        billName === undefined
                           ? undefined
-                          : ($evaluationByNameArray[
+                          : (shared.evaluationByNameArray[
                               situationsToCompareIndex[1]
                             ][displayMode.parametersVariableName]
                               ?.calculationEvaluationByName["bill"]
                               ?.deltaAtVectorIndex ?? 0),
                       law:
-                        $evaluationByNameArray[situationsToCompareIndex[1]][
-                          displayMode.parametersVariableName
-                        ]?.calculationEvaluationByName["law"]
+                        shared.evaluationByNameArray[
+                          situationsToCompareIndex[1]
+                        ][displayMode.parametersVariableName]
+                          ?.calculationEvaluationByName["law"]
                           ?.deltaAtVectorIndex ?? 0,
                       revaluation:
                         revaluationName === undefined
                           ? undefined
-                          : ($evaluationByNameArray[
+                          : (shared.evaluationByNameArray[
                               situationsToCompareIndex[1]
                             ][displayMode.parametersVariableName]
                               ?.calculationEvaluationByName["revaluation"]
@@ -330,11 +317,9 @@
             {/if}
           </div>
           <WaterfallCompareView
-            {decompositionByName}
             {displayMode}
-            evaluationByNameArray={$evaluationByNameArray}
-            on:changeDecompositionByName
-            situations={$testCases}
+            evaluationByNameArray={shared.evaluationByNameArray}
+            situations={shared.testCases}
             {situationsToCompareIndex}
             {variableSummaryByName}
             {year}
@@ -347,10 +332,10 @@
           {#each waterfalls as { icon, label, name }}
             <a
               class="flex grow items-center justify-center shadow-inner"
-              class:bg-white={name === $waterfall.name}
-              class:border-le-bleu={name === $waterfall.name}
-              class:border-r-4={name === $waterfall.name}
-              class:shadow-none={name === $waterfall.name}
+              class:bg-white={name === shared.waterfall.name}
+              class:border-le-bleu={name === shared.waterfall.name}
+              class:border-r-4={name === shared.waterfall.name}
+              class:shadow-none={name === shared.waterfall.name}
               href={newSimulationUrl({
                 ...displayMode,
                 waterfallName: name,
@@ -368,8 +353,8 @@
                   {/if}
                   <span
                     class="ml-2 text-xs uppercase tracking-wide text-gray-500 xl:text-sm"
-                    class:text-le-bleu={name === $waterfall.name}
-                    class:font-bold={name === $waterfall.name}
+                    class:text-le-bleu={name === shared.waterfall.name}
+                    class:font-bold={name === shared.waterfall.name}
                   >
                     {label}
                   </span>
diff --git a/src/lib/components/test_cases/TestCaseEditVariablesSearch.svelte b/src/lib/components/test_cases/TestCaseEditVariablesSearch.svelte
index 7232cf65d39b7d960730312f14119859fb75dd77..a58a002a91e749375fa141ad2bfafa841e24464e 100644
--- a/src/lib/components/test_cases/TestCaseEditVariablesSearch.svelte
+++ b/src/lib/components/test_cases/TestCaseEditVariablesSearch.svelte
@@ -1,11 +1,9 @@
 <script lang="ts">
   import type { Variable } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import VariableInput from "$lib/components/variables/VariableInput.svelte"
-  import publicConfig from "$lib/public_config"
   import { parseSearch } from "$lib/search/regexp_search"
+  import { billName } from "$lib/shared.svelte"
   import type { Situation } from "$lib/situations"
   import {
     type ValuesByCalculationNameByVariableName,
@@ -24,7 +22,6 @@
     year: number
   }
 
-  const { reformName } = publicConfig
   let {
     date,
     inputInstantsByVariableName = $bindable(),
@@ -52,7 +49,7 @@
   // Note: A reform variable is always more complete than a variable before reform.
   // But it may contain different formulas, with different parameters & variables.
   let billVariableSummaryByName = $derived(
-    variableSummaryByNameByReformName[reformName] ?? variableSummaryByName,
+    variableSummaryByNameByReformName[billName] ?? variableSummaryByName,
   )
   let inputVariables = $derived(
     (Object.values(billVariableSummaryByName) as Variable[]).filter(
diff --git a/src/lib/components/test_cases/TestCaseFilters.svelte b/src/lib/components/test_cases/TestCaseFilters.svelte
index d813a19348eeec0403acb65fcfa24d8f22be6c0f..2f9a5194c004155972ea97264c576dfccefcebef 100644
--- a/src/lib/components/test_cases/TestCaseFilters.svelte
+++ b/src/lib/components/test_cases/TestCaseFilters.svelte
@@ -1,12 +1,9 @@
 <script lang="ts">
-  import { run } from "svelte/legacy"
-
   import {
     scaleByInstantFromBrackets,
     type Variable,
   } from "@openfisca/json-model"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { createEventDispatcher } from "svelte"
 
   import { page } from "$app/stores"
   import SelectChip from "$lib/components/SelectChip.svelte"
@@ -16,7 +13,6 @@
   import {
     decompositionCoreByName,
     decompositionCoreByNameByReformName,
-    type EvaluationByName,
     getLatestCalculation,
   } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
@@ -28,10 +24,10 @@
     rootParameterByReformName,
   } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
+  import { billName, shared } from "$lib/shared.svelte"
   import { getSituationVariableValue, type Situation } from "$lib/situations"
   import { valueFormatter } from "$lib/values"
   import {
-    type ValuesByCalculationNameByVariableName,
     variableSummaryByName,
     variableSummaryByNameByReformName,
     type VariableValue,
@@ -45,8 +41,8 @@
     year: number
   }
 
-  const { childrenKey, familyEntityKey, householdEntityKey, reformName } =
-    publicConfig
+  const { childrenKey, familyEntityKey, householdEntityKey } = publicConfig
+
   let {
     displayMode,
     showOnlyDeciles = $bindable(false),
@@ -57,9 +53,6 @@
 
   let descriptionsOpen = $state(false)
   const dispatch = createEventDispatcher()
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
   const personEntity = entityByKey[personEntityKey]
   const familyEntity = entityByKey[familyEntityKey]
   const householdEntity = entityByKey[householdEntityKey]
@@ -74,9 +67,6 @@
     ["one", "er"],
   ])
   const ordinalPluralRules = new Intl.PluralRules("fr-FR", { type: "ordinal" })
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
 
   // Filters
   let filters: {
@@ -139,6 +129,110 @@
 
   let filterNiveauDeVieValue: string | undefined = $state(undefined)
 
+  // Note: A reform decomposition is always more complete than a decomposition before reform.
+  // And the children of a reform decomposition always contain the children of the decomposition
+  // before reform.
+  // → Non reform decomposition is not needed.
+  let latestDecompositionCoreByName = $derived(
+    decompositionCoreByNameByReformName[billName] ?? decompositionCoreByName,
+  )
+  let latestDecompositionCore = $derived(
+    latestDecompositionCoreByName[variableName],
+  )
+  let decomposition = $derived(
+    latestDecompositionCore === undefined
+      ? undefined
+      : {
+          ...latestDecompositionCore,
+          variableName,
+        },
+  )
+  // Note: A reform variable is always more complete than a variable before reform.
+  // But it may contain different formulas, with different parameters & variables.
+  let latestVariableSummaryByName = $derived(
+    variableSummaryByNameByReformName[billName] ?? variableSummaryByName,
+  )
+  let variable = $derived(latestVariableSummaryByName[variableName])
+  $effect(() => {
+    if (
+      variableName !== undefined &&
+      decomposition === undefined &&
+      variable === undefined
+    ) {
+      console.error(`Variable "${variableName}" not found`)
+    }
+  })
+  // Note: A reform parameters tree is always more complete than a parameters tree before reform.
+  // And the children of a reform node parameter always contain the children of the node parameter
+  // before reform (albeit with some different value parameters).
+  let billRootParameter = $derived(
+    rootParameterByReformName[billName] ?? rootParameter,
+  )
+  let decilesNiveauDeVieParameter = $derived(
+    asScaleParameter(getParameter(billRootParameter, "deciles_niveau_de_vie")),
+  )
+  let decilesNiveauDeVieScaleByInstant = $derived(
+    scaleByInstantFromBrackets(decilesNiveauDeVieParameter.brackets),
+  )
+  let decilesNiveauDeVieInstantScaleCouplesArray = $derived(
+    Object.entries(decilesNiveauDeVieScaleByInstant).sort(
+      ([instant1], [instant2]) => instant2.localeCompare(instant1),
+    ),
+  )
+  let decilesNiveauDeVieLatestInstantScaleCouple = $derived(
+    decilesNiveauDeVieInstantScaleCouplesArray[0],
+  )
+  let decilesNiveauDeVieScaleAtInstant = $derived(
+    decilesNiveauDeVieLatestInstantScaleCouple[1],
+  )
+  let filterValueByName = $derived(
+    Object.fromEntries(filters.map((filter) => [filter.name, filter.value])),
+  )
+  let variableSummary = $derived(
+    variableName !== undefined
+      ? billName === undefined
+        ? variableSummaryByName[variableName]
+        : variableSummaryByNameByReformName[billName][variableName]
+      : undefined,
+  )
+  let filteredTestCases = $derived(
+    filterTestCases(
+      filterValueByName,
+      showOnlyDeciles,
+      filterNiveauDeVieValue,
+      variableSummary,
+    ),
+  )
+  let selectDecilesNiveauDeVie = $derived([
+    {
+      label: "Tous",
+      shortLabel: "tous",
+      value: "tous",
+    },
+    {
+      label: "1<sup>er</sup> décile - à partir de 0&nbsp;€",
+      shortLabel: "1<sup>er</sup> décile",
+      value: "1",
+    },
+    ...(decilesNiveauDeVieScaleAtInstant ?? []).map(({ rate, threshold }) => ({
+      label: `${formatLongOrdinalSup(Number(rate.value) + 1)} décile - à partir de ${formatCurrency(threshold.value)}`,
+      shortLabel: `${formatLongOrdinalSup(Number(rate.value) + 1)} décile`,
+      value: `${rate.value + 1}`,
+    })),
+  ] as { label: string; shortLabel: string; value: string }[])
+  let shortLabel = $derived(
+    decomposition?.short_label ??
+      variable?.short_label ??
+      decomposition?.name ??
+      variable?.name,
+  )
+
+  $effect(() => {
+    if (showOnlyDeciles) {
+      filterNiveauDeVieValue = undefined
+    }
+  })
+
   function filterTestCases(
     filterValueByName: {
       [filter: string]: boolean | string
@@ -320,7 +414,7 @@
         if (filterValueByName["dispositif"] && variableSummary !== undefined) {
           let show = false
           const latestCalculationValue = getLatestCalculation(
-            $evaluationByNameArray[index][variableName]
+            shared.evaluationByNameArray[index][variableName]
               ?.calculationEvaluationByName,
           )?.deltaAtVectorIndex
           if (
@@ -348,8 +442,6 @@
             continue
           }
         }
-      } else {
-        filterNiveauDeVieValue = undefined
       }
       filtered.push([situation, index])
     }
@@ -367,103 +459,6 @@
     }
     return getSituationVariableValue(situation, variable, populationId, year)
   }
-  // Note: A reform decomposition is always more complete than a decomposition before reform.
-  // And the children of a reform decomposition always contain the children of the decomposition
-  // before reform.
-  // → Non reform decomposition is not needed.
-  let latestDecompositionCoreByName = $derived(
-    decompositionCoreByNameByReformName[reformName] ?? decompositionCoreByName,
-  )
-  let latestDecompositionCore = $derived(
-    latestDecompositionCoreByName[variableName],
-  )
-  let decomposition = $derived(
-    latestDecompositionCore === undefined
-      ? undefined
-      : {
-          ...latestDecompositionCore,
-          variableName,
-        },
-  )
-  // Note: A reform variable is always more complete than a variable before reform.
-  // But it may contain different formulas, with different parameters & variables.
-  let latestVariableSummaryByName = $derived(
-    variableSummaryByNameByReformName[reformName] ?? variableSummaryByName,
-  )
-  let variable = $derived(latestVariableSummaryByName[variableName])
-  run(() => {
-    if (
-      variableName !== undefined &&
-      decomposition === undefined &&
-      variable === undefined
-    ) {
-      console.error(`Variable "${variableName}" not found`)
-    }
-  })
-  // Note: A reform parameters tree is always more complete than a parameters tree before reform.
-  // And the children of a reform node parameter always contain the children of the node parameter
-  // before reform (albeit with some different value parameters).
-  let billRootParameter = $derived(
-    rootParameterByReformName[reformName] ?? rootParameter,
-  )
-  let decilesNiveauDeVieParameter = $derived(
-    asScaleParameter(getParameter(billRootParameter, "deciles_niveau_de_vie")),
-  )
-  let decilesNiveauDeVieScaleByInstant = $derived(
-    scaleByInstantFromBrackets(decilesNiveauDeVieParameter.brackets),
-  )
-  let decilesNiveauDeVieInstantScaleCouplesArray = $derived(
-    Object.entries(decilesNiveauDeVieScaleByInstant).sort(
-      ([instant1], [instant2]) => instant2.localeCompare(instant1),
-    ),
-  )
-  let decilesNiveauDeVieLatestInstantScaleCouple = $derived(
-    decilesNiveauDeVieInstantScaleCouplesArray[0],
-  )
-  let decilesNiveauDeVieScaleAtInstant = $derived(
-    decilesNiveauDeVieLatestInstantScaleCouple[1],
-  )
-  let filterValueByName = $derived(
-    Object.fromEntries(filters.map((filter) => [filter.name, filter.value])),
-  )
-  let variableSummary = $derived(
-    variableName !== undefined
-      ? reformName === undefined
-        ? variableSummaryByName[variableName]
-        : variableSummaryByNameByReformName[reformName][variableName]
-      : undefined,
-  )
-  let filteredTestCases = $derived(
-    filterTestCases(
-      filterValueByName,
-      showOnlyDeciles,
-      filterNiveauDeVieValue,
-      variableSummary,
-    ),
-  )
-  let selectDecilesNiveauDeVie = $derived([
-    {
-      label: "Tous",
-      shortLabel: "tous",
-      value: "tous",
-    },
-    {
-      label: "1<sup>er</sup> décile - à partir de 0&nbsp;€",
-      shortLabel: "1<sup>er</sup> décile",
-      value: "1",
-    },
-    ...(decilesNiveauDeVieScaleAtInstant ?? []).map(({ rate, threshold }) => ({
-      label: `${formatLongOrdinalSup(Number(rate.value) + 1)} décile - à partir de ${formatCurrency(threshold.value)}`,
-      shortLabel: `${formatLongOrdinalSup(Number(rate.value) + 1)} décile`,
-      value: `${rate.value + 1}`,
-    })),
-  ] as { label: string; shortLabel: string; value: string }[])
-  let shortLabel = $derived(
-    decomposition?.short_label ??
-      variable?.short_label ??
-      decomposition?.name ??
-      variable?.name,
-  )
 </script>
 
 <span class="block text-gray-600"> Filtrer par : </span>
@@ -618,9 +613,8 @@
                 mode="select"
                 situation={testCase}
                 situationIndex={index}
-                valuesByCalculationNameByVariableName={$valuesByCalculationNameByVariableNameArray[
-                  index
-                ]}
+                valuesByCalculationNameByVariableName={shared
+                  .valuesByCalculationNameByVariableNameArray[index]}
                 {year}
               />
             </div>
@@ -636,7 +630,7 @@
                   {shortLabel}&nbsp;:
                   <VariableValueChange
                     bold={true}
-                    evaluationByName={$evaluationByNameArray[index]}
+                    evaluationByName={shared.evaluationByNameArray[index]}
                     inline
                     name={variableName}
                   />
diff --git a/src/lib/components/test_cases/TestCaseGraph.svelte b/src/lib/components/test_cases/TestCaseGraph.svelte
index 5ded260dff3b03f9b028c64548b6bd2ae4247c01..d82aea47f6af8978b014cc9207a5893acef17632 100644
--- a/src/lib/components/test_cases/TestCaseGraph.svelte
+++ b/src/lib/components/test_cases/TestCaseGraph.svelte
@@ -11,8 +11,7 @@
     type RateBracketAtInstant,
     scaleByInstantFromBrackets,
   } from "@openfisca/json-model"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { createEventDispatcher } from "svelte"
   import { fade } from "svelte/transition"
 
   import { page } from "$app/stores"
@@ -39,7 +38,6 @@
   import ValueChangeGraph from "$lib/components/ValueChangeGraph.svelte"
   import {
     buildVisibleDecompositionsForGraph,
-    type DecompositionByName,
     type EvaluationByName,
     type VisibleDecompositionForGraph,
   } from "$lib/decompositions"
@@ -59,9 +57,9 @@
     rootParameterByReformName,
   } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
+  import { billActive, billName, shared, yearPLF } from "$lib/shared.svelte"
   import {
     type ActiveSlider,
-    type CalculationByName,
     getSituationVariableValue,
     setSituationVariableValue,
     type Situation,
@@ -73,7 +71,6 @@
   } from "$lib/variables"
 
   interface Props {
-    decompositionByName: DecompositionByName
     displayMode: DisplayMode
     evaluationByName: EvaluationByName
     evaluationByNameArray: EvaluationByName[] | undefined
@@ -87,9 +84,9 @@
     year: number
   }
 
-  const { childrenKey, familyEntityKey, reformName } = publicConfig
+  const { childrenKey, familyEntityKey } = publicConfig
+
   let {
-    decompositionByName,
     displayMode,
     evaluationByName,
     evaluationByNameArray,
@@ -103,10 +100,6 @@
     year,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
   const dispatch = createEventDispatcher()
   const familyEntity = entityByKey[familyEntityKey]
   const formatCurrency = valueFormatter(0, "currency-EUR", false)
@@ -131,7 +124,6 @@
     ["one", "er"],
   ])
   let svgPadding = { bottom: 20, left: 8, right: 20, top: 20 }
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   let grapheExplanationOpen = $state(false)
   let maxVariableValue: number = $state()
@@ -528,7 +520,7 @@
   let visibleDecompositionsGraph = $derived(
     situation.slider !== undefined
       ? buildVisibleDecompositionsForGraph(
-          decompositionByName,
+          shared.decompositionByName,
           entityByKey,
           evaluationByName,
           situation,
@@ -811,7 +803,7 @@
   // And the children of a reform node parameter always contain the children of the node parameter
   // before reform (albeit with some different value parameters).
   let billRootParameter = $derived(
-    rootParameterByReformName[reformName] ?? rootParameter,
+    rootParameterByReformName[billName] ?? rootParameter,
   )
   let decilesNiveauDeVieParameter = $derived(
     asScaleParameter(getParameter(billRootParameter, "deciles_niveau_de_vie")),
@@ -863,7 +855,7 @@
     ),
   )
   let isCalculationRunning = $derived(
-    Object.values($calculationByName).filter(
+    Object.values(shared.calculationByName).filter(
       (calculation) =>
         calculation.running &&
         (calculation.situationIndex === undefined ||
@@ -1072,8 +1064,9 @@
                           </div>
                         {/if}
                         <span class="mx-2">
-                          {decompositionByName[variable.name]?.short_label ??
-                            decompositionByName[variable.name]?.label}
+                          {shared.decompositionByName[variable.name]
+                            ?.short_label ??
+                            shared.decompositionByName[variable.name]?.label}
                           {row.calculationName === "amendment"
                             ? "(réforme)"
                             : row.calculationName === "bill"
@@ -1641,10 +1634,10 @@
                           <span class="font-normal text-black">
                             Cette échelle indique à quel décile de niveau de vie
                             correspondent les salaires des 100 cas types fictifs
-                            du graphique, dans le cadre du {#if $billActive}
-                              droit {$yearPLF} sans PLF/PLSS
+                            du graphique, dans le cadre du {#if billActive}
+                              droit {yearPLF} sans PLF/PLSS
                             {:else}
-                              droit {$yearPLF - 1}
+                              droit {yearPLF - 1}
                             {/if}. Elle s'appuie sur les
                             <a
                               class="lx-link-text"
@@ -1670,10 +1663,10 @@
                     {/snippet}
                   </Tooltip>
                   <span class="text-nowrap text-xs"
-                    >({#if $billActive}
-                      droit {$yearPLF} <br />sans PLF/PLSS
+                    >({#if billActive}
+                      droit {yearPLF} <br />sans PLF/PLSS
                     {:else}
-                      droit {$yearPLF - 1}
+                      droit {yearPLF - 1}
                     {/if})</span
                   >
                 {:else}
diff --git a/src/lib/components/test_cases/TestCaseGraphXlsxExport.svelte b/src/lib/components/test_cases/TestCaseGraphXlsxExport.svelte
index 07a0e70daadc1e1b2a868f25da46778f1e6679f4..b9bc42bb3c103300b5a070296c5522452e8245ea 100644
--- a/src/lib/components/test_cases/TestCaseGraphXlsxExport.svelte
+++ b/src/lib/components/test_cases/TestCaseGraphXlsxExport.svelte
@@ -9,8 +9,6 @@
     type VariableByName,
     type Waterfall,
   } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
   import XLSX from "xlsx-js-style"
 
   import { page } from "$app/stores"
@@ -31,10 +29,8 @@
     rootParameterByReformName,
   } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
-  import {
-    ParameterReformChangeType,
-    type ParametricReform,
-  } from "$lib/reforms"
+  import { ParameterReformChangeType } from "$lib/reforms"
+  import { billActive, billName, budgetDate, shared } from "$lib/shared.svelte"
   import { publishTestCaseSimulation } from "$lib/simulations"
   import {
     getSituationVariableValue,
@@ -59,7 +55,8 @@
     year: number
   }
 
-  const { baseUrl, reformName } = publicConfig
+  const { baseUrl } = publicConfig
+
   let {
     displayMode,
     domain,
@@ -71,8 +68,6 @@
     year,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
-  const budgetDate = getContext("budgetDate") as Writable<string>
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", {
     day: "2-digit",
     month: "2-digit",
@@ -90,23 +85,12 @@
       : unit?.ratio
         ? parseFloat((value * 100).toFixed(8)) // trick to round value * 100
         : value
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const testCases = getContext("testCases") as Writable<Situation[]>
 
   // Note: A reform parameters tree is always more complete than a parameters tree before reform.
   // And the children of a reform node parameter always contain the children of the node parameter
   // before reform (albeit with some different value parameters).
   let billRootParameter = $derived(
-    rootParameterByReformName[reformName] ?? rootParameter,
+    rootParameterByReformName[billName] ?? rootParameter,
   )
 
   async function xlsxExport() {
@@ -131,9 +115,9 @@
       const token = await publishTestCaseSimulation(
         null, // blobImageOpenGraph
         displayMode,
-        $inputInstantsByVariableNameArray,
-        $parametricReform,
-        $testCases,
+        shared.inputInstantsByVariableNameArray,
+        shared.parametricReform,
+        shared.testCases,
       )
       const sheetData = [
         [],
@@ -225,7 +209,7 @@
     const calculationRows = []
     // "Impact code en vigueur" sheet:
     {
-      const sheetName = $billActive
+      const sheetName = billActive
         ? `Impact Code ${year} sans PLF.SS`
         : "Impact code en vigueur"
       const sheetData = []
@@ -252,7 +236,7 @@
     }
 
     // "Impact PLF.SS" sheet:
-    if ($billActive) {
+    if (billActive) {
       const sheetName = `Impact PLF.SS ${year}`
       const sheetData = []
       // Add the column titles
@@ -280,11 +264,11 @@
 
     // "Impact Réforme" sheet:
     {
-      const sheetName = $billActive
+      const sheetName = billActive
         ? `Impact Réforme ${year} vs PLF.SS`
         : "Impact Réforme"
       const sheetData = []
-      if (Object.keys($parametricReform).length > 0) {
+      if (Object.keys(shared.parametricReform).length > 0) {
         // Add the column titles
         sheetData.push([
           "Cas type",
@@ -323,7 +307,7 @@
         [],
       ]
       for (const [parameterName, parameterReform] of Object.entries(
-        $parametricReform,
+        shared.parametricReform,
       )) {
         const parameter = getParameter(billRootParameter, parameterName)
         if (parameterReform.type === ParameterReformChangeType.Parameter) {
@@ -336,7 +320,7 @@
           for (const [i, bracketAtInstant] of parameterReform.scale.entries()) {
             const thresholdUnit = getUnitAtDate(
               (parameter as ScaleParameter).threshold_unit,
-              $budgetDate,
+              budgetDate,
             )
 
             const thresholdValue =
@@ -357,7 +341,7 @@
             if (isAmountScale) {
               const amountUnit = getUnitAtDate(
                 asAmountScaleParameter(parameter as ScaleParameter).amount_unit,
-                $budgetDate,
+                budgetDate,
               )
 
               const amountValue =
@@ -388,7 +372,7 @@
 
               const rateUnit = getUnitAtDate(
                 asRateScaleParameter(parameter as ScaleParameter).rate_unit,
-                $budgetDate,
+                budgetDate,
               )
 
               const rateValue =
@@ -440,7 +424,7 @@
         variablesName = new Set([...variablesName, ...newVariablesName])
       }
       const inputInstantsByVariableName =
-        $inputInstantsByVariableNameArray[situationIndex]
+        shared.inputInstantsByVariableNameArray[situationIndex]
       const entityLabelByKey: { [key: string]: string } = {
         famille: "Famille",
         foyer_fiscal: "Foyer fiscal",
diff --git a/src/lib/components/test_cases/TestCaseScreenshotLayout.svelte b/src/lib/components/test_cases/TestCaseScreenshotLayout.svelte
index 2ae9a40f18408dea8f574c4ee6a4a57abe41da9a..51dad7546e6db2f5be15cfcaafc74cfc9e26ed31 100644
--- a/src/lib/components/test_cases/TestCaseScreenshotLayout.svelte
+++ b/src/lib/components/test_cases/TestCaseScreenshotLayout.svelte
@@ -1,11 +1,9 @@
 <script lang="ts">
   import TestCaseSummary from "$lib/components/test_cases/TestCaseSummary.svelte"
   import VariableValueChange from "$lib/components/variables/VariableValueChange.svelte"
-  import type {
-    DecompositionByName,
-    EvaluationByName,
-  } from "$lib/decompositions"
+  import type { EvaluationByName } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
+  import { shared } from "$lib/shared.svelte"
   import type { Situation } from "$lib/situations"
   import {
     type ValuesByCalculationNameByVariableName,
@@ -13,7 +11,6 @@
   } from "$lib/variables.js"
 
   interface Props {
-    decompositionByName: DecompositionByName
     displayMode: DisplayMode
     evaluationByNameArray: EvaluationByName[]
     testCase: Situation
@@ -23,7 +20,6 @@
   }
 
   let {
-    decompositionByName,
     displayMode,
     evaluationByNameArray,
     testCase,
@@ -71,11 +67,12 @@
       >
         {#if displayMode.parametersVariableName !== undefined}
           <p class="block px-1 text-start text-sm text-gray-500">
-            {decompositionByName[displayMode.parametersVariableName]
+            {shared.decompositionByName[displayMode.parametersVariableName]
               ?.short_label ??
               variableSummaryByName[displayMode.parametersVariableName]
                 ?.short_label ??
-              decompositionByName[displayMode.parametersVariableName]?.label ??
+              shared.decompositionByName[displayMode.parametersVariableName]
+                ?.label ??
               variableSummaryByName[displayMode.parametersVariableName]
                 ?.label}&nbsp;:
             <VariableValueChange
diff --git a/src/lib/components/test_cases/TestCaseSelectModal.svelte b/src/lib/components/test_cases/TestCaseSelectModal.svelte
index fab01e169c1db221fd530f995cd721974f8fe2a7..82a4fb82adc7713055876a65dc746a9e549a4f38 100644
--- a/src/lib/components/test_cases/TestCaseSelectModal.svelte
+++ b/src/lib/components/test_cases/TestCaseSelectModal.svelte
@@ -1,12 +1,12 @@
 <script lang="ts">
   import { Dialog } from "bits-ui"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { createEventDispatcher } from "svelte"
+  import { fade } from "svelte/transition"
 
   import { goto } from "$app/navigation"
   import TestCaseFilters from "$lib/components/test_cases/TestCaseFilters.svelte"
   import type { DisplayMode } from "$lib/displays"
-  import type { Situation } from "$lib/situations"
+  import { shared } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
 
   interface Props {
@@ -18,8 +18,6 @@
   let { displayMode, isOpen = $bindable(false), year }: Props = $props()
 
   const dispatch = createEventDispatcher()
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
 
   function changeTestCaseIndex(value: number) {
     isOpen = false
@@ -37,7 +35,7 @@
   onOpenChange={(open) => {
     isOpen = open
     if (!isOpen) {
-      dispatch("changeTestCasesIndex", $testCasesIndex)
+      dispatch("changeTestCasesIndex", shared.testCasesIndex)
     }
   }}
   open={isOpen}
@@ -45,9 +43,14 @@
   <Dialog.Portal>
     <Dialog.Overlay
       class="fixed inset-0 z-50 bg-gray-500 opacity-50 transition-opacity"
+      transition={fade}
+      transitionConfig={{ duration: 150 }}
     />
+    <!-- TODO svelte5: transition -->
     <Dialog.Content
       class="fixed left-1/2 top-1/2 z-50 flex max-h-[85%] w-full max-w-6xl -translate-x-1/2 -translate-y-1/2 transform flex-col overflow-hidden rounded-md bg-white p-6 text-left shadow-xl transition-all"
+      transition={fade}
+      transitionConfig={{ duration: 200 }}
     >
       <Dialog.Title class="mb-4 text-2xl font-bold 2xl:text-3xl"
         >Choisir un cas type</Dialog.Title
@@ -56,7 +59,7 @@
         <TestCaseFilters
           {displayMode}
           on:select={({ detail }) => changeTestCaseIndex(detail)}
-          testCases={$testCases}
+          testCases={shared.testCases}
           variableName={displayMode.parametersVariableName}
           {year}
         />
diff --git a/src/lib/components/test_cases/TestCaseSummary.svelte b/src/lib/components/test_cases/TestCaseSummary.svelte
index 2bbc50e39dd9c6f3572b5050fbe1c6ead4d9b7bd..e822733909184e9845fa487a0a18f6affabffb0b 100644
--- a/src/lib/components/test_cases/TestCaseSummary.svelte
+++ b/src/lib/components/test_cases/TestCaseSummary.svelte
@@ -7,8 +7,7 @@
     ValueParameter,
   } from "@openfisca/json-model"
   import deepEqual from "deep-equal"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { createEventDispatcher } from "svelte"
 
   import { page } from "$app/stores"
   import PictoBigAdulteRetraite from "$lib/components/pictos/PictoBigAdulteRetraite.svelte"
@@ -27,6 +26,7 @@
   import { entityByKey, personEntityKey } from "$lib/entities"
   import { getParameter, rootParameter } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
+  import { billName } from "$lib/shared.svelte"
   import {
     getCalculatedVariableValueByCalculationName,
     getSituationVariableValue,
@@ -58,9 +58,9 @@
     childrenKey,
     familyEntityKey,
     householdEntityKey,
-    reformName,
     taxableHouseholdEntityKey,
   } = publicConfig
+
   let {
     displayMode,
     mode,
@@ -130,9 +130,9 @@
 
   // Note: A reform variable is always more complete than a variable before reform.
   let variableSummary = $derived(
-    reformName === undefined
+    billName === undefined
       ? variableSummaryByName[displayMode.parametersVariableName]
-      : variableSummaryByNameByReformName[reformName][
+      : variableSummaryByNameByReformName[billName][
           displayMode.parametersVariableName
         ],
   )
diff --git a/src/lib/components/test_cases/TestCaseView.svelte b/src/lib/components/test_cases/TestCaseView.svelte
index d4145d2291faebe776fc79857278e9f37a44fa74..429e0501092e2dfdfd5dba0fc8cedca96736d801 100644
--- a/src/lib/components/test_cases/TestCaseView.svelte
+++ b/src/lib/components/test_cases/TestCaseView.svelte
@@ -1,8 +1,4 @@
 <script lang="ts">
-  import type { Waterfall } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
   import {
     isNullVariableValueByCalculationName,
     variableValueByCalculationNameFromEvaluation,
@@ -12,18 +8,12 @@
   import OilSpendingBill from "$lib/components/test_cases/OilSpendingBill.svelte"
   import TestCaseSummary from "$lib/components/test_cases/TestCaseSummary.svelte"
   import TestCaseTab from "$lib/components/test_cases/TestCaseTab.svelte"
-  import Tooltip from "$lib/components/Tooltip.svelte"
   import VariableValueChange from "$lib/components/variables/VariableValueChange.svelte"
   import WaterfallView from "$lib/components/WaterfallView.svelte"
-  import type {
-    DecompositionByName,
-    EvaluationByName,
-  } from "$lib/decompositions"
   import { waterfalls } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
-  import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
-  import type { CalculationByName, Situation } from "$lib/situations"
+  import { billName, revaluationName, shared } from "$lib/shared.svelte"
+  import type { Situation } from "$lib/situations"
   import type { TabsConfig } from "$lib/tabs"
   import { newSimulationUrl } from "$lib/urls"
   import {
@@ -34,7 +24,6 @@
   } from "$lib/variables"
 
   interface Props {
-    decompositionByName: DecompositionByName
     displayMode: DisplayMode
     highlightDecomposition?: boolean
     situation: Situation
@@ -44,9 +33,7 @@
     year: number
   }
 
-  const { reformName, revaluationName } = publicConfig
   let {
-    decompositionByName,
     displayMode,
     highlightDecomposition = false,
     situation,
@@ -65,19 +52,7 @@
     tvaVariableName: `tva_sur_${name}`,
   }))
 
-  const calculationByName = getContext(
-    "calculationByName",
-  ) as Writable<CalculationByName>
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const showNulls = getContext("showNulls") as Writable<boolean>
-  const waterfall = getContext("waterfall") as Writable<Waterfall>
-
-  let evaluationByName = $derived($evaluationByNameArray[situationIndex])
+  let evaluationByName = $derived(shared.evaluationByNameArray[situationIndex])
 </script>
 
 <div
@@ -137,11 +112,11 @@
                   {#if displayMode.parametersVariableName !== undefined}
                     <!-- Note: A reform variable is always more complete than a variable before reform. -->
                     {@const variableSummary =
-                      reformName === undefined
+                      billName === undefined
                         ? variableSummaryByName[
                             displayMode.parametersVariableName
                           ]
-                        : variableSummaryByNameByReformName[reformName][
+                        : variableSummaryByNameByReformName[billName][
                             displayMode.parametersVariableName
                           ]}
                     {#if variableSummary !== undefined}
@@ -170,11 +145,11 @@
                 {#if displayMode.parametersVariableName !== undefined}
                   <!-- Note: A reform variable is always more complete than a variable before reform. -->
                   {@const variableSummary =
-                    reformName === undefined
+                    billName === undefined
                       ? variableSummaryByName[
                           displayMode.parametersVariableName
                         ]
-                      : variableSummaryByNameByReformName[reformName][
+                      : variableSummaryByNameByReformName[billName][
                           displayMode.parametersVariableName
                         ]}
                   {#if variableSummary !== undefined}
@@ -184,22 +159,22 @@
                           variableValueByCalculationNameFromEvaluation(
                             evaluationByName[name],
                             revaluationName,
-                            reformName,
-                            $parametricReform,
+                            billName,
+                            shared.parametricReform,
                           ),
                         )}
-                      {#if $showNulls || !linkedVariablesValueByCalculationName.every(isNullVariableValueByCalculationName)}
+                      {#if shared.showNulls || !linkedVariablesValueByCalculationName.every(isNullVariableValueByCalculationName)}
                         <ul class="flex flex-col gap-3">
                           {#each variableSummary.linked_added_variables as linkedVariableName, index}
                             {@const linkedVariableValueByCalculationName =
                               linkedVariablesValueByCalculationName[index]}
-                            {#if $showNulls || !isNullVariableValueByCalculationName(linkedVariableValueByCalculationName)}
+                            {#if shared.showNulls || !isNullVariableValueByCalculationName(linkedVariableValueByCalculationName)}
                               {@const linkedVariableSummary =
-                                reformName === undefined
+                                billName === undefined
                                   ? variableSummaryByName[linkedVariableName]
-                                  : variableSummaryByNameByReformName[
-                                      reformName
-                                    ][linkedVariableName]}
+                                  : variableSummaryByNameByReformName[billName][
+                                      linkedVariableName
+                                    ]}
                               <li>
                                 <a
                                   class="cursor-pointer text-sm hover:underline 2xl:text-base"
@@ -235,9 +210,9 @@
             {#if displayMode.parametersVariableName !== undefined}
               <!-- Note: A reform variable is always more complete than a variable before reform. -->
               {@const variableSummary =
-                reformName === undefined
+                billName === undefined
                   ? variableSummaryByName[displayMode.parametersVariableName]
-                  : variableSummaryByNameByReformName[reformName][
+                  : variableSummaryByNameByReformName[billName][
                       displayMode.parametersVariableName
                     ]}
               {#if variableSummary !== undefined}
@@ -267,11 +242,11 @@
                           variableValueByCalculationNameFromEvaluation(
                             evaluationByName[name],
                             revaluationName,
-                            reformName,
-                            $parametricReform,
+                            billName,
+                            shared.parametricReform,
                           ),
                         )}
-                      {#if $showNulls || !linkedVariablesValueByCalculationName.every(isNullVariableValueByCalculationName)}
+                      {#if shared.showNulls || !linkedVariablesValueByCalculationName.every(isNullVariableValueByCalculationName)}
                         <ul
                           class="flex flex-col gap-2 border-t-2 border-gray-200 pt-5 md:gap-5 lg:border-l-2 lg:border-t-0 lg:pl-5 lg:pt-0"
                           class:lg:max-h-[200px]={allowColumnWrap}
@@ -280,13 +255,13 @@
                           {#each linkedVariables as linkedVariableName, index}
                             {@const linkedVariableValueByCalculationName =
                               linkedVariablesValueByCalculationName[index]}
-                            {#if $showNulls || !isNullVariableValueByCalculationName(linkedVariableValueByCalculationName)}
+                            {#if shared.showNulls || !isNullVariableValueByCalculationName(linkedVariableValueByCalculationName)}
                               {@const linkedVariableSummary =
-                                reformName === undefined
+                                billName === undefined
                                   ? variableSummaryByName[linkedVariableName]
-                                  : variableSummaryByNameByReformName[
-                                      reformName
-                                    ][linkedVariableName]}
+                                  : variableSummaryByNameByReformName[billName][
+                                      linkedVariableName
+                                    ]}
                               <li class="flex">
                                 <a
                                   class="cursor-pointer text-sm hover:underline 2xl:text-base"
@@ -347,7 +322,7 @@
                 type="checkbox"
                 value=""
                 class="peer sr-only"
-                bind:checked={$showNulls}
+                bind:checked={shared.showNulls}
               />
               <div
                 class="peer relative h-6 w-11 shrink-0 rounded-full bg-gray-400 after:absolute after:start-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:transition-all after:content-[''] peer-checked:bg-le-vert-500 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-0"
@@ -376,9 +351,9 @@
     <div class="bg-white">
       {#if variableSummaryByName !== undefined}
         {@const completeVariableSummaryByName =
-          reformName === undefined
+          billName === undefined
             ? variableSummaryByName
-            : variableSummaryByNameByReformName[reformName]}
+            : variableSummaryByNameByReformName[billName]}
         <div class="flex w-full justify-between bg-gray-100">
           <!--Impacts et waterfall-->
           <div
@@ -386,11 +361,9 @@
             id="situation_{situationIndex}_waterfall"
           >
             <WaterfallView
-              {decompositionByName}
               {displayMode}
               {evaluationByName}
               {highlightDecomposition}
-              on:changeDecompositionByName
               on:changeSituation
               {situation}
               {situationIndex}
@@ -407,10 +380,10 @@
             {#each waterfalls as { icon, label, name }}
               <a
                 class="flex grow items-center justify-center shadow-inner"
-                class:bg-white={name === $waterfall.name}
-                class:border-le-bleu={name === $waterfall.name}
-                class:border-r-4={name === $waterfall.name}
-                class:shadow-none={name === $waterfall.name}
+                class:bg-white={name === shared.waterfall.name}
+                class:border-le-bleu={name === shared.waterfall.name}
+                class:border-r-4={name === shared.waterfall.name}
+                class:shadow-none={name === shared.waterfall.name}
                 href={newSimulationUrl({
                   ...displayMode,
                   waterfallName: name,
@@ -428,8 +401,8 @@
                     {/if}
                     <span
                       class="ml-2 text-xs uppercase tracking-wide text-gray-600 xl:text-sm"
-                      class:text-le-bleu={name === $waterfall.name}
-                      class:font-bold={name === $waterfall.name}
+                      class:text-le-bleu={name === shared.waterfall.name}
+                      class:font-bold={name === shared.waterfall.name}
                     >
                       {label}
                     </span>
diff --git a/src/lib/components/variables/FormulaView.svelte b/src/lib/components/variables/FormulaView.svelte
index c865d903c55f97bfd37bcc1c09965d954afc069e..61a2b690f5fd0951487fc6cc755e53039a6576be 100644
--- a/src/lib/components/variables/FormulaView.svelte
+++ b/src/lib/components/variables/FormulaView.svelte
@@ -11,6 +11,7 @@
   import { entityByKey } from "$lib/entities"
   import { leafParametersName } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
+  import { shared } from "$lib/shared.svelte"
   import type { Situation } from "$lib/situations"
   import {
     variableSummaryByName,
@@ -40,9 +41,6 @@
   }: Props = $props()
 
   const { openfiscaRepository } = publicConfig
-  const requestedVariablesNameToCalculate = getContext(
-    "requestedVariablesNameToCalculate",
-  ) as Writable<Set<string> | undefined>
 
   let extraction = $derived(
     extractFromFormulaAst(
@@ -52,8 +50,8 @@
     ),
   )
 
-  run(() => {
-    $requestedVariablesNameToCalculate = extraction.openFiscaVariablesName
+  $effect(() => {
+    shared.requestedVariablesNameToCalculate = extraction.openFiscaVariablesName
   })
 
   let openFiscaVariables = $derived(
diff --git a/src/lib/components/variables/InflationLawButton.svelte b/src/lib/components/variables/InflationLawButton.svelte
index a72f212e4a0d5c616f66d919764147a5d06b481f..e73089236246750d0e29f99c7b7b6463f8d86bcb 100644
--- a/src/lib/components/variables/InflationLawButton.svelte
+++ b/src/lib/components/variables/InflationLawButton.svelte
@@ -3,10 +3,8 @@
 
   const bubble = createBubbler()
   import type { ValueParameter } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
-  import publicConfig from "$lib/public_config"
+  import { billName, yearPLF } from "$lib/shared.svelte"
   import { formatValue } from "$lib/values"
 
   interface Props {
@@ -14,11 +12,8 @@
     parameterName: string | undefined
   }
 
-  const { reformName } = publicConfig
   let { inflatorByReformName, parameterName }: Props = $props()
 
-  const yearPLF = getContext("yearPLF") as Writable<number>
-
   let inflatorWithLatestByReformName = $derived(
     Object.fromEntries(
       Object.entries(inflatorByReformName ?? []).map(
@@ -47,9 +42,9 @@
 
   // Latest inflator
   let billInflator = $derived(
-    reformName === undefined
+    billName === undefined
       ? undefined
-      : inflatorWithLatestByReformName?.[reformName],
+      : inflatorWithLatestByReformName?.[billName],
   )
   let billInflatorValueFormatted = $derived(
     billInflator?.values !== undefined
@@ -66,7 +61,7 @@
   ></iconify-icon>
 
   <p class="text-left font-bold tracking-wider">
-    Droit attendu pour {$yearPLF}
+    Droit attendu pour {yearPLF}
     <br />
     <span class="text-sm font-normal tracking-wide">
       {#if parameterName?.startsWith("impot_revenu.bareme_ir_depuis_1945.bareme")}
diff --git a/src/lib/components/variables/InflationLawDetails.svelte b/src/lib/components/variables/InflationLawDetails.svelte
index 250b89ed5c189e19475aa9951d065a3a18dd3130..140995bc378d28b400fba2ef77d2a4bbbd39c764 100644
--- a/src/lib/components/variables/InflationLawDetails.svelte
+++ b/src/lib/components/variables/InflationLawDetails.svelte
@@ -4,10 +4,8 @@
     type ScaleParameter,
     type ValueParameter,
   } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
-  import publicConfig from "$lib/public_config"
+  import { billName, revaluationName, yearPLF } from "$lib/shared.svelte"
   import { getUnitAtDate } from "$lib/units"
   import { formatValue, removeNegativeZero } from "$lib/values"
 
@@ -18,7 +16,6 @@
     revaluationParameter: ScaleParameter | ValueParameter
   }
 
-  const { revaluationName } = publicConfig
   let {
     billParameter,
     inflatorByReformName,
@@ -30,7 +27,6 @@
     new Intl.NumberFormat("fr-FR", {
       style: "decimal",
     }).format(removeNegativeZero(value))
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   let parameterIsScale = $derived(billParameter.class === ParameterClass.Scale)
 
@@ -155,7 +151,7 @@
       : undefined,
   )
 
-  let billInflator = $derived(inflatorWithLatestByReformName?.[reformName])
+  let billInflator = $derived(inflatorWithLatestByReformName?.[billName])
   let billInflatorValueFormatted = $derived(
     billInflator !== undefined
       ? formatValue(billInflator.values["latest"].value, billInflator.unit)
@@ -176,13 +172,13 @@
     <p class="mt-2 text-gray-600">
       <span class="rounded-sm bg-gray-100 p-1 font-bold"
         >{lawValueFormatted}&nbsp;€
-        <span class="text-xs font-normal">{$yearPLF - 1}</span>
+        <span class="text-xs font-normal">{yearPLF - 1}</span>
         {#if showBillInflator}
           <span class="text-sm text-le-rouge-bill">
             <iconify-icon
               class="align-[-0.3rem] text-xl"
               icon="mdi-arrow-right-bold"
-            ></iconify-icon>Le PLF {$yearPLF} augmente ce montant de
+            ></iconify-icon>Le PLF {yearPLF} augmente ce montant de
             <span class="text-base font-bold">{billInflatorValueFormatted}</span
             >.
           </span>
@@ -195,7 +191,7 @@
             ></iconify-icon></span
           ><span class="rounded-sm bg-gray-100 p-1 font-bold text-black"
             >{revaluationValueFormatted}&nbsp;€
-            <span class="text-xs font-normal">{$yearPLF}</span></span
+            <span class="text-xs font-normal">{yearPLF}</span></span
           >
         {/if}
       </span>
@@ -211,7 +207,7 @@
         <iconify-icon
           class="rotate-90 align-[-0.3rem] text-xl"
           icon="mdi-arrow-up-bold"
-        ></iconify-icon>Le PLF {$yearPLF} augmente les seuils de {billInflatorValueFormatted}.
+        ></iconify-icon>Le PLF {yearPLF} augmente les seuils de {billInflatorValueFormatted}.
       </p>
     {:else}
       <p
@@ -220,7 +216,7 @@
         <iconify-icon
           class="rotate-90 align-[-0.3rem] text-xl"
           icon="mdi-arrow-up-bold"
-        ></iconify-icon>En {$yearPLF}, les seuils augmentent de {revaluationInflatorValueFormatted}.
+        ></iconify-icon>En {yearPLF}, les seuils augmentent de {revaluationInflatorValueFormatted}.
       </p>
     {/if}
   {/if}
@@ -247,7 +243,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_impot_revenu.plaf_qf.decote.seuil_couple") || parameterName?.startsWith("impot_revenu.calcul_impot_revenu.plaf_qf.decote.seuil_celib")}
   <p class="font-serif text-lg">
-    En {$yearPLF}, il est attendu que les
+    En {yearPLF}, il est attendu que les
     <strong>seuils de la décote soient revalorisés.</strong>
   </p>
 
@@ -271,7 +267,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_impot_revenu.plaf_qf.plafond_avantages_procures_par_demi_part.general") || parameterName?.startsWith("impot_revenu.calcul_impot_revenu.plaf_qf.plafond_avantages_procures_par_demi_part.celib")}
   <p class="font-serif text-lg">
-    En {$yearPLF}, il est attendu que
+    En {yearPLF}, il est attendu que
     <strong
       >les paramètres de plafonnement des effets du quotient familial sur
       l'impôt sur le revenu soient revalorisés.</strong
@@ -298,7 +294,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_impot_revenu.plaf_qf.plafond_avantages_procures_par_demi_part.reduc_postplafond")}
   <p class="font-serif text-lg">
-    En {$yearPLF}, il est attendu que
+    En {yearPLF}, il est attendu que
     <strong
       >les réductions d'impôt pour invalides, anciens combattants ou veufs avec
       enfants à charge, intervenant si le plafonnement a été atteint, soient
@@ -326,7 +322,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_revenus_imposables.abat_rni.enfant_marie.montant")}
   <p class="font-serif text-lg">
-    En {$yearPLF}, il est attendu que
+    En {yearPLF}, il est attendu que
     <strong
       >l'abattement spécial pour enfants mariés à charge soit revalorisé.</strong
     >
@@ -352,7 +348,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_reductions_impots.dons.dons_coluche.plafond")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant maximum de dons dits « Coluche » suivra l'augmentation
       appliquée par le PLF sur le seuil de la première tranche du barème de
@@ -379,7 +375,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_revenus_imposables.abat_rni.personne_agee_ou_invalide")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >l'abattement spécial pour personne âgée ou invalide suivra l'augmentation
       appliquée par le PLF sur le seuil de la première tranche du barème de
@@ -406,7 +402,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_revenus_imposables.charges_deductibles.accueil_personne_agee.plafond")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant maximum de déduction de charges pour accueil d'une personne
       âgée suivra l'augmentation appliquée par le PLF sur le seuil de la
@@ -433,7 +429,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_revenus_imposables.deductions.abatpen")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant maximum de l'abattement sur les retraites suivra
       l'augmentation appliquée par le PLF sur le seuil de la première tranche du
@@ -460,7 +456,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_revenus_imposables.deductions.abatpro")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant maximum de l'abattement suivra l'augmentation appliquée par le
       PLF sur le seuil de la première tranche du barème de l'impôt sur le
@@ -502,7 +498,7 @@
 
 {#if parameterName?.startsWith("impot_revenu.calcul_revenus_imposables.charges_deductibles.pensions_alimentaires.plafond")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant maximum de déduction par enfant de la pension alimentaire
       suivra l'augmentation appliquée par le PLF sur le seuil de la première
@@ -521,7 +517,7 @@
 
 {#if parameterName?.startsWith("prelevements_sociaux.contributions_sociales.csg.remplacement.seuils")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >les seuils de RFR déterminant le taux de CSG sont revalorisés de {revaluationInflatorValueFormatted}.</strong
     >
@@ -544,7 +540,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.allocations_logement.al_loc2.par_zone")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >les plafonds des loyers sont revalorisés de {revaluationInflatorValueFormatted}.</strong
     >
@@ -566,7 +562,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.allocations_logement.al_charge")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant forfaitaire des charges est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
@@ -588,7 +584,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.allocations_logement.al_etudiant")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >les équivalences de loyer et de charges locatives sont revalorisées de {revaluationInflatorValueFormatted}.</strong
     >
@@ -610,7 +606,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.allocations_logement.al_plaf_logement_foyer")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >les équivalences de loyer et de charges locatives sont revalorisées de {revaluationInflatorValueFormatted}.</strong
     >
@@ -632,7 +628,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.allocations_logement.al_loc2.montant_forfaitaire_participation_minimale_po")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le terme constant «&nbsp;P0&nbsp;» de la participation personnelle du
       ménage est revalorisé de {revaluationInflatorValueFormatted}.</strong
@@ -655,7 +651,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.allocations_logement.al_param_r0.r0")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le paramètre de calcul des ressources «&nbsp;R0&nbsp;» est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
@@ -679,7 +675,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_logement.ressources.dar_4") || parameterName?.startsWith("prestations_sociales.aides_logement.ressources.dar_5") || parameterName?.startsWith("prestations_sociales.aides_logement.ressources.dar_11") || parameterName?.startsWith("prestations_sociales.aides_logement.ressources.dar_12")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le forfait de ressources pour les étudiants est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
@@ -702,7 +698,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.solidarite_insertion.minima_sociaux.ppa.pa_m.montant_de_base")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant de base de la prime d'activité est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
@@ -733,7 +729,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.solidarite_insertion.minima_sociaux.rsa.rsa_m.montant_de_base_du_rsa")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant de base du RSA est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
@@ -764,7 +760,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.solidarite_insertion.minimum_vieillesse.aspa.plafond_ressources") || parameterName?.startsWith("prestations_sociales.solidarite_insertion.minimum_vieillesse.aspa.montant_maximum_annuel")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant et le plafond de ressources de l'ASPA sont revalorisés de {revaluationInflatorValueFormatted}.</strong
     >
@@ -795,7 +791,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.prestations_etat_de_sante.invalidite.asi.plafond_ressource_couple") || parameterName?.startsWith("prestations_sociales.prestations_etat_de_sante.invalidite.asi.plafond_ressource_seul")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant et le plafond de ressources de l'ASI sont revalorisés de {revaluationInflatorValueFormatted}.</strong
     >
@@ -826,7 +822,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.aides_jeunes.contrat_engagement_jeune.montants")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >les montants du contrat d'engagement jeune sont revalorisés de {revaluationInflatorValueFormatted}.</strong
     >
@@ -857,7 +853,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.prestations_etat_de_sante.invalidite.aah.montant")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant maximal mensuel de l'AAH est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
@@ -888,7 +884,7 @@
 
 {#if parameterName?.startsWith("prestations_sociales.prestations_familiales.bmaf.bmaf")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le montant de la base mensuelle des allocations familiales est revalorisé
       de {revaluationInflatorValueFormatted}.</strong
@@ -920,7 +916,7 @@
 
 {#if parameterName?.startsWith("prelevements_sociaux.pss")}
   <p class="font-serif text-lg">
-    En {$yearPLF},
+    En {yearPLF},
     <strong
       >le plafond de la sécurité sociale est revalorisé de {revaluationInflatorValueFormatted}.</strong
     >
diff --git a/src/lib/components/variables/InflationLawInfoModal.svelte b/src/lib/components/variables/InflationLawInfoModal.svelte
index c17d7fc0031c9bd05da48a6bb66c38de3da21a72..ed0ea5314b0964f2ae136017f4f802bb85b6ceeb 100644
--- a/src/lib/components/variables/InflationLawInfoModal.svelte
+++ b/src/lib/components/variables/InflationLawInfoModal.svelte
@@ -5,12 +5,10 @@
     Reference,
   } from "@openfisca/json-model"
   import { Dialog } from "bits-ui"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import ArticleModal from "$lib/components/parameters/ArticleModal.svelte"
   import InflationLawDetails from "$lib/components/variables/InflationLawDetails.svelte"
-  import publicConfig from "$lib/public_config"
+  import { billName, yearPLF } from "$lib/shared.svelte"
 
   interface Props {
     isOpen?: boolean
@@ -20,7 +18,6 @@
     revaluationParameter: ScaleParameter | ValueParameter
   }
 
-  const { reformName } = publicConfig
   let {
     isOpen = $bindable(false),
     billParameter,
@@ -30,11 +27,10 @@
   }: Props = $props()
 
   let openReferenceUrl: string | undefined | null = $state(null)
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   // Latest inflator, contains all references.
   let billInflator = $derived(
-    reformName === undefined ? undefined : inflatorByReformName?.[reformName],
+    billName === undefined ? undefined : inflatorByReformName?.[billName],
   )
 
   let references = $derived(
@@ -70,7 +66,7 @@
       <Dialog.Title
         class="mb-8 w-full text-center text-2xl font-bold md:text-3xl"
       >
-        Droit attendu {$yearPLF}
+        Droit attendu {yearPLF}
         <!--  <div class="text-sm">{billParameter.name}</div>-->
       </Dialog.Title>
 
@@ -88,11 +84,11 @@
             class="rounded-md bg-le-gris-dispositif-ultralight p-4 text-le-gris-dispositif-dark"
           >
             <p class="mb-2 text-lg font-bold">
-              Qu'est-ce que le droit attendu pour {$yearPLF}&nbsp;?
+              Qu'est-ce que le droit attendu pour {yearPLF}&nbsp;?
             </p>
             <p class="text-base leading-6">
               En cette période budgétaire, le simulateur LexImpact se projette
-              en {$yearPLF} pour vous permettre de comprendre et d'évaluer les projets
+              en {yearPLF} pour vous permettre de comprendre et d'évaluer les projets
               de loi de finances (PLF) et de financement de la sécurité sociale (PLFSS).<br
               /><br />
               <span class="font-bold"
@@ -101,20 +97,20 @@
             </p>
             <ul class="list-inside list-disc">
               <li class="py-2">
-                Le droit attendu en {$yearPLF} et ses impacts
+                Le droit attendu en {yearPLF} et ses impacts
                 <span class="italic"
-                  >(prenant en compte les revalorisations automatiques pour {$yearPLF}
+                  >(prenant en compte les revalorisations automatiques pour {yearPLF}
                   explicitées dans la loi)</span
-                >. Lorsque le droit attendu en {$yearPLF} est différent du droit
-                en vigueur en {$yearPLF - 1}, ce dernier est spécifié en petit
-                au dessus de la valeur {$yearPLF}&nbsp;;
+                >. Lorsque le droit attendu en {yearPLF} est différent du droit en
+                vigueur en {yearPLF - 1}, ce dernier est spécifié en petit au
+                dessus de la valeur {yearPLF}&nbsp;;
               </li>
               <li class="py-2">
-                Les PLF {$yearPLF} & PLFSS {$yearPLF}, ainsi que leurs
+                Les PLF {yearPLF} & PLFSS {yearPLF}, ainsi que leurs
                 impacts&nbsp;;
               </li>
               <li class="py-2">
-                Votre réforme pour l'année {$yearPLF} et ses impacts.
+                Votre réforme pour l'année {yearPLF} et ses impacts.
               </li>
             </ul>
           </div>
diff --git a/src/lib/components/variables/VariableDetail.svelte b/src/lib/components/variables/VariableDetail.svelte
index 6483910fa65ccfa9f883a3c86c79daf042f8445d..b6386e0aa839219db29d9818c2f9f362b76a597e 100644
--- a/src/lib/components/variables/VariableDetail.svelte
+++ b/src/lib/components/variables/VariableDetail.svelte
@@ -1,17 +1,12 @@
 <script lang="ts">
   import { run } from "svelte/legacy"
 
-  import { createEventDispatcher, getContext } from "svelte"
+  import { createEventDispatcher } from "svelte"
   import { quartOut } from "svelte/easing"
-  import type { Writable } from "svelte/store"
   import { fade, fly } from "svelte/transition"
 
   import { goto } from "$app/navigation"
-  import type { BudgetSimulation } from "$lib/budgets"
-  import {
-    requestAllBudgetCalculations,
-    type RequestedCalculations,
-  } from "$lib/calculations.svelte"
+  import { requestAllBudgetCalculations } from "$lib/calculations.svelte"
   import { clickOutside } from "$lib/click_outside"
   import Accordion from "$lib/components/accordion/Accordion.svelte"
   import AccordionItem from "$lib/components/accordion/AccordionItem.svelte"
@@ -23,13 +18,11 @@
   import {
     decompositionCoreByName,
     decompositionCoreByNameByReformName,
-    type EvaluationByName,
     getLatestCalculation,
   } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { memoUrlByName } from "$lib/memos"
-  import publicConfig from "$lib/public_config"
-  import type { Situation } from "$lib/situations"
+  import { billName, shared, year } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
   import {
     budgetVariablesName,
@@ -42,23 +35,14 @@
     name: string
   }
 
-  const { reformName } = publicConfig
   let { displayMode, name }: Props = $props()
 
-  const budgetSimulation = getContext("budgetSimulation") as Writable<
-    BudgetSimulation | undefined
-  >
   let budgetSimulationOutdated = $state(false)
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", {
     dateStyle: "medium",
   }).format
   const dispatch = createEventDispatcher()
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
   let innerHeight: number = $state()
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const year = getContext("year") as Writable<number>
 
   function requestBudgetCalculations() {
     if (budgetVariablesName.has(name)) {
@@ -70,7 +54,7 @@
   // before reform.
   // → Non reform decomposition is not needed.
   let latestDecompositionCoreByName = $derived(
-    decompositionCoreByNameByReformName[reformName] ?? decompositionCoreByName,
+    decompositionCoreByNameByReformName[billName] ?? decompositionCoreByName,
   )
   let latestDecompositionCore = $derived(latestDecompositionCoreByName[name])
   let decomposition = $derived(
@@ -84,7 +68,7 @@
   // Note: A reform variable is always more complete than a variable before reform.
   // But it may contain different formulas, with different parameters & variables.
   let latestVariableSummaryByName = $derived(
-    variableSummaryByNameByReformName[reformName] ?? variableSummaryByName,
+    variableSummaryByNameByReformName[billName] ?? variableSummaryByName,
   )
   let variable = $derived(latestVariableSummaryByName[name])
   run(() => {
@@ -113,7 +97,7 @@
     decomposition?.reference ?? variable?.reference,
   )
   let indexedTestCases = $derived(
-    $testCases
+    shared.testCases
       .map((situation, situationIndex) => ({ situation, situationIndex }))
       .filter(
         ({ situation }) => situation.linked_variables?.[name] !== undefined,
@@ -151,9 +135,9 @@
       ),
   )
   let nonNullTestCases = $derived(
-    $testCases.reduce((arr, curr, index) => {
+    shared.testCases.reduce((arr, curr, index) => {
       const latestCalculationValue = getLatestCalculation(
-        $evaluationByNameArray[index][name]?.calculationEvaluationByName,
+        shared.evaluationByNameArray[index][name]?.calculationEvaluationByName,
       )?.deltaAtVectorIndex
       if (latestCalculationValue !== undefined && latestCalculationValue > 0) {
         const [titleBoldPart, titleRegularPart] = curr.title.split("|")
@@ -318,19 +302,19 @@
         title="Impacts budgétaires"
       >
         {#if budgetVariablesName.has(name)}
-          {#if budgetSimulationOutdated || $budgetSimulation === undefined}
+          {#if budgetSimulationOutdated || shared.budgetSimulation === undefined}
             <div class="flex animate-pulse-2 flex-col gap-2">
               <div class="mr-64 h-6 self-stretch bg-neutral-300"></div>
               <div class="mr-48 h-6 self-stretch bg-neutral-300"></div>
             </div>
-          {:else if $budgetSimulation.errors != null && $budgetSimulation.errors.length > 0}
-            {#each $budgetSimulation.errors as error}
+          {:else if shared.budgetSimulation.errors != null && shared.budgetSimulation.errors.length > 0}
+            {#each shared.budgetSimulation.errors as error}
               <span class="text-base">{error}</span>
             {/each}
           {:else}
             <span class="text-base xl:text-lg">
               <VariableDetailBudget
-                budgetSimulation={$budgetSimulation}
+                budgetSimulation={shared.budgetSimulation}
                 {name}
               /></span
             >
@@ -412,7 +396,7 @@
                       <TestCasePictos
                         classes="[&>svg]:w-7 [&>svg]:h-7 col-span-3 last:odd:col-start-3 justify-center"
                         situation={situations[0]}
-                        year={$year}
+                        {year}
                       />
                     </div>
                   {/if}
@@ -435,7 +419,7 @@
                       {/if}
                       <VariableValueChange
                         bold={true}
-                        evaluationByName={$evaluationByNameArray[index]}
+                        evaluationByName={shared.evaluationByNameArray[index]}
                         inline
                         {name}
                       />
@@ -467,9 +451,9 @@
               }),
             )}
           showOnlyDeciles={false}
-          testCases={$testCases}
+          testCases={shared.testCases}
           variableName={name}
-          year={$year}
+          {year}
         />
       </AccordionItem>
     </Accordion>
diff --git a/src/lib/components/variables/VariableDetailBudget.svelte b/src/lib/components/variables/VariableDetailBudget.svelte
index aaff8adec2ae83510700853ee2bd8ac212ad6943..8404377cdea1db12cd6f8a2cadb3885b69d9320e 100644
--- a/src/lib/components/variables/VariableDetailBudget.svelte
+++ b/src/lib/components/variables/VariableDetailBudget.svelte
@@ -4,7 +4,6 @@
 
   import type { BudgetSimulation } from "$lib/budgets"
   import ValueChange from "$lib/components/ValueChange.svelte"
-  import type { DecompositionByName } from "$lib/decompositions"
   import {
     type BudgetVariable,
     budgetVariableNameByVariableName,
@@ -12,6 +11,7 @@
     variableSummaryByName,
     type VariableValueByCalculationName,
   } from "$lib/variables"
+  import { shared } from "$lib/shared.svelte"
 
   interface Props {
     budgetSimulation: BudgetSimulation
@@ -20,10 +20,6 @@
 
   let { budgetSimulation, name }: Props = $props()
 
-  const decompositionByName = getContext(
-    "decompositionByName",
-  ) as Writable<DecompositionByName>
-
   function buildBudgetValueByCalculationName(
     type: string,
     variableName: string,
@@ -94,9 +90,9 @@
   let budgetVariable = $derived({
     ...budgetVariablesConfig[budgetVariableName],
     label:
-      $decompositionByName[budgetVariableName]?.short_label ??
+      shared.decompositionByName[budgetVariableName]?.short_label ??
       variableSummaryByName[budgetVariableName].short_label ??
-      $decompositionByName[budgetVariableName]?.label ??
+      shared.decompositionByName[budgetVariableName]?.label ??
       variableSummaryByName[budgetVariableName].label,
     name: budgetVariableName,
   } as BudgetVariable & { label: string; name: string })
diff --git a/src/lib/components/variables/VariableReferredInputsPane.svelte b/src/lib/components/variables/VariableReferredInputsPane.svelte
index 4afa8a22b172896eccd0d8a2908f94677cc297fb..0089edac87203a39627916bea74f6249690b8191 100644
--- a/src/lib/components/variables/VariableReferredInputsPane.svelte
+++ b/src/lib/components/variables/VariableReferredInputsPane.svelte
@@ -1,9 +1,6 @@
 <script lang="ts">
-  import { run } from "svelte/legacy"
-
-  import type { Variable, Waterfall } from "@openfisca/json-model"
-  import { createEventDispatcher, getContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import type { Variable } from "@openfisca/json-model"
+  import { createEventDispatcher } from "svelte"
 
   import VariableReferredInputs from "./VariableReferredInputs.svelte"
 
@@ -17,6 +14,7 @@
     iterVariableInputVariables,
     variableSummaryByName,
   } from "$lib/variables"
+  import { shared } from "$lib/shared.svelte"
 
   interface Props {
     date: string
@@ -43,14 +41,13 @@
   let currentInputInstantsByVariableName = inputInstantsByVariableName
   let currentSituation = situation
   const dispatch = createEventDispatcher()
-  const waterfall = getContext("waterfall") as Writable<Waterfall>
 
   function getVariableReferredInputs(name: string, date: string): Variable[] {
     const ignoreVariablesName = new Set(
       walkDecompositionsCoreName(
         decompositionCoreByName,
-        $waterfall.name,
-        $waterfall.root,
+        shared.waterfall.name,
+        shared.waterfall.root,
         false,
       ),
     )
@@ -76,16 +73,16 @@
     dispatch("changeSituation", situation)
   }
   let variable = $derived(variableSummaryByName[name])
-  run(() => {
+  $effect(() => {
     if (variable === undefined) {
       console.error(`Variable "${name}" not found`)
     }
   })
   let inputs = $derived(getVariableReferredInputs(name, date))
-  run(() => {
+  $effect(() => {
     updateInputInstantsByVariableName(inputInstantsByVariableName)
   })
-  run(() => {
+  $effect(() => {
     updateSituation(situation)
   })
 </script>
diff --git a/src/lib/components/variables/VariableReferredParameters.svelte b/src/lib/components/variables/VariableReferredParameters.svelte
index 88dc01c1bf91fb17a34c7bee4ea607891bd4b8ab..3cec3008449b8d394237b83c1095311ff9377580 100644
--- a/src/lib/components/variables/VariableReferredParameters.svelte
+++ b/src/lib/components/variables/VariableReferredParameters.svelte
@@ -8,8 +8,6 @@
     type NodeParameter,
     type Parameter,
   } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import VariableHeader from "./VariableHeader.svelte"
   import VariableReferredNodeParameter from "./VariableReferredNodeParameter.svelte"
@@ -29,7 +27,7 @@
     rootParameter,
     rootParameterByReformName,
   } from "$lib/parameters"
-  import publicConfig from "$lib/public_config"
+  import { billActive, billName, revaluationName } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
   import {
     iterVariableParametersName,
@@ -43,17 +41,49 @@
     name: string
   }
 
-  const { reformName, revaluationName } = publicConfig
   let { date, displayMode, name }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
   let openDirectParameters = $state(true)
+
+  function* iterVariableRootParameters(
+    bothRootParameterById: { [id: string]: Parameter },
+    lawRootParameter: NodeParameter,
+    revaluationRootParameter: NodeParameter,
+    billRootParameter: NodeParameter,
+  ): Generator<
+    [Parameter, Parameter | undefined, Parameter, Parameter],
+    void,
+    unknown
+  > {
+    for (const bothChild of Object.values(bothRootParameterById).sort(
+      (bothChild1, bothChild2) =>
+        bothChild1.class === bothChild2.class ||
+        (bothChild1.class !== ParameterClass.Node &&
+          bothChild2.class !== ParameterClass.Node)
+          ? bothChild1.title.localeCompare(bothChild2.title)
+          : bothChild1.class === ParameterClass.Node
+            ? 1
+            : -1,
+    )) {
+      if (bothChild.id === undefined) {
+        // TODO: This is a mistake that shoudn't occur.
+        continue
+      }
+      // Notes:
+      // A reform (bill) parameter is always more complete than a parameter before reform.
+      // A reform never changes the class of a parameter
+      const lawChild = lawRootParameter.children[bothChild.id] // Sometimes undefined
+      const revaluationChild = revaluationRootParameter.children[bothChild.id]
+      const billChild = billRootParameter.children[bothChild.id] // Never undefined
+      yield [bothChild, lawChild, revaluationChild, billChild]
+    }
+  }
   // Note: A reform decomposition is always more complete than a decomposition before reform.
   // And the children of a reform decomposition always contain the children of the decomposition
   // before reform.
   // => Non reform decomposition is not needed.
   let billDecompositionCoreByName = $derived(
-    decompositionCoreByNameByReformName[reformName] ?? decompositionCoreByName,
+    decompositionCoreByNameByReformName[billName] ?? decompositionCoreByName,
   )
   let billDecompositionCore = $derived(billDecompositionCoreByName[name])
   let billDecomposition = $derived(
@@ -67,7 +97,7 @@
   // Note: A reform variable is always more complete than a variable before reform.
   // But it may contain different formulas, with different parameters & variables.
   let billVariableSummaryByName = $derived(
-    variableSummaryByNameByReformName[reformName] ?? variableSummaryByName,
+    variableSummaryByNameByReformName[billName] ?? variableSummaryByName,
   )
   let billVariable = $derived(billVariableSummaryByName[name])
   let lawVariable = $derived(variableSummaryByName[name])
@@ -83,7 +113,7 @@
   // And the children of a reform node parameter always contain the children of the node parameter
   // before reform (albeit with some different value parameters).
   let billRootParameter = $derived(
-    rootParameterByReformName[reformName] ?? revaluationRootParameter,
+    rootParameterByReformName[billName] ?? revaluationRootParameter,
   )
   let bothParametersName = $derived(
     new Set([
@@ -92,7 +122,7 @@
         : iterVariableParametersName(lawVariable, date)),
       ...(billVariable === undefined
         ? []
-        : iterVariableParametersName(billVariable, date, reformName)),
+        : iterVariableParametersName(billVariable, date, billName)),
     ]),
   )
   let bothDirectParametersName = $derived(
@@ -120,40 +150,6 @@
     ),
   )
   let openAllParameters = $state(false)
-
-  function* iterVariableRootParameters(
-    bothRootParameterById: { [id: string]: Parameter },
-    lawRootParameter: NodeParameter,
-    revaluationRootParameter: NodeParameter,
-    billRootParameter: NodeParameter,
-  ): Generator<
-    [Parameter, Parameter | undefined, Parameter, Parameter],
-    void,
-    unknown
-  > {
-    for (const bothChild of Object.values(bothRootParameterById).sort(
-      (bothChild1, bothChild2) =>
-        bothChild1.class === bothChild2.class ||
-        (bothChild1.class !== ParameterClass.Node &&
-          bothChild2.class !== ParameterClass.Node)
-          ? bothChild1.title.localeCompare(bothChild2.title)
-          : bothChild1.class === ParameterClass.Node
-            ? 1
-            : -1,
-    )) {
-      if (bothChild.id === undefined) {
-        // TODO: This is a mistake that shoudn't occur.
-        continue
-      }
-      // Notes:
-      // A reform (bill) parameter is always more complete than a parameter before reform.
-      // A reform never changes the class of a parameter
-      const lawChild = lawRootParameter.children[bothChild.id] // Sometimes undefined
-      const revaluationChild = revaluationRootParameter.children[bothChild.id]
-      const billChild = billRootParameter.children[bothChild.id] // Never undefined
-      yield [bothChild, lawChild, revaluationChild, billChild]
-    }
-  }
 </script>
 
 {#if billDecomposition !== undefined || billVariable !== undefined}
@@ -165,7 +161,7 @@
     />
   </div>
   <!--PLFSS 2025 - Affichage spécifique pour la réduction générale -->
-  {#if $billActive}
+  {#if billActive}
     {#if billVariable.name === "allegement_general"}
       <div class="mx-4 mb-4 rounded-sm bg-red-100 p-1 text-sm">
         <span class="font-bold text-le-rouge-bill"
diff --git a/src/lib/components/variables/VariableReferredScaleParameter.svelte b/src/lib/components/variables/VariableReferredScaleParameter.svelte
index 3b5647488cf8538c09420b5bb9986b4fc6b8ff01..1556cca2eadbaec26244e537743c20011c74de25 100644
--- a/src/lib/components/variables/VariableReferredScaleParameter.svelte
+++ b/src/lib/components/variables/VariableReferredScaleParameter.svelte
@@ -9,14 +9,11 @@
     type ValueParameter,
   } from "@openfisca/json-model"
   import deepEqual from "deep-equal"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import { goto } from "$app/navigation"
   import {
     requestBudgetCalculation,
     requestTestCasesCalculation,
-    type RequestedCalculations,
   } from "$lib/calculations.svelte"
   import ArticleModal from "$lib/components/parameters/ArticleModal.svelte"
   import InflationLawButton from "$lib/components/variables/InflationLawButton.svelte"
@@ -30,12 +27,17 @@
     trackLawEditParameterStatus,
   } from "$lib/matomo"
   import { rootParameterByReformName } from "$lib/parameters"
-  import publicConfig from "$lib/public_config"
   import {
     ParameterReformChangeType,
-    type ParametricReform,
     type ScaleParameterReform,
   } from "$lib/reforms"
+  import {
+    billActive,
+    billName,
+    revaluationName,
+    shared,
+    yearPLF,
+  } from "$lib/shared.svelte"
   import {
     budgetEditableParametersNameByVariableName,
     budgetVariablesName,
@@ -52,7 +54,6 @@
     revaluationParameter: ScaleParameter
   }
 
-  const { reformName, revaluationName } = publicConfig
   let {
     billParameter,
     budget,
@@ -64,15 +65,10 @@
     revaluationParameter,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
     .format
   let isInflationLawInfoModalOpen = $state(false)
   let openReferenceUrl: string | undefined | null = $state(null)
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   function changeScale({ detail: scale }: { detail: ScaleAtInstant }) {
     updateReform(`${date.split("-")[0]}-01-01`, scale)
@@ -100,18 +96,15 @@
       scale !== undefined &&
       Object.keys(scale).length > 0
     ) {
-      $parametricReform = {
-        ...$parametricReform,
-        [billParameter.name as string]: {
-          scale,
-          start,
-          type: ParameterReformChangeType.Scale,
-          variable: displayMode.parametersVariableName,
-        },
+      shared.parametricReform[billParameter.name as string] = {
+        scale,
+        start,
+        type: ParameterReformChangeType.Scale,
+        variable: displayMode.parametersVariableName,
       }
 
       if (deepEqual(scale, billScaleAtInstant)) {
-        delete $parametricReform[billParameter.name]
+        delete shared.parametricReform[billParameter.name]
       }
 
       if (name !== undefined && budgetVariablesName.has(name)) {
@@ -121,7 +114,7 @@
     }
   }
   let change = $derived(
-    $parametricReform[billParameter.name as string] as
+    shared.parametricReform[billParameter.name as string] as
       | ScaleParameterReform
       | undefined,
   )
@@ -220,7 +213,7 @@
                   inflatorType![1]
                 ],
                 ...{
-                  inflator_reference: (reformName === reformName
+                  inflator_reference: (reformName === billName
                     ? billParameter
                     : reformName === revaluationName
                       ? revaluationParameter
@@ -254,15 +247,15 @@
       <div class="ml-8 flex pt-2 text-xs italic">
         <p class="w-20 text-center">
           {#if showRevaluationLabel}
-            <span class="text-[0.6rem]">Droit {$yearPLF - 1}</span>
+            <span class="text-[0.6rem]">Droit {yearPLF - 1}</span>
             <br />
           {/if}
           <span
-            title="Droit attendu en {$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {$yearPLF}."
+            title="Droit attendu en {yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {yearPLF}."
             class="font-bold underline decoration-dotted"
           >
-            {#if $billActive}
-              Droit {$yearPLF} <br />sans PLF/PLSS
+            {#if billActive}
+              Droit {yearPLF} <br />sans PLF/PLSS
             {:else}
               Droit&nbsp;en&nbsp;vigueur
             {/if}</span
@@ -270,13 +263,13 @@
         </p>
         {#if showBillLabel}
           <p class="w-20 text-center font-bold text-le-rouge-bill">
-            PLF/PLFSS<br />{$yearPLF}
+            PLF/PLFSS<br />{yearPLF}
           </p>
         {/if}
         {#if showParametricReformLabel}
           <p class="w-20 text-center font-bold">
             <span class="bg-le-jaune px-2">Votre réforme</span><br /><span
-              class="bg-le-jaune px-2">pour {$yearPLF}</span
+              class="bg-le-jaune px-2">pour {yearPLF}</span
             >
           </p>
         {/if}
diff --git a/src/lib/components/variables/VariableReferredValueParameter.svelte b/src/lib/components/variables/VariableReferredValueParameter.svelte
index e1318d4e78e9f1e9d155f063121ddf87d456c4b2..cce1d0dbff3b5b5e39e230a6999c9f2560c7201f 100644
--- a/src/lib/components/variables/VariableReferredValueParameter.svelte
+++ b/src/lib/components/variables/VariableReferredValueParameter.svelte
@@ -17,14 +17,11 @@
     type ValueAtInstant,
     type ValueParameter,
   } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
 
   import { goto } from "$app/navigation"
   import {
     requestBudgetCalculation,
     requestTestCasesCalculation,
-    type RequestedCalculations,
   } from "$lib/calculations.svelte"
   import ArticleModal from "$lib/components/parameters/ArticleModal.svelte"
   import InflationLawButton from "$lib/components/variables/InflationLawButton.svelte"
@@ -39,12 +36,17 @@
     trackLawEditParameterStatus,
   } from "$lib/matomo"
   import { rootParameterByReformName } from "$lib/parameters"
-  import publicConfig from "$lib/public_config"
   import {
     ParameterReformChangeType,
-    type ParametricReform,
     type ValueParameterReform,
   } from "$lib/reforms"
+  import {
+    billActive,
+    billName,
+    revaluationName,
+    shared,
+    yearPLF,
+  } from "$lib/shared.svelte"
   import { getUnitAtDate, getUnitShortLabel } from "$lib/units"
   import {
     budgetEditableParametersNameByVariableName,
@@ -63,7 +65,6 @@
     revaluationParameter: ValueParameter
   }
 
-  const { reformName, revaluationName } = publicConfig
   let {
     billParameter,
     budget,
@@ -76,7 +77,6 @@
     revaluationParameter,
   }: Props = $props()
 
-  const billActive = getContext("billActive") as Writable<boolean>
   let billLatestInstantValueCouplesArray: [string, ValueAtInstant][] = $derived(
     Object.entries(billParameter.values).sort(([instant1], [instant2]) =>
       instant2.localeCompare(instant1),
@@ -91,9 +91,6 @@
     ),
   )
   let openReferenceUrl: string | null = $state(null)
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
   let revaluationLatestInstantValueCouplesArray: [string, ValueAtInstant][] =
     $derived(
       Object.entries(revaluationParameter?.values ?? []).sort(
@@ -102,7 +99,6 @@
     )
   let validValue = undefined
   let valueError: string | null = $state(null)
-  const yearPLF = getContext("yearPLF") as Writable<number>
 
   function changeValue({ detail: value }: CustomEvent) {
     ;[validValue, valueError] = auditChain(
@@ -140,7 +136,7 @@
   function updateReform(start: string, value: number | undefined) {
     if (start !== undefined && value !== undefined) {
       const updatedParametricReform = {
-        ...$parametricReform,
+        ...shared.parametricReform,
       }
       if (value === billValue.value) {
         delete updatedParametricReform[billParameter.name as string]
@@ -152,7 +148,7 @@
           value,
         }
       }
-      $parametricReform = updatedParametricReform
+      shared.parametricReform = updatedParametricReform
 
       if (name !== undefined && budgetVariablesName.has(name)) {
         requestBudgetCalculation(name, "amendment")
@@ -170,7 +166,7 @@
   let change = $derived(
     billParameter.name === undefined
       ? undefined
-      : ($parametricReform[billParameter.name] as
+      : (shared.parametricReform[billParameter.name] as
           | ValueParameterReform
           | undefined),
   )
@@ -222,7 +218,7 @@
                   inflatorType![1]
                 ],
                 ...{
-                  inflator_reference: (reformName === reformName
+                  inflator_reference: (reformName === billName
                     ? billParameter
                     : reformName === revaluationName
                       ? revaluationParameter
@@ -306,15 +302,15 @@
           >
             <p class="w-20 text-center">
               {#if isRevaluationActive}
-                <span class="text-[0.6rem]">Droit {$yearPLF - 1}</span>
+                <span class="text-[0.6rem]">Droit {yearPLF - 1}</span>
                 <br />
               {/if}
               <span
-                title="Droit attendu en {$yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {$yearPLF}."
+                title="Droit attendu en {yearPLF} suite aux revalorisations automatiques prévues dans la loi, sans les modifications qui seront apportées par le PLF et le PLFSS {yearPLF}."
                 class="font-bold underline decoration-dotted"
               >
-                {#if $billActive}
-                  Droit {$yearPLF} <br />sans PLF/PLSS
+                {#if billActive}
+                  Droit {yearPLF} <br />sans PLF/PLSS
                 {:else}
                   Droit&nbsp;en&nbsp;vigueur
                 {/if}</span
@@ -322,7 +318,7 @@
             </p>
             {#if isBillActive}
               <p class="w-20 text-center font-bold text-le-rouge-bill">
-                PLF/PLFSS {$yearPLF}
+                PLF/PLFSS {yearPLF}
               </p>
             {/if}
             {#if isParametricReformActive}
@@ -350,7 +346,7 @@
         {/if}
       </div>
       <!--Spécial PLF 2025 : Alerte paramètre modifié par le PLF mais pas modifié par LexImpact -->
-      {#if $billActive && billParameter.name?.startsWith("prelevements_sociaux.reductions_cotisations_sociales.allegement_general.ensemble_des_entreprises.plafond")}
+      {#if billActive && billParameter.name?.startsWith("prelevements_sociaux.reductions_cotisations_sociales.allegement_general.ensemble_des_entreprises.plafond")}
         <div class="flex bg-gray-100 px-3">
           <div class="mb-1 rounded-sm bg-red-100 p-1 text-sm">
             <span class="font-bold text-le-rouge-bill"
diff --git a/src/lib/components/variables/VariableValueChange.svelte b/src/lib/components/variables/VariableValueChange.svelte
index e383c1798e7f361ad77d08b02269a43ce9509298..312e180d9dd2c1c768828c1c9e91a096ab2709a4 100644
--- a/src/lib/components/variables/VariableValueChange.svelte
+++ b/src/lib/components/variables/VariableValueChange.svelte
@@ -1,11 +1,7 @@
 <script lang="ts">
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
-
   import ValueChange from "$lib/components/ValueChange.svelte"
   import type { EvaluationByName } from "$lib/decompositions"
-  import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
+  import { billName, date, revaluationName, shared } from "$lib/shared.svelte"
   import { getUnitAtDate } from "$lib/units"
   import {
     variableSummaryByName,
@@ -24,7 +20,6 @@
     bold?: boolean
   }
 
-  const { reformName, revaluationName } = publicConfig
   let {
     compact = false,
     evaluationByName,
@@ -35,17 +30,12 @@
     bold = false,
   }: Props = $props()
 
-  const date = getContext("date") as Writable<string>
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-
   let evaluation = $derived(evaluationByName[name])
 
   let variableSummary = $derived(
-    reformName === undefined
+    billName === undefined
       ? variableSummaryByName[name]
-      : variableSummaryByNameByReformName[reformName][name],
+      : variableSummaryByNameByReformName[billName][name],
   )
 </script>
 
@@ -54,17 +44,17 @@
     {compact}
     {inline}
     {legend}
-    unitName={getUnitAtDate(variableSummary.unit, $date)?.name}
+    unitName={getUnitAtDate(variableSummary.unit, date)?.name}
     valueByCalculationName={valueByCalculationName ?? {
       amendment:
-        Object.keys($parametricReform).length === 0
+        Object.keys(shared.parametricReform).length === 0
           ? undefined
           : Math.abs(
               evaluation?.calculationEvaluationByName["amendment"]
                 ?.deltaAtVectorIndex ?? 0,
             ),
       bill:
-        reformName === undefined
+        billName === undefined
           ? undefined
           : Math.abs(
               evaluation?.calculationEvaluationByName["bill"]
diff --git a/src/lib/components/variables/VariableView.svelte b/src/lib/components/variables/VariableView.svelte
index 6f5ab636b64158fa3b9b00cbe873bd7abed31b1d..7df0ec2c48a0ae1a0bd5ac147dc7bab3254658ef 100644
--- a/src/lib/components/variables/VariableView.svelte
+++ b/src/lib/components/variables/VariableView.svelte
@@ -2,18 +2,17 @@
   import type { Variable } from "@openfisca/json-model"
   import { getContext } from "svelte"
 
-  import { page } from "$app/stores"
   import FormulaView from "$lib/components/variables/FormulaView.svelte"
   import VariableInput from "$lib/components/variables/VariableInput.svelte"
   import { decompositionCoreByName } from "$lib/decompositions"
   import publicConfig from "$lib/public_config"
+  import { date, year } from "$lib/shared.svelte"
   import type { Situation } from "$lib/situations"
   import type { SelfTargetAProps } from "$lib/urls"
   import type { ValuesByCalculationNameByVariableName } from "$lib/variables"
   import { buildInstantFormulaAndReferencesArray } from "$lib/variables"
 
   interface Props {
-    date: string
     editable: boolean
     inputInstantsByVariableName: {
       [name: string]: Set<string>
@@ -22,19 +21,17 @@
     situationIndex: number
     valuesByCalculationNameByVariableName: ValuesByCalculationNameByVariableName
     variable: Variable
-    year: number
   }
 
   const { openfiscaRepository } = publicConfig
+
   let {
-    date,
     editable,
     inputInstantsByVariableName = $bindable(),
     situation = $bindable(),
     situationIndex,
     valuesByCalculationNameByVariableName = $bindable(),
     variable,
-    year,
   }: Props = $props()
 
   const dateFormatter = new Intl.DateTimeFormat("fr-FR", { dateStyle: "full" })
diff --git a/src/lib/shared.svelte.ts b/src/lib/shared.svelte.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4eac4e2266117ee8284e726e718857ba7417a22d
--- /dev/null
+++ b/src/lib/shared.svelte.ts
@@ -0,0 +1,1065 @@
+import "intro.js/introjs.css"
+
+import {
+  getRolePersonsIdKey,
+  type GroupEntity,
+  type PopulationWithoutId,
+  type Waterfall,
+} from "@openfisca/json-model"
+import "iconify-icon"
+import { v4 as uuidV4 } from "uuid"
+
+import type { BudgetSimulation } from "$lib/budgets"
+import {
+  requestAllTestCasesCalculations,
+  type CalculationName,
+  type RequestedSituationIndexByCalculationName,
+} from "$lib/calculations.svelte"
+import {
+  buildDecompositionByNameFromCore,
+  decompositionCoreByName,
+  decompositionCoreByNameByReformName,
+  nonVirtualVariablesName,
+  nonVirtualVariablesNameByReformName,
+  updateEvaluations,
+  updateEvaluationsVectorIndex,
+  waterfalls,
+  type EvaluationByName,
+  type DecompositionByName,
+} from "$lib/decompositions"
+import type { DisplayMode } from "$lib/displays"
+import { entityByKey } from "$lib/entities"
+import { trackTestCaseShowAllVariables } from "$lib/matomo"
+import { metadata } from "$lib/metadata"
+import { getNavbarConfig, type NavbarConfig } from "$lib/navbar"
+import publicConfig from "$lib/public_config"
+import { type ParametricReform, reformMetadataByName } from "$lib/reforms"
+import {
+  extractInputInstantsFromTestCases,
+  getPopulationReservedKeys,
+  indexOfSituationPopulationId,
+  testCasesCore,
+  type Axis,
+  type Calculation,
+  type CalculationByName,
+  type Situation,
+  type SituationWithAxes,
+  type TestCasesCalculationInput,
+} from "$lib/situations"
+import {
+  budgetEditableParametersName,
+  budgetVariableNameByVariableName,
+  budgetVariablesConfig,
+  budgetVariablesName,
+  otherCalculatedVariablesName,
+  summaryCalculatedVariablesName,
+  type BudgetVariable,
+  type ValuesByCalculationNameByVariableName,
+  type VariableValue,
+  type VariableValues,
+  variableSummaryByName,
+  variableSummaryByNameByReformName,
+} from "$lib/variables"
+
+export interface Shared {
+  axes: Axis[][]
+  displayMode?: DisplayMode
+  budgetSimulation?: BudgetSimulation
+  calculationByName: CalculationByName
+  decompositionByName: DecompositionByName
+  evaluationByNameArray: EvaluationByName[]
+  inputInstantsByVariableNameArray: Array<{
+    [name: string]: Set<string>
+  }>
+  navbarConfig: NavbarConfig
+  parametricReform: ParametricReform
+  requestedSimulationEmail?: string // Budget simulation requests
+  requestedSimulationSent: boolean // Budget simulation requests
+  requestedVariablesNameToCalculate?: Set<string> // Budget simulation requests
+  searchActive: boolean // Search
+  searchVariableName?: string // Search
+  showNulls: boolean
+  showTutorial: boolean
+  testCases: Situation[]
+  testCasesIndex: number[]
+  valuesByCalculationNameByVariableNameArray: ValuesByCalculationNameByVariableName[]
+  vectorLength: number
+  waterfall: Waterfall
+}
+
+const { reformName: reformBillName, revaluationName: reformRevaluationName } =
+  publicConfig
+
+let axisBySituationIndex: { [situationIndex: string]: Axis } = {}
+
+let budgetSimulationAbortController = new AbortController()
+
+/**
+ * Bill (PLF) and revaluation (contrefactuel)
+ */
+
+export const billName: string | undefined =
+  reformBillName === undefined
+    ? undefined
+    : reformMetadataByName[reformBillName] === undefined
+      ? undefined
+      : reformBillName
+export const billActive: boolean = billName !== undefined
+
+export const revaluationName: string | undefined =
+  reformRevaluationName === undefined
+    ? undefined
+    : reformMetadataByName[reformRevaluationName] === undefined
+      ? undefined
+      : reformRevaluationName
+
+const today = new Date()
+export const year =
+  today.getFullYear() + (today.getMonth() > 1 /* => After February */ ? 1 : 0)
+export const yearPLF =
+  today.getFullYear() +
+  (billActive && today.getMonth() > 1 /* => After February */ ? 1 : 0)
+export const date = `${year}-01-01`
+export const budgetDate = `${yearPLF}-01-01`
+
+export const shared: Shared = $state({
+  axes: [],
+  calculationByName: {},
+  // Note: We always use the reform decomposition, because it is more
+  // complete than decomposition before reform.
+  decompositionByName: buildDecompositionByNameFromCore(
+    billName === undefined
+      ? decompositionCoreByName
+      : (decompositionCoreByNameByReformName[billName] ??
+          decompositionCoreByName),
+  ),
+  evaluationByNameArray: new Array(testCasesCore.length).fill(
+    {},
+  ) as EvaluationByName[],
+  inputInstantsByVariableNameArray:
+    extractInputInstantsFromTestCases(testCasesCore),
+  navbarConfig: getNavbarConfig("/"),
+  parametricReform: {},
+  requestedSimulationSent: false,
+  searchActive: false,
+  showNulls: false,
+  showTutorial: false,
+  testCases: structuredClone(testCasesCore),
+  testCasesIndex: [],
+  valuesByCalculationNameByVariableNameArray: new Array(
+    testCasesCore.length,
+  ).fill({}),
+  vectorLength: 1,
+  waterfall: waterfalls[0],
+})
+
+// TODO svelte5: remove this and import from calculations
+const calculationNames: CalculationName[] = [
+  "law",
+  "revaluation",
+  "bill",
+  "amendment",
+]
+const testCasesAbortControllers: {
+  [calculationName: string]: AbortController
+} = Object.fromEntries(
+  calculationNames.map((calculationName) => [
+    calculationName,
+    new AbortController(),
+  ]),
+)
+
+const vectorIndexes = new Array(testCasesCore.length).fill(0)
+
+if (shared.showNulls) {
+  trackTestCaseShowAllVariables()
+}
+
+function buildBudgetDemandBody(
+  variableName: string,
+  outputVariables: string[],
+  quantileBaseVariable: string[],
+  quantileCompareVariables: string[],
+  includeDisplay = true,
+) {
+  const budgetParametricReform = Object.fromEntries(
+    Object.entries(shared.parametricReform).filter(([parameterName]) =>
+      budgetEditableParametersName.has(parameterName),
+    ),
+  )
+  return {
+    amendement: budgetParametricReform,
+    base: yearPLF,
+    displayMode: includeDisplay ? shared.displayMode : undefined,
+    metadata,
+    output_variables: outputVariables,
+    quantile_base_variable: quantileBaseVariable,
+    quantile_compare_variables: quantileCompareVariables,
+    winners_loosers_variable: variableName,
+    quantile_nb: 10,
+    plf: billName === undefined ? undefined : yearPLF,
+  }
+}
+
+export async function calculateBudget(
+  budgetVariableName: string,
+  // budgetCalculationNames: Set<CalculationName>,
+): Promise<void> {
+  budgetSimulationAbortController.abort()
+  budgetSimulationAbortController = new AbortController()
+  if (!budgetVariablesName.has(budgetVariableName)) {
+    console.error(
+      `Budget calculation for variable ${budgetVariableName} is not available`,
+    )
+    shared.budgetSimulation = undefined
+    return
+  }
+  const variableName = budgetVariableNameByVariableName[budgetVariableName]
+  const variableConfig: BudgetVariable = budgetVariablesConfig[variableName]
+  const body = JSON.stringify(
+    buildBudgetDemandBody(
+      variableName,
+      variableConfig.outputVariables,
+      variableConfig.quantileBaseVariable,
+      variableConfig.quantileCompareVariables,
+    ),
+  )
+  shared.budgetSimulation = undefined
+  const response = await fetch("/budgets", {
+    body,
+    headers: {
+      Accept: "application/json",
+      "Content-Type": "application/json; charset=utf-8",
+    },
+    method: "POST",
+    signal: budgetSimulationAbortController.signal,
+  })
+  if (!response.ok) {
+    console.error(
+      `${$page.url}: Error while calculating budget:\n${body}\n${response.status} ${response.statusText}`,
+    )
+    console.error(await response.text())
+    shared.budgetSimulation = {
+      errors: [
+        `Une erreur inattendue (${response.status} ${response.statusText}) s'est produite et les impacts budgétaires ne sont pas disponibles pour le moment. Écrivez-nous à leximpact@assemblee-nationale.fr.`,
+      ],
+      isPublic: true,
+    }
+    shared.budgetSimulation = undefined
+    return
+  }
+  shared.budgetSimulation = await response.json()
+}
+
+export async function calculateTestCases(
+  situationIndexByCalculationName: RequestedSituationIndexByCalculationName,
+) {
+  $inspect("3")
+  const aggregatedSituation: SituationWithAxes = {}
+  const axesData: { situationIndex: number; variables: string[] } =
+    shared.axes.reduce(
+      (
+        result: { situationIndex?: number; variables: string[] },
+        parallelAxes,
+      ) => {
+        for (const axis of parallelAxes) {
+          result.situationIndex = axis.situationIndex
+          if (result.variables.includes(axis.name)) {
+            continue
+          }
+          result.variables.push(axis.name)
+        }
+        return result
+      },
+      { variables: [] },
+    )
+  const entities = Object.values(entityByKey)
+  if (
+    Object.values(situationIndexByCalculationName).some(
+      (situationIndex) => situationIndex === null,
+    )
+  ) {
+    $inspect("4")
+    let personIndex = -1
+    // Some of the calculations are requested to be done for every situations.
+    // Aggregate every situations into a single one without calculated variables.
+    for (const [situationIndex, situation] of shared.testCases.entries()) {
+      const inputInstantsByVariableName =
+        shared.inputInstantsByVariableNameArray[situationIndex]
+      const situationPrefix = `Cas type n°${situationIndex + 1} | `
+      for (const entity of entities) {
+        let entitySituation = situation[entity.key_plural as string]
+        if (entitySituation === undefined) {
+          continue
+        }
+        let aggregatedEntitySituation =
+          aggregatedSituation[entity.key_plural as string]
+        if (aggregatedEntitySituation === undefined) {
+          aggregatedEntitySituation = aggregatedSituation[
+            entity.key_plural as string
+          ] = {}
+        }
+        const reservedKeys = getPopulationReservedKeys(entity)
+        for (const [populationId, population] of Object.entries(
+          entitySituation,
+        ).sort(([populationId1], [populationId2]) =>
+          populationId1.localeCompare(populationId2),
+        )) {
+          const transformedPopulation: PopulationWithoutId = {}
+          if (!entity.is_person) {
+            for (const role of (entity as GroupEntity).roles) {
+              const personsIdKey = getRolePersonsIdKey(role)
+              const personsId = population[personsIdKey] as string[] | undefined
+              if (personsId === undefined) {
+                continue
+              }
+              transformedPopulation[personsIdKey] = personsId.map(
+                (personId) => situationPrefix + personId,
+              )
+            }
+          } else {
+            personIndex++
+          }
+          for (const [variableName, variableValueByInstant] of Object.entries(
+            population,
+          )) {
+            if (
+              reservedKeys.has(variableName) ||
+              (entity.is_person &&
+                axesData.situationIndex === personIndex &&
+                axesData.variables.includes(variableName))
+            ) {
+              continue
+            }
+            const inputVariableValueByInstant: {
+              [instant: string]: VariableValue | null
+            } = {}
+            const inputInstants =
+              inputInstantsByVariableName[variableName] ?? new Set<string>()
+            for (const [instant, variableValue] of Object.entries(
+              variableValueByInstant as {
+                [instant: string]: VariableValue | null
+              },
+            )) {
+              if (!inputInstants.has(instant)) {
+                // Ignore calculated value.
+                continue
+              }
+              inputVariableValueByInstant[instant] = variableValue
+            }
+            if (Object.keys(inputVariableValueByInstant).length > 0) {
+              transformedPopulation[variableName] = inputVariableValueByInstant
+            }
+          }
+          aggregatedEntitySituation[situationPrefix + populationId] =
+            transformedPopulation
+        }
+      }
+    }
+
+    if (shared.axes.length > 0) {
+      aggregatedSituation.axes = shared.axes
+    }
+  }
+  $inspect("5")
+
+  const message = {
+    period: year.toString(),
+  }
+  const newCalculationByName: CalculationByName = {}
+
+  const lawSituationIndex = situationIndexByCalculationName.law
+  if (lawSituationIndex !== undefined) {
+    $inspect("6")
+    const calculation: Calculation = (newCalculationByName.law = {
+      running: true,
+    })
+    let situation: SituationWithAxes
+    if (lawSituationIndex === null) {
+      situation = aggregatedSituation
+    } else {
+      calculation.situationIndex = lawSituationIndex
+      situation = cleanSituation(
+        shared.testCases[lawSituationIndex],
+        shared.axes,
+      )
+    }
+    calculation.input = {
+      ...message,
+      situation,
+      variables: [
+        ...summaryCalculatedVariablesName,
+        ...otherCalculatedVariablesName,
+        ...nonVirtualVariablesName,
+      ],
+    }
+    sendTestCasesSimulation("law", calculation.input) // Don't wait for result.
+  }
+  $inspect("7")
+
+  const revaluationSituationIndex = situationIndexByCalculationName.revaluation
+  if (
+    revaluationSituationIndex !== undefined &&
+    revaluationName !== undefined
+  ) {
+    $inspect("8")
+    const calculation: Calculation = (newCalculationByName.revaluation = {
+      running: true,
+    })
+    let situation: SituationWithAxes
+    if (revaluationSituationIndex === null) {
+      situation = aggregatedSituation
+    } else {
+      calculation.situationIndex = revaluationSituationIndex
+      situation = cleanSituation(
+        shared.testCases[revaluationSituationIndex],
+        shared.axes,
+      )
+    }
+    calculation.input = {
+      ...message,
+      reform: revaluationName,
+      situation,
+      variables: [
+        ...summaryCalculatedVariablesName,
+        ...otherCalculatedVariablesName,
+        ...(nonVirtualVariablesNameByReformName[revaluationName] ??
+          nonVirtualVariablesName),
+      ],
+    }
+    sendTestCasesSimulation("revaluation", calculation.input) // Don't wait for result.
+  }
+  $inspect("9")
+
+  const billSituationIndex = situationIndexByCalculationName.bill
+  if (billSituationIndex !== undefined && billActive) {
+    $inspect("10")
+    const calculation: Calculation = (newCalculationByName.bill = {
+      running: true,
+    })
+    let situation: SituationWithAxes
+    if (billSituationIndex === null) {
+      situation = aggregatedSituation
+    } else {
+      calculation.situationIndex = billSituationIndex
+      situation = cleanSituation(
+        shared.testCases[billSituationIndex],
+        shared.axes,
+      )
+    }
+    calculation.input = {
+      ...message,
+      reform: billName,
+      situation,
+      variables: [
+        ...summaryCalculatedVariablesName,
+        ...otherCalculatedVariablesName,
+        ...(nonVirtualVariablesNameByReformName[billName] ??
+          nonVirtualVariablesName),
+      ],
+    }
+    sendTestCasesSimulation("bill", calculation.input) // Don't wait for result.
+  }
+  $inspect("11")
+
+  const amendmentSituationIndex = situationIndexByCalculationName.amendment
+  if (amendmentSituationIndex !== undefined) {
+    $inspect("12")
+    if (Object.keys(shared.parametricReform).length === 0) {
+      // Remove amendment evaluations from decompositions.
+      shared.evaluationByNameArray = shared.evaluationByNameArray.map(
+        (evaluationByName, situationIndex): EvaluationByName => {
+          const updatedEvaluationByName = Object.fromEntries(
+            Object.entries(evaluationByName).map(
+              ([variableName, evaluation]) => {
+                const calculationEvaluationByName = {
+                  ...evaluation.calculationEvaluationByName,
+                }
+                delete calculationEvaluationByName["amendment"]
+                return [
+                  variableName,
+                  { ...evaluation, calculationEvaluationByName },
+                ]
+              },
+            ),
+          )
+          return updateEvaluations(
+            shared.decompositionByName,
+            updatedEvaluationByName,
+            shared.testCases[situationIndex].slider?.vectorIndex ?? 0,
+            shared.vectorLength,
+            waterfalls,
+          )
+        },
+      )
+
+      // Remove amendment values.
+      shared.valuesByCalculationNameByVariableNameArray =
+        shared.valuesByCalculationNameByVariableNameArray.map(
+          (valuesByCalculationNameByVariableName) =>
+            Object.fromEntries(
+              Object.entries(valuesByCalculationNameByVariableName).map(
+                ([variableName, valuesByCalculationName]) => {
+                  const updatedValuesByCalculationName = {
+                    ...valuesByCalculationName,
+                  }
+                  delete updatedValuesByCalculationName["amendment"]
+                  return [variableName, updatedValuesByCalculationName]
+                },
+              ),
+            ),
+        )
+    } else {
+      const calculation: Calculation = (newCalculationByName.amendment = {
+        running: true,
+      })
+      let situation: SituationWithAxes
+      if (amendmentSituationIndex === null) {
+        situation = aggregatedSituation
+      } else {
+        calculation.situationIndex = amendmentSituationIndex
+        situation = cleanSituation(
+          shared.testCases[amendmentSituationIndex],
+          shared.axes,
+        )
+      }
+      calculation.input = {
+        ...message,
+        parametric_reform: shared.parametricReform,
+        reform: billName ?? revaluationName, // Will be removed when billName and revaluationName are undefined.
+        situation,
+        variables: [
+          ...summaryCalculatedVariablesName,
+          ...otherCalculatedVariablesName,
+          ...(nonVirtualVariablesNameByReformName[billName as string] ??
+            nonVirtualVariablesNameByReformName[revaluationName as string] ??
+            nonVirtualVariablesName),
+        ],
+      }
+      sendTestCasesSimulation("amendment", calculation.input) // Don't wait for result.
+    }
+  }
+  $inspect("13")
+
+  shared.calculationByName = newCalculationByName
+  $inspect("14")
+}
+
+export function calculateTestCasesAdditionalVariables(
+  additionalVariablesName: Set<string>,
+): void {
+  const newCalculationByName = { ...shared.calculationByName }
+  for (const [calculationName, calculation] of Object.entries(
+    newCalculationByName,
+  )) {
+    if (calculation.input === undefined) {
+      continue
+    }
+
+    let variablesAdded = false
+    const variablesName = [...calculation.input.variables]
+    for (const variableName of additionalVariablesName) {
+      if (!variablesName.includes(variableName)) {
+        variablesName.push(variableName)
+        variablesAdded = true
+      }
+    }
+
+    if (variablesAdded) {
+      const input = { ...calculation.input, variables: variablesName }
+      newCalculationByName[calculationName as CalculationName] = {
+        ...calculation,
+        input,
+        running: true,
+      }
+      sendTestCasesSimulation(calculationName as CalculationName, input) // Don't wait for result.
+    }
+  }
+  shared.calculationByName = newCalculationByName
+}
+
+function cleanSituation(
+  situationToClean: Situation,
+  axes: Axis[][],
+): SituationWithAxes {
+  let situation: SituationWithAxes = {}
+  for (const entity of Object.values(entityByKey)) {
+    let entitySituation = situationToClean[entity.key_plural as string]
+    if (entitySituation === undefined) {
+      continue
+    }
+    situation[entity.key_plural as string] = entitySituation
+  }
+  if (axes.length > 0) {
+    situation.axes = axes.map((parallelAxes) =>
+      parallelAxes.map((axis) => ({
+        ...axis,
+        index: (axis.index as number) - (axis.situationIndex as number),
+        situationIndex: 0,
+      })),
+    )
+  }
+  return situation
+}
+
+export async function sendBudgetSimulationDemand() {
+  const budgetVariableName = shared.displayMode?.parametersVariableName
+  if (
+    budgetVariableName === undefined ||
+    !budgetVariablesName.has(budgetVariableName)
+  ) {
+    console.error(
+      `Budget calculation for variable ${budgetVariableName} is not available`,
+    )
+    shared.budgetSimulation = undefined
+    return
+  }
+  const variableName = budgetVariableNameByVariableName[budgetVariableName]
+  const variableConfig: BudgetVariable = budgetVariablesConfig[variableName]
+  const simulationBody = buildBudgetDemandBody(
+    variableName,
+    variableConfig.outputVariables,
+    variableConfig.quantileBaseVariable,
+    variableConfig.quantileCompareVariables,
+    false,
+  )
+  const urlString = "/budgets/demands"
+  const res = await fetch(urlString, {
+    body: JSON.stringify(
+      {
+        displayMode: shared.displayMode,
+        email: shared.requestedSimulationEmail,
+        request: Object.fromEntries(
+          Object.entries(shared.parametricReform).filter(([parameterName]) =>
+            budgetEditableParametersName.has(parameterName),
+          ),
+        ),
+        simulation: simulationBody,
+      },
+      null,
+      2,
+    ),
+    headers: {
+      Accept: "application/json",
+      "Content-Type": "application/json; charset=utf-8",
+    },
+    method: "POST",
+  })
+  if (!res.ok) {
+    shared.requestedSimulationEmail = undefined
+    console.error(
+      `Error ${
+        res.status
+      } while sending a simulation request at ${urlString}\n\n${await res.text()}`,
+    )
+    return
+  }
+  shared.requestedSimulationEmail = undefined
+}
+
+async function sendTestCasesSimulation(
+  calculationName: CalculationName,
+  {
+    period,
+    parametric_reform,
+    reform,
+    situation,
+    variables,
+  }: TestCasesCalculationInput,
+) {
+  const completeVariableSummaryByName =
+    billName === undefined
+      ? variableSummaryByName
+      : variableSummaryByNameByReformName[billName]
+  try {
+    // Note: crypto.randomUUID() is not supported by Safari before version 15.4.
+    // const token = crypto.randomUUID()
+    const token = uuidV4()
+    testCasesAbortControllers[calculationName].abort()
+    testCasesAbortControllers[calculationName] = new AbortController()
+    const response = await fetch("/test_cases", {
+      body: JSON.stringify({
+        period,
+        parametric_reform,
+        reform,
+        situation,
+        title: calculationName,
+        token,
+        variables,
+      }),
+      headers: {
+        Accept: "application/json",
+        "Content-Type": "application/json; charset=utf-8",
+      },
+      method: "POST",
+      signal: testCasesAbortControllers[calculationName].signal,
+    })
+    if (!response.ok) {
+      console.error(
+        `Error while submitting test case simulation:\n${response.status} ${response.statusText}`,
+      )
+      console.error(await response.text())
+      return
+    }
+    const { evaluations } = (await response.json()) as {
+      evaluations: [
+        {
+          entity: string
+          name: string
+          value: VariableValues
+        },
+      ]
+      token: string
+    }
+
+    let calculation = shared.calculationByName[calculationName] as Calculation
+
+    let updatedEvaluationByNameArray =
+      calculation.situationIndex === undefined
+        ? shared.evaluationByNameArray
+        : [...shared.evaluationByNameArray]
+    for (const {
+      entity: entityKey,
+      name: variableName,
+      value,
+    } of evaluations) {
+      // Round returned values if unit of variable is a currency.
+      const variable = completeVariableSummaryByName[variableName]
+      const roundedValue =
+        variable.unit === "currency" || variable.unit?.startsWith("currency-")
+          ? value.map((valueAtIndex) => Math.round(valueAtIndex as number))
+          : value
+
+      const entity = entityByKey[entityKey]
+
+      if (calculation.situationIndex === undefined) {
+        // Variable has been computed for all test cases.
+
+        // Count total population of test cases.
+        let testCasesPopulationCount = 0
+        for (const situation of shared.testCases) {
+          const entitySituation = situation[entity.key_plural as string] ?? {}
+          const situationPopulationCount = Object.keys(entitySituation).length
+          testCasesPopulationCount += situationPopulationCount
+        }
+
+        // Split evaluation.value vector for each situation.
+        {
+          let testCasesPopulationIndex = 0
+          shared.valuesByCalculationNameByVariableNameArray =
+            shared.valuesByCalculationNameByVariableNameArray.map(
+              (
+                valuesByCalculationNameByVariableName,
+                situationIndex,
+              ): ValuesByCalculationNameByVariableName => {
+                const situation = shared.testCases[situationIndex]
+                const entitySituation =
+                  situation[entity.key_plural as string] ?? {}
+                let values = []
+                for (
+                  let index = testCasesPopulationIndex, vectorIndex = 0;
+                  vectorIndex < shared.vectorLength;
+                  index += testCasesPopulationCount, vectorIndex++
+                ) {
+                  for (const situationPersonIndex of Object.keys(
+                    entitySituation,
+                  ).keys()) {
+                    values.push(roundedValue[index + situationPersonIndex])
+                  }
+                }
+                testCasesPopulationIndex += Object.keys(entitySituation).length
+                const valuesByCalculationName =
+                  valuesByCalculationNameByVariableName[variableName] ?? {}
+                return {
+                  ...valuesByCalculationNameByVariableName,
+                  [variableName]: {
+                    ...valuesByCalculationName,
+                    [calculationName]: values,
+                  },
+                }
+              },
+            )
+        }
+      } else {
+        // Variable has been computed for a single test case.
+
+        const updatedValuesByCalculationNameByVariableNameArray = [
+          ...shared.valuesByCalculationNameByVariableNameArray,
+        ]
+        const valuesByCalculationNameByVariableName = {
+          ...updatedValuesByCalculationNameByVariableNameArray[
+            calculation.situationIndex
+          ],
+        }
+        const valuesByCalculationName =
+          valuesByCalculationNameByVariableName[variableName] ?? {}
+        valuesByCalculationNameByVariableName[variableName] = {
+          ...valuesByCalculationName,
+          [calculationName]: roundedValue,
+        }
+        updatedValuesByCalculationNameByVariableNameArray[
+          calculation.situationIndex
+        ] = valuesByCalculationNameByVariableName
+        shared.valuesByCalculationNameByVariableNameArray =
+          updatedValuesByCalculationNameByVariableNameArray
+      }
+
+      // Update evaluations for decompositions.
+      const calculationNonVirtualVariablesName =
+        calculationName === "law"
+          ? nonVirtualVariablesName
+          : (nonVirtualVariablesNameByReformName[billName as string] ??
+            nonVirtualVariablesName)
+      if (calculationNonVirtualVariablesName.includes(variableName)) {
+        if (calculation.situationIndex === undefined) {
+          // Variable has been computed for all test cases.
+
+          // First, update delta and values of evaluations.
+          updatedEvaluationByNameArray = updatedEvaluationByNameArray.map(
+            (evaluationByName, situationIndex): EvaluationByName => {
+              const situation = shared.testCases[situationIndex]
+              const values = shared.valuesByCalculationNameByVariableNameArray[
+                situationIndex
+              ][variableName][calculationName] as VariableValues
+              const entitySituation =
+                situation[entity.key_plural as string] ?? {}
+              const situationPopulationCount =
+                Object.keys(entitySituation).length
+              let delta = new Array(shared.vectorLength).fill(0)
+              for (const situationPersonIndex of Object.keys(
+                entitySituation,
+              ).keys()) {
+                for (
+                  let index = situationPersonIndex, vectorIndex = 0;
+                  vectorIndex < shared.vectorLength;
+                  index += situationPopulationCount, vectorIndex++
+                ) {
+                  delta[vectorIndex] += values[index]
+                }
+              }
+              const evaluation = evaluationByName[variableName]
+              const calculationEvaluationByName =
+                evaluation?.calculationEvaluationByName ?? {}
+              return {
+                ...evaluationByName,
+                [variableName]: {
+                  ...(evaluation ?? {}),
+                  calculationEvaluationByName: {
+                    ...calculationEvaluationByName,
+                    [calculationName]: {
+                      ...(calculationEvaluationByName[calculationName] ?? {}),
+                      delta,
+                      deltaAtVectorIndex:
+                        delta[situation.slider?.vectorIndex ?? 0] ?? 0,
+                    },
+                  },
+                  fromOpenFisca: true,
+                },
+              }
+            },
+          )
+        } else {
+          // Variable has been computed for a single test case.
+
+          // First, update delta and values of evaluations.
+          const situation = shared.testCases[calculation.situationIndex]
+          const values = shared.valuesByCalculationNameByVariableNameArray[
+            calculation.situationIndex
+          ][variableName][calculationName] as VariableValues
+          const entitySituation = situation[entity.key_plural as string] ?? {}
+          const situationPopulationCount = Object.keys(entitySituation).length
+          let delta = new Array(shared.vectorLength).fill(0)
+          for (const situationPersonIndex of Object.keys(
+            entitySituation,
+          ).keys()) {
+            for (
+              let index = situationPersonIndex, vectorIndex = 0;
+              vectorIndex < shared.vectorLength;
+              index += situationPopulationCount, vectorIndex++
+            ) {
+              delta[vectorIndex] += values[index]
+            }
+          }
+          const evaluationByName = {
+            ...updatedEvaluationByNameArray[calculation.situationIndex],
+          }
+          const evaluation = evaluationByName[variableName]
+          const calculationEvaluationByName =
+            evaluation?.calculationEvaluationByName ?? {}
+          evaluationByName[variableName] = {
+            ...(evaluation ?? {}),
+            calculationEvaluationByName: {
+              ...calculationEvaluationByName,
+              [calculationName]: {
+                ...(calculationEvaluationByName[calculationName] ?? {}),
+                delta,
+                deltaAtVectorIndex:
+                  delta[situation.slider?.vectorIndex ?? 0] ?? 0,
+              },
+            },
+            fromOpenFisca: true,
+          }
+        }
+      }
+    }
+
+    // Update deltaSums of evaluations from their new delta.
+    if (calculation.situationIndex === undefined) {
+      shared.evaluationByNameArray = updatedEvaluationByNameArray.map(
+        (evaluationByName, situationIndex) =>
+          updateEvaluations(
+            shared.decompositionByName,
+            evaluationByName,
+            shared.testCases[situationIndex].slider?.vectorIndex ?? 0,
+            shared.vectorLength,
+            waterfalls,
+          ),
+      )
+    } else {
+      updatedEvaluationByNameArray[calculation.situationIndex] =
+        updateEvaluations(
+          shared.decompositionByName,
+          updatedEvaluationByNameArray[calculation.situationIndex],
+          shared.testCases[calculation.situationIndex].slider?.vectorIndex ?? 0,
+          shared.vectorLength,
+          waterfalls,
+        )
+      shared.evaluationByNameArray = updatedEvaluationByNameArray
+    }
+
+    calculation = { ...calculation }
+    delete calculation.running
+    shared.calculationByName[calculationName] = calculation
+  } catch (e) {
+    if (e?.name === "AbortError") {
+      return
+    }
+  }
+}
+
+export function updateOnSliderChange(situations: Situation[]): void {
+  let changedAxesSituationIndex: number[] = []
+  let evaluationByNameArrayChanged = false
+  const updatedEvaluationByNameArray = [...shared.evaluationByNameArray]
+  for (const [situationIndex, situation] of situations.entries()) {
+    const slider = situation.slider
+    if (slider === undefined) {
+      if (axisBySituationIndex[situationIndex] !== undefined) {
+        axisBySituationIndex = { ...axisBySituationIndex }
+        delete axisBySituationIndex[situationIndex]
+        changedAxesSituationIndex.push(situationIndex)
+
+        // Change only vectorIndexes content, because vectorIndexes reactivity
+        // is not needed.
+        vectorIndexes[situationIndex] = 0
+      }
+    } else {
+      const currentAxis = axisBySituationIndex[situationIndex]
+      if (
+        currentAxis === undefined ||
+        currentAxis.name !== slider.name ||
+        currentAxis.min !== slider.min ||
+        currentAxis.max !== slider.max
+      ) {
+        const entity = entityByKey[slider.entity]
+
+        let previousSituationsPopulationCount = 0
+        for (const situation of shared.testCases.slice(0, situationIndex)) {
+          const entitySituation = situation[entity.key_plural as string] ?? {}
+          const populationCount = Object.keys(entitySituation).length
+          previousSituationsPopulationCount += populationCount
+        }
+        const axis = {
+          count: 101,
+          index:
+            previousSituationsPopulationCount +
+            indexOfSituationPopulationId(entity, situation, slider.id),
+          max: slider.max,
+          min: slider.min,
+          name: slider.name,
+          period: year.toString(), // Previous years are added later.
+          situationIndex: previousSituationsPopulationCount,
+        }
+        axisBySituationIndex = {
+          ...axisBySituationIndex,
+          [situationIndex]: axis,
+        }
+        changedAxesSituationIndex.push(situationIndex)
+      }
+
+      const vectorIndex = slider.vectorIndex
+      if (vectorIndex !== vectorIndexes[situationIndex]) {
+        // Change only vectorIndexes content, because vectorIndexes reactivity
+        // is not needed.
+        vectorIndexes[situationIndex] = vectorIndex
+
+        // Update evaluations.
+        let evaluationByName = updatedEvaluationByNameArray[situationIndex]
+        const updatedEvaluationByName = updateEvaluationsVectorIndex(
+          evaluationByName,
+          vectorIndex,
+        )
+        if (updatedEvaluationByName !== evaluationByName) {
+          updatedEvaluationByNameArray[situationIndex] = updatedEvaluationByName
+          evaluationByNameArrayChanged = true
+        }
+      }
+    }
+  }
+
+  if (changedAxesSituationIndex.length > 0) {
+    const parallelAxes = Object.entries(axisBySituationIndex)
+      .sort(([situationIndex1], [situationIndex2]) =>
+        situationIndex1.localeCompare(situationIndex2),
+      )
+      .map(([, axis]) => axis)
+      .reduce((parallelAxes, axis) => {
+        // Add previous years of each axis.
+        const year = parseInt(axis.period as string)
+        parallelAxes.push(
+          {
+            ...axis,
+            period: (year - 2).toString(),
+          },
+          {
+            ...axis,
+            period: (year - 1).toString(),
+          },
+          axis,
+        )
+        return parallelAxes
+      }, [] as Axis[])
+
+    shared.axes = parallelAxes.length === 0 ? [] : [parallelAxes]
+
+    let updatedVectorLength = 1
+    for (const parallelAxes of shared.axes) {
+      // All the parallel axes have the same count.
+      const axis = parallelAxes[0]
+      updatedVectorLength *= axis.count
+    }
+    shared.vectorLength = updatedVectorLength
+
+    for (const situationIndex of changedAxesSituationIndex) {
+      updatedEvaluationByNameArray[situationIndex] = updateEvaluations(
+        shared.decompositionByName,
+        updatedEvaluationByNameArray[situationIndex],
+        vectorIndexes[situationIndex],
+        shared.vectorLength,
+        waterfalls,
+      )
+      evaluationByNameArrayChanged = true
+    }
+
+    // Launch calculations if the axes have not been deleted (ie shared.vectorLength > 1).
+    const situationIndex =
+      changedAxesSituationIndex.length === 1
+        ? changedAxesSituationIndex[0]
+        : undefined
+    requestAllTestCasesCalculations(situationIndex ?? null)
+  }
+
+  if (evaluationByNameArrayChanged) {
+    shared.evaluationByNameArray = updatedEvaluationByNameArray
+  }
+}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 8bb9855a2447b82ed18d2378c6ed719cf379d4da..eb18b2ba3a429d2404ef480fc63ccb8e42a6321f 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -1,419 +1,73 @@
 <script lang="ts">
-  import { run } from "svelte/legacy"
-
   import "intro.js/introjs.css"
 
   import "../app.css"
 
-  import {
-    getRolePersonsIdKey,
-    type GroupEntity,
-    type PopulationWithoutId,
-  } from "@openfisca/json-model"
   import "iconify-icon"
-  import { setContext, untrack } from "svelte"
-  import { writable, type Writable } from "svelte/store"
-  import { v4 as uuidV4 } from "uuid"
+  import { onMount, setContext } from "svelte"
+  import { writable } from "svelte/store"
 
   import type { LayoutData } from "./$types"
 
-  import { browser } from "$app/environment"
   import { onNavigate } from "$app/navigation"
   import { page } from "$app/stores"
-  import type { BudgetSimulation } from "$lib/budgets"
   import {
     requestAllTestCasesCalculations,
-    type CalculationName,
-    type RequestedCalculations,
-    type RequestedSituationIndexByCalculationName,
-    calculationNames,
     requestedCalculations,
   } from "$lib/calculations.svelte"
   import NavBar from "$lib/components/NavBar.svelte"
-  import {
-    buildDecompositionByNameFromCore,
-    decompositionCoreByName,
-    decompositionCoreByNameByReformName,
-    nonVirtualVariablesName,
-    nonVirtualVariablesNameByReformName,
-    updateEvaluations,
-    updateEvaluationsVectorIndex,
-    waterfalls,
-    type EvaluationByName,
-    type DecompositionByName,
-  } from "$lib/decompositions"
-  import type { DisplayMode } from "$lib/displays"
-  import { entityByKey } from "$lib/entities"
-  import {
-    trackPageView,
-    trackParametricReform,
-    trackTestCaseShowAllVariables,
-  } from "$lib/matomo"
-  import { metadata } from "$lib/metadata"
-  import { getNavbarConfig, type NavbarConfig } from "$lib/navbar"
+  import { trackPageView, trackParametricReform } from "$lib/matomo"
+  import { getNavbarConfig } from "$lib/navbar"
   import publicConfig from "$lib/public_config"
-  import { reformMetadataByName, type ParametricReform } from "$lib/reforms"
   import {
-    extractInputInstantsFromTestCases,
-    getPopulationReservedKeys,
-    indexOfSituationPopulationId,
-    testCasesCore,
-    type Axis,
-    type Calculation,
-    type CalculationByName,
-    type Situation,
-    type SituationWithAxes,
-    type TestCasesCalculationInput,
-  } from "$lib/situations"
-  import {
-    budgetEditableParametersName,
-    budgetVariableNameByVariableName,
-    budgetVariablesConfig,
-    budgetVariablesName,
-    otherCalculatedVariablesName,
-    summaryCalculatedVariablesName,
-    type BudgetVariable,
-    type ValuesByCalculationNameByVariableName,
-    type VariableValue,
-    type VariableValues,
-    variableSummaryByName,
-    variableSummaryByNameByReformName,
-  } from "$lib/variables"
+    calculateBudget,
+    calculateTestCases,
+    calculateTestCasesAdditionalVariables,
+    sendBudgetSimulationDemand,
+    shared,
+    updateOnSliderChange,
+  } from "$lib/shared.svelte"
 
   interface Props {
     data: LayoutData
     children?: import("svelte").Snippet
   }
 
-  const {
-    baseUrl,
-    matomo: matomoConfig,
-    reformName,
-    revaluationName,
-  } = publicConfig
-  let { data, children }: Props = $props()
-
-  let axisBySituationIndex: { [situationIndex: string]: Axis } = {}
-
-  const budgetSimulation: Writable<BudgetSimulation | undefined> =
-    writable(undefined)
-  setContext("budgetSimulation", budgetSimulation)
-  let budgetSimulationAbortController = new AbortController()
-
-  const calculationByName: Writable<CalculationByName> = writable({})
-  setContext("calculationByName", calculationByName)
+  const { baseUrl, matomo: matomoConfig } = publicConfig
 
-  /**
-   * Bill (PLF)
-   */
+  let { children }: Props = $props()
 
-  let currentBillName: string | undefined =
-    reformName === undefined
-      ? undefined
-      : reformMetadataByName[reformName] === undefined
-        ? undefined
-        : reformName
-  const billActive: Writable<boolean> = writable(currentBillName !== undefined)
-  setContext("billActive", billActive)
-
-  let currentRevaluationName: string | undefined =
-    revaluationName === undefined
-      ? undefined
-      : reformMetadataByName[revaluationName] === undefined
-        ? undefined
-        : revaluationName
+  let { url } = $derived($page)
 
   const customOpenGraphRoutes = [
     /\/fonctionnement/,
     /\/test_cases\/simulations\/.*/,
   ]
 
-  const today = new Date()
-  const year = writable(
-    today.getFullYear() +
-      (today.getMonth() > 1 /* => After February */ ? 1 : 0),
-  )
-  setContext("year", year)
-  const yearPLF = writable(
-    today.getFullYear() +
-      ($billActive && today.getMonth() > 1 /* => After February */ ? 1 : 0),
-  )
-  setContext("yearPLF", yearPLF)
-  const date = writable(`${$year}-01-01`)
-  setContext("date", date)
-  const budgetDate = writable(`${$yearPLF}-01-01`)
-  setContext("budgetDate", budgetDate)
-
-  const decompositionByName = writable(
-    // Note: We always use the reform decomposition, because it is more
-    // complete than decomposition before reform.
-    buildDecompositionByNameFromCore(
-      currentBillName === undefined
-        ? decompositionCoreByName
-        : (decompositionCoreByNameByReformName[currentBillName] ??
-            decompositionCoreByName),
-    ),
-  )
-  setContext("decompositionByName", decompositionByName)
-
-  const displayMode: Writable<DisplayMode | undefined> = writable(undefined)
-  setContext("displayMode", displayMode)
-
-  const evaluationByNameArray = writable(
-    new Array(testCasesCore.length).fill({}) as EvaluationByName[],
-  )
-  setContext("evaluationByNameArray", evaluationByNameArray)
-
-  const inputInstantsByVariableNameArray: Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  > = writable(extractInputInstantsFromTestCases(testCasesCore))
-  setContext(
-    "inputInstantsByVariableNameArray",
-    inputInstantsByVariableNameArray,
-  )
-
-  const navbarConfig: Writable<NavbarConfig> = writable(
-    getNavbarConfig($page.route.id ?? "/"),
-  )
-  setContext("navbarConfig", navbarConfig)
-
-  const parametricReformValue: ParametricReform = {}
-  // let parametricReformValue: ParametricReform
-  // if (browser) {
-  //   const parametricReformJson = localStorage.getItem("parametricReform")
-  //   if (parametricReformJson !== null) {
-  //     try {
-  //       parametricReformValue = JSON.parse(parametricReformJson)
-  //     } catch {
-  //       parametricReformValue = {}
-  //     }
-  //   } else {
-  //     parametricReformValue = {}
-  //   }
-  // } else {
-  //   parametricReformValue = {}
-  // }
-  const parametricReform = writable(parametricReformValue)
-  setContext("parametricReform", parametricReform)
-
-  const requestedSimulationEmail: Writable<string | undefined> =
-    writable(undefined)
-  setContext("requestedSimulationEmail", requestedSimulationEmail)
-
-  const requestedSimulationSent: Writable<boolean> = writable(false)
-  setContext("requestedSimulationSent", requestedSimulationSent)
-
-  const requestedVariablesNameToCalculate: Writable<Set<string> | undefined> =
-    writable(undefined)
-  setContext(
-    "requestedVariablesNameToCalculate",
-    requestedVariablesNameToCalculate,
-  )
-
-  /*
-   * Search
-   * */
-  const searchActive: Writable<boolean> = writable(false)
-  setContext("searchActive", searchActive)
-
-  const searchVariableName: Writable<string | undefined> = writable(undefined)
-  setContext("searchVariableName", searchVariableName)
-
-  const showNulls = writable(false)
-  setContext("showNulls", showNulls)
-
-  const showTutorial = writable(publicConfig.showTutorial)
-  setContext("showTutorial", showTutorial)
-
-  const testCasesValue: Situation[] = structuredClone(testCasesCore)
-  // let testCasesValue: Situation[]
-  // if (browser) {
-  //   const testCasesJson = localStorage.getItem("testCases")
-  //   if (testCasesJson !== null) {
-  //     try {
-  //       testCasesValue = JSON.parse(testCasesJson)
-  //     } catch {
-  //       testCasesValue = testCasesCore
-  //     }
-  //   } else {
-  //     testCasesValue = testCasesCore
-  //   }
-  // } else {
-  //   testCasesValue = testCasesCore
-  // }
-  const testCases = writable(testCasesValue)
-  setContext("testCases", testCases)
-
-  const testCasesIndex: Writable<number[]> = writable([])
-  setContext("testCasesIndex", testCasesIndex)
-
-  const testCasesAbortControllers: {
-    [calculationName: string]: AbortController
-  } = Object.fromEntries(
-    calculationNames.map((calculationName) => [
-      calculationName,
-      new AbortController(),
-    ]),
-  )
-
-  const valuesByCalculationNameByVariableNameArray: Writable<
-    ValuesByCalculationNameByVariableName[]
-  > = writable(new Array(testCasesCore.length).fill({}))
-  setContext(
-    "valuesByCalculationNameByVariableNameArray",
-    valuesByCalculationNameByVariableNameArray,
-  )
-
-  const vectorLength = writable(1)
-  setContext("vectorLength", vectorLength)
-
-  let vectorIndexes = new Array(testCasesCore.length).fill(0)
-
-  let waterfall = writable(waterfalls[0])
-  setContext("waterfall", waterfall)
-
-  if (browser && matomoConfig !== undefined) {
-    matomo(matomoConfig)
-  }
-
-  if (browser && $showNulls === true) {
-    trackTestCaseShowAllVariables()
-  }
-
-  function buildBudgetDemandBody(
-    variableName: string,
-    outputVariables: string[],
-    quantileBaseVariable: string[],
-    quantileCompareVariables: string[],
-    includeDisplay = true,
-  ) {
-    const budgetParametricReform = Object.fromEntries(
-      Object.entries($parametricReform).filter(([parameterName]) =>
-        budgetEditableParametersName.has(parameterName),
-      ),
-    )
-    return {
-      amendement: budgetParametricReform,
-      base: $yearPLF,
-      displayMode: includeDisplay ? $displayMode : undefined,
-      metadata,
-      output_variables: outputVariables,
-      quantile_base_variable: quantileBaseVariable,
-      quantile_compare_variables: quantileCompareVariables,
-      winners_loosers_variable: variableName,
-      quantile_nb: 10,
-      plf: reformName === undefined ? undefined : $yearPLF,
-    }
+  if ($page.route.id) {
+    shared.navbarConfig = getNavbarConfig($page.route.id)
   }
 
-  async function calculateBudget(
-    budgetVariableName: string,
-    // budgetCalculationNames: Set<CalculationName>,
-  ): Promise<void> {
-    budgetSimulationAbortController.abort()
-    budgetSimulationAbortController = new AbortController()
-    if (!budgetVariablesName.has(budgetVariableName)) {
-      console.error(
-        `Budget calculation for variable ${budgetVariableName} is not available`,
-      )
-      $budgetSimulation = undefined
-      return
-    }
-    const variableName = budgetVariableNameByVariableName[budgetVariableName]
-    const variableConfig: BudgetVariable = budgetVariablesConfig[variableName]
-    const body = JSON.stringify(
-      buildBudgetDemandBody(
-        variableName,
-        variableConfig.outputVariables,
-        variableConfig.quantileBaseVariable,
-        variableConfig.quantileCompareVariables,
-      ),
-    )
-    $budgetSimulation = undefined
-    const response = await fetch("/budgets", {
-      body,
-      headers: {
-        Accept: "application/json",
-        "Content-Type": "application/json; charset=utf-8",
-      },
-      method: "POST",
-      signal: budgetSimulationAbortController.signal,
-    })
-    if (!response.ok) {
-      console.error(
-        `${$page.url}: Error while calculating budget:\n${body}\n${response.status} ${response.statusText}`,
-      )
-      console.error(await response.text())
-      $budgetSimulation = {
-        errors: [
-          `Une erreur inattendue (${response.status} ${response.statusText}) s'est produite et les impacts budgétaires ne sont pas disponibles pour le moment. Écrivez-nous à leximpact@assemblee-nationale.fr.`,
-        ],
-        isPublic: true,
-      }
-      $budgetSimulation = undefined
-      return
+  $effect(() => {
+    if (matomoConfig !== undefined) {
+      matomo(matomoConfig)
     }
-    $budgetSimulation = await response.json()
-  }
-
-  function calculateTestCasesAdditionalVariables(
-    additionalVariablesName: Set<string>,
-  ): void {
-    const newCalculationByName = { ...$calculationByName }
-    for (const [calculationName, calculation] of Object.entries(
-      newCalculationByName,
-    )) {
-      if (calculation.input === undefined) {
-        continue
-      }
-
-      let variablesAdded = false
-      const variablesName = [...calculation.input.variables]
-      for (const variableName of additionalVariablesName) {
-        if (!variablesName.includes(variableName)) {
-          variablesName.push(variableName)
-          variablesAdded = true
-        }
-      }
+  })
 
-      if (variablesAdded) {
-        const input = { ...calculation.input, variables: variablesName }
-        newCalculationByName[calculationName as CalculationName] = {
-          ...calculation,
-          input,
-          running: true,
-        }
-        sendTestCasesSimulation(calculationName as CalculationName, input) // Don't wait for result.
-      }
+  $effect(() => {
+    if (matomoConfig !== undefined && $page) {
+      trackPageView(url, matomoConfig.prependDomain)
     }
-    $calculationByName = newCalculationByName
-  }
+  })
 
-  function cleanSituation(
-    situationToClean: Situation,
-    axes: Axis[][],
-  ): SituationWithAxes {
-    let situation: SituationWithAxes = {}
-    for (const entity of Object.values(entityByKey)) {
-      let entitySituation = situationToClean[entity.key_plural as string]
-      if (entitySituation === undefined) {
-        continue
-      }
-      situation[entity.key_plural as string] = entitySituation
-    }
-    if (axes.length > 0) {
-      situation.axes = axes.map((parallelAxes) =>
-        parallelAxes.map((axis) => ({
-          ...axis,
-          index: (axis.index as number) - (axis.situationIndex as number),
-          situationIndex: 0,
-        })),
-      )
+  $effect(() => {
+    if (
+      matomoConfig !== undefined &&
+      Object.keys(shared.parametricReform).length !== 0
+    ) {
+      trackParametricReform(shared.parametricReform, matomoConfig.prependDomain)
     }
-    return situation
-  }
+  })
 
   function matomo({
     prependDomain,
@@ -455,529 +109,13 @@
     })()
   }
 
-  async function sendBudgetSimulationDemand() {
-    const budgetVariableName = $displayMode?.parametersVariableName
-    if (
-      budgetVariableName === undefined ||
-      !budgetVariablesName.has(budgetVariableName)
-    ) {
-      console.error(
-        `Budget calculation for variable ${budgetVariableName} is not available`,
-      )
-      $budgetSimulation = undefined
-      return
-    }
-    const variableName = budgetVariableNameByVariableName[budgetVariableName]
-    const variableConfig: BudgetVariable = budgetVariablesConfig[variableName]
-    const simulationBody = buildBudgetDemandBody(
-      variableName,
-      variableConfig.outputVariables,
-      variableConfig.quantileBaseVariable,
-      variableConfig.quantileCompareVariables,
-      false,
-    )
-    const urlString = "/budgets/demands"
-    const res = await fetch(urlString, {
-      body: JSON.stringify(
-        {
-          displayMode: $displayMode,
-          email: $requestedSimulationEmail,
-          request: Object.fromEntries(
-            Object.entries($parametricReform).filter(([parameterName]) =>
-              budgetEditableParametersName.has(parameterName),
-            ),
-          ),
-          simulation: simulationBody,
-        },
-        null,
-        2,
-      ),
-      headers: {
-        Accept: "application/json",
-        "Content-Type": "application/json; charset=utf-8",
-      },
-      method: "POST",
-    })
-    if (!res.ok) {
-      $requestedSimulationEmail = undefined
-      console.error(
-        `Error ${
-          res.status
-        } while sending a simulation request at ${urlString}\n\n${await res.text()}`,
-      )
-      return
-    }
-    $requestedSimulationEmail = undefined
-  }
-
-  async function sendTestCasesSimulation(
-    calculationName: CalculationName,
-    {
-      period,
-      parametric_reform,
-      reform,
-      situation,
-      variables,
-    }: TestCasesCalculationInput,
-  ) {
-    const completeVariableSummaryByName =
-      reformName === undefined
-        ? variableSummaryByName
-        : variableSummaryByNameByReformName[reformName]
-    try {
-      // Note: crypto.randomUUID() is not supported by Safari before version 15.4.
-      // const token = crypto.randomUUID()
-      const token = uuidV4()
-      testCasesAbortControllers[calculationName].abort()
-      testCasesAbortControllers[calculationName] = new AbortController()
-      const response = await fetch("/test_cases", {
-        body: JSON.stringify({
-          period,
-          parametric_reform,
-          reform,
-          situation,
-          title: calculationName,
-          token,
-          variables,
-        }),
-        headers: {
-          Accept: "application/json",
-          "Content-Type": "application/json; charset=utf-8",
-        },
-        method: "POST",
-        signal: testCasesAbortControllers[calculationName].signal,
-      })
-      if (!response.ok) {
-        console.error(
-          `Error while submitting test case simulation:\n${response.status} ${response.statusText}`,
-        )
-        console.error(await response.text())
-        return
-      }
-      const { evaluations } = (await response.json()) as {
-        evaluations: [
-          {
-            entity: string
-            name: string
-            value: VariableValues
-          },
-        ]
-        token: string
-      }
-
-      let calculation = $calculationByName[calculationName] as Calculation
-
-      let updatedEvaluationByNameArray =
-        calculation.situationIndex === undefined
-          ? $evaluationByNameArray
-          : [...$evaluationByNameArray]
-      for (const {
-        entity: entityKey,
-        name: variableName,
-        value,
-      } of evaluations) {
-        // Round returned values if unit of variable is a currency.
-        const variable = completeVariableSummaryByName[variableName]
-        const roundedValue =
-          variable.unit === "currency" || variable.unit?.startsWith("currency-")
-            ? value.map((valueAtIndex) => Math.round(valueAtIndex as number))
-            : value
-
-        const entity = entityByKey[entityKey]
-
-        if (calculation.situationIndex === undefined) {
-          // Variable has been computed for all test cases.
-
-          // Count total population of test cases.
-          let testCasesPopulationCount = 0
-          for (const situation of $testCases) {
-            const entitySituation = situation[entity.key_plural as string] ?? {}
-            const situationPopulationCount = Object.keys(entitySituation).length
-            testCasesPopulationCount += situationPopulationCount
-          }
-
-          // Split evaluation.value vector for each situation.
-          {
-            let testCasesPopulationIndex = 0
-            $valuesByCalculationNameByVariableNameArray =
-              $valuesByCalculationNameByVariableNameArray.map(
-                (
-                  valuesByCalculationNameByVariableName,
-                  situationIndex,
-                ): ValuesByCalculationNameByVariableName => {
-                  const situation = $testCases[situationIndex]
-                  const entitySituation =
-                    situation[entity.key_plural as string] ?? {}
-                  let values = []
-                  for (
-                    let index = testCasesPopulationIndex, vectorIndex = 0;
-                    vectorIndex < $vectorLength;
-                    index += testCasesPopulationCount, vectorIndex++
-                  ) {
-                    for (const situationPersonIndex of Object.keys(
-                      entitySituation,
-                    ).keys()) {
-                      values.push(roundedValue[index + situationPersonIndex])
-                    }
-                  }
-                  testCasesPopulationIndex +=
-                    Object.keys(entitySituation).length
-                  const valuesByCalculationName =
-                    valuesByCalculationNameByVariableName[variableName] ?? {}
-                  return {
-                    ...valuesByCalculationNameByVariableName,
-                    [variableName]: {
-                      ...valuesByCalculationName,
-                      [calculationName]: values,
-                    },
-                  }
-                },
-              )
-          }
-        } else {
-          // Variable has been computed for a single test case.
-
-          const updatedValuesByCalculationNameByVariableNameArray = [
-            ...$valuesByCalculationNameByVariableNameArray,
-          ]
-          const valuesByCalculationNameByVariableName = {
-            ...updatedValuesByCalculationNameByVariableNameArray[
-              calculation.situationIndex
-            ],
-          }
-          const valuesByCalculationName =
-            valuesByCalculationNameByVariableName[variableName] ?? {}
-          valuesByCalculationNameByVariableName[variableName] = {
-            ...valuesByCalculationName,
-            [calculationName]: roundedValue,
-          }
-          updatedValuesByCalculationNameByVariableNameArray[
-            calculation.situationIndex
-          ] = valuesByCalculationNameByVariableName
-          $valuesByCalculationNameByVariableNameArray =
-            updatedValuesByCalculationNameByVariableNameArray
-        }
-
-        // Update evaluations for decompositions.
-        const calculationNonVirtualVariablesName =
-          calculationName === "law"
-            ? nonVirtualVariablesName
-            : (nonVirtualVariablesNameByReformName[reformName as string] ??
-              nonVirtualVariablesName)
-        if (calculationNonVirtualVariablesName.includes(variableName)) {
-          if (calculation.situationIndex === undefined) {
-            // Variable has been computed for all test cases.
-
-            // First, update delta and values of evaluations.
-            updatedEvaluationByNameArray = updatedEvaluationByNameArray.map(
-              (evaluationByName, situationIndex): EvaluationByName => {
-                const situation = $testCases[situationIndex]
-                const values = $valuesByCalculationNameByVariableNameArray[
-                  situationIndex
-                ][variableName][calculationName] as VariableValues
-                const entitySituation =
-                  situation[entity.key_plural as string] ?? {}
-                const situationPopulationCount =
-                  Object.keys(entitySituation).length
-                let delta = new Array($vectorLength).fill(0)
-                for (const situationPersonIndex of Object.keys(
-                  entitySituation,
-                ).keys()) {
-                  for (
-                    let index = situationPersonIndex, vectorIndex = 0;
-                    vectorIndex < $vectorLength;
-                    index += situationPopulationCount, vectorIndex++
-                  ) {
-                    delta[vectorIndex] += values[index]
-                  }
-                }
-                const evaluation = evaluationByName[variableName]
-                const calculationEvaluationByName =
-                  evaluation?.calculationEvaluationByName ?? {}
-                return {
-                  ...evaluationByName,
-                  [variableName]: {
-                    ...(evaluation ?? {}),
-                    calculationEvaluationByName: {
-                      ...calculationEvaluationByName,
-                      [calculationName]: {
-                        ...(calculationEvaluationByName[calculationName] ?? {}),
-                        delta,
-                        deltaAtVectorIndex:
-                          delta[situation.slider?.vectorIndex ?? 0] ?? 0,
-                      },
-                    },
-                    fromOpenFisca: true,
-                  },
-                }
-              },
-            )
-          } else {
-            // Variable has been computed for a single test case.
-
-            // First, update delta and values of evaluations.
-            const situation = $testCases[calculation.situationIndex]
-            const values = $valuesByCalculationNameByVariableNameArray[
-              calculation.situationIndex
-            ][variableName][calculationName] as VariableValues
-            const entitySituation = situation[entity.key_plural as string] ?? {}
-            const situationPopulationCount = Object.keys(entitySituation).length
-            let delta = new Array($vectorLength).fill(0)
-            for (const situationPersonIndex of Object.keys(
-              entitySituation,
-            ).keys()) {
-              for (
-                let index = situationPersonIndex, vectorIndex = 0;
-                vectorIndex < $vectorLength;
-                index += situationPopulationCount, vectorIndex++
-              ) {
-                delta[vectorIndex] += values[index]
-              }
-            }
-            const evaluationByName = {
-              ...updatedEvaluationByNameArray[calculation.situationIndex],
-            }
-            const evaluation = evaluationByName[variableName]
-            const calculationEvaluationByName =
-              evaluation?.calculationEvaluationByName ?? {}
-            evaluationByName[variableName] = {
-              ...(evaluation ?? {}),
-              calculationEvaluationByName: {
-                ...calculationEvaluationByName,
-                [calculationName]: {
-                  ...(calculationEvaluationByName[calculationName] ?? {}),
-                  delta,
-                  deltaAtVectorIndex:
-                    delta[situation.slider?.vectorIndex ?? 0] ?? 0,
-                },
-              },
-              fromOpenFisca: true,
-            }
-          }
-        }
-      }
-
-      // Update deltaSums of evaluations from their new delta.
-      if (calculation.situationIndex === undefined) {
-        $evaluationByNameArray = updatedEvaluationByNameArray.map(
-          (evaluationByName, situationIndex) =>
-            updateEvaluations(
-              $decompositionByName,
-              evaluationByName,
-              $testCases[situationIndex].slider?.vectorIndex ?? 0,
-              $vectorLength,
-              waterfalls,
-            ),
-        )
-      } else {
-        updatedEvaluationByNameArray[calculation.situationIndex] =
-          updateEvaluations(
-            $decompositionByName,
-            updatedEvaluationByNameArray[calculation.situationIndex],
-            $testCases[calculation.situationIndex].slider?.vectorIndex ?? 0,
-            $vectorLength,
-            waterfalls,
-          )
-        $evaluationByNameArray = updatedEvaluationByNameArray
-      }
-
-      calculation = { ...calculation }
-      delete calculation.running
-      $calculationByName = {
-        ...$calculationByName,
-        [calculationName]: calculation,
-      }
-    } catch (e) {
-      if (e?.name === "AbortError") {
-        return
-      }
-    }
-  }
-
-  function updateBillName(billName: string | undefined): void {
-    // Note: We always use the reform (aka "bill") decomposition, because it is more
-    // complete than decomposition before reform (aka "law" or "revaluation") and
-    // "amendment"has always the same decomposition as "bill", because it is a
-    // parametric-only reform.
-    if (billName !== currentBillName) {
-      currentBillName = billName
-      const newDecompositionByName = buildDecompositionByNameFromCore(
-        currentBillName === undefined
-          ? decompositionCoreByName
-          : (decompositionCoreByNameByReformName[currentBillName] ??
-              decompositionCoreByName),
-      ) as DecompositionByName
-      const oldDecompositionByName = $decompositionByName
-      for (const [name, decomposition] of Object.entries(
-        newDecompositionByName,
-      )) {
-        if (oldDecompositionByName[name]?.open) {
-          decomposition.open = true
-        }
-      }
-      $decompositionByName = newDecompositionByName
-    }
-  }
-
-  function updateOnSliderChange(situations: Situation[]): void {
-    let changedAxesSituationIndex: number[] = []
-    let evaluationByNameArrayChanged = false
-    const updatedEvaluationByNameArray = [...$evaluationByNameArray]
-    for (const [situationIndex, situation] of situations.entries()) {
-      const slider = situation.slider
-      if (slider === undefined) {
-        if (axisBySituationIndex[situationIndex] !== undefined) {
-          axisBySituationIndex = { ...axisBySituationIndex }
-          delete axisBySituationIndex[situationIndex]
-          changedAxesSituationIndex.push(situationIndex)
-
-          // Change only vectorIndexes content, because vectorIndexes reactivity
-          // is not needed.
-          vectorIndexes[situationIndex] = 0
-        }
-      } else {
-        const currentAxis = axisBySituationIndex[situationIndex]
-        if (
-          currentAxis === undefined ||
-          currentAxis.name !== slider.name ||
-          currentAxis.min !== slider.min ||
-          currentAxis.max !== slider.max
-        ) {
-          const entity = entityByKey[slider.entity]
-
-          let previousSituationsPopulationCount = 0
-          for (const situation of $testCases.slice(0, situationIndex)) {
-            const entitySituation = situation[entity.key_plural as string] ?? {}
-            const populationCount = Object.keys(entitySituation).length
-            previousSituationsPopulationCount += populationCount
-          }
-          const axis = {
-            count: 101,
-            index:
-              previousSituationsPopulationCount +
-              indexOfSituationPopulationId(entity, situation, slider.id),
-            max: slider.max,
-            min: slider.min,
-            name: slider.name,
-            period: $year.toString(), // Previous years are added later.
-            situationIndex: previousSituationsPopulationCount,
-          }
-          axisBySituationIndex = {
-            ...axisBySituationIndex,
-            [situationIndex]: axis,
-          }
-          changedAxesSituationIndex.push(situationIndex)
-        }
-
-        const vectorIndex = slider.vectorIndex
-        if (vectorIndex !== vectorIndexes[situationIndex]) {
-          // Change only vectorIndexes content, because vectorIndexes reactivity
-          // is not needed.
-          vectorIndexes[situationIndex] = vectorIndex
-
-          // Update evaluations.
-          let evaluationByName = updatedEvaluationByNameArray[situationIndex]
-          const updatedEvaluationByName = updateEvaluationsVectorIndex(
-            evaluationByName,
-            vectorIndex,
-          )
-          if (updatedEvaluationByName !== evaluationByName) {
-            updatedEvaluationByNameArray[situationIndex] =
-              updatedEvaluationByName
-            evaluationByNameArrayChanged = true
-          }
-        }
-      }
-    }
-
-    if (changedAxesSituationIndex.length > 0) {
-      const parallelAxes = Object.entries(axisBySituationIndex)
-        .sort(([situationIndex1], [situationIndex2]) =>
-          situationIndex1.localeCompare(situationIndex2),
-        )
-        .map(([, axis]) => axis)
-        .reduce((parallelAxes, axis) => {
-          // Add previous years of each axis.
-          const year = parseInt(axis.period as string)
-          parallelAxes.push(
-            {
-              ...axis,
-              period: (year - 2).toString(),
-            },
-            {
-              ...axis,
-              period: (year - 1).toString(),
-            },
-            axis,
-          )
-          return parallelAxes
-        }, [] as Axis[])
-      $axes = parallelAxes.length === 0 ? [] : [parallelAxes]
-
-      let updatedVectorLength = 1
-      for (const parallelAxes of $axes) {
-        // All the parallel axes have the same count.
-        const axis = parallelAxes[0]
-        updatedVectorLength *= axis.count
-      }
-      $vectorLength = updatedVectorLength
-
-      for (const situationIndex of changedAxesSituationIndex) {
-        updatedEvaluationByNameArray[situationIndex] = updateEvaluations(
-          $decompositionByName,
-          updatedEvaluationByNameArray[situationIndex],
-          vectorIndexes[situationIndex],
-          $vectorLength,
-          waterfalls,
-        )
-        evaluationByNameArrayChanged = true
-      }
-
-      // Launch calculations if the axes have not been deleted (ie $vectorLength > 1).
-      const situationIndex =
-        changedAxesSituationIndex.length === 1
-          ? changedAxesSituationIndex[0]
-          : undefined
-      requestAllTestCasesCalculations(situationIndex ?? null)
-    }
-
-    if (evaluationByNameArrayChanged) {
-      $evaluationByNameArray = updatedEvaluationByNameArray
-    }
-  }
-
-  onNavigate((navigation) => {
-    if (navigation.to?.route?.id !== navigation.from?.route?.id) {
-      $navbarConfig = getNavbarConfig(navigation.to?.route?.id ?? "/")
-    }
-  })
-  let { fetch } = $derived(data)
-  let { url } = $derived($page)
-  run(() => {
-    updateBillName(reformName)
-  })
-  run(() => {
-    updateOnSliderChange($testCases)
-  })
-  run(() => {
-    if (browser) {
-      // Launch first simulation.
-      requestAllTestCasesCalculations(null)
-    }
+  $effect(() => {
+    updateOnSliderChange(shared.testCases)
   })
-  // run(() => {
-  //   if (
-  //     $requestedCalculations.budgetVariableName !== undefined &&
-  //     $requestedCalculations.budgetCalculationNames !== undefined
-  //   ) {
-  //     const { /*budgetCalculationNames, */ budgetVariableName } =
-  //       $requestedCalculations
-  //     const newRequestedCalculations = { ...$requestedCalculations }
-  //     delete newRequestedCalculations.budgetCalculationNames
-  //     $requestedCalculations = newRequestedCalculations
-  //     calculateBudget(budgetVariableName /*, budgetCalculationNames */) // Don't await
-  //     $requestedSimulationSent = false
-  //   }
+  // TODO svelte5: find out why requestAllTestCasesCalculations makes the UI lag
+  // onMount(() => {
+  //   // Launch first simulation.
+  //   requestAllTestCasesCalculations(null)
   // })
   $effect(() => {
     if (
@@ -988,29 +126,14 @@
       calculateBudget(
         requestedCalculations.budgetVariableName /*, budgetCalculationNames */,
       ) // Don't await
-      $requestedSimulationSent = false
+      shared.requestedSimulationSent = false
     }
   })
-  run(() => {
-    if ($requestedSimulationEmail !== undefined) {
+  $effect(() => {
+    if (shared.requestedSimulationEmail !== undefined) {
       sendBudgetSimulationDemand()
     }
   })
-  // run(() => {
-  //   if (
-  //     browser &&
-  //     Object.keys($requestedCalculations.situationIndexByCalculationName)
-  //       .length > 0
-  //   ) {
-  //     const situationIndexByCalculationName =
-  //       $requestedCalculations.situationIndexByCalculationName
-  //     $requestedCalculations = {
-  //       ...$requestedCalculations,
-  //       situationIndexByCalculationName: {},
-  //     }
-  //     calculateTestCases(situationIndexByCalculationName)
-  //   }
-  // })
   $effect(() => {
     if (
       Object.keys(requestedCalculations.situationIndexByCalculationName)
@@ -1019,37 +142,27 @@
       $inspect("avant", requestedCalculations.situationIndexByCalculationName)
       const situationIndexByCalculationName =
         requestedCalculations.situationIndexByCalculationName
-      untrack(() => {
-        requestedCalculations.situationIndexByCalculationName = {}
-      })
+      requestedCalculations.situationIndexByCalculationName = {}
       $inspect("après", requestedCalculations.situationIndexByCalculationName)
       calculateTestCases(situationIndexByCalculationName)
     }
     $inspect("fin")
   })
-  run(() => {
-    if (browser && $requestedVariablesNameToCalculate !== undefined) {
-      calculateTestCasesAdditionalVariables($requestedVariablesNameToCalculate)
-      $requestedVariablesNameToCalculate = undefined
-    }
-  })
-  run(() => {
-    if (browser && matomoConfig !== undefined && $page) {
-      trackPageView(url, matomoConfig.prependDomain)
+  $effect(() => {
+    if (shared.requestedVariablesNameToCalculate !== undefined) {
+      calculateTestCasesAdditionalVariables(
+        shared.requestedVariablesNameToCalculate,
+      )
+      shared.requestedVariablesNameToCalculate = undefined
     }
   })
-  run(() => {
-    if (
-      browser &&
-      matomoConfig !== undefined &&
-      Object.keys($parametricReform).length !== 0
-    ) {
-      trackParametricReform($parametricReform, matomoConfig.prependDomain)
-    }
+  $effect(() => {
+    shared.showTutorial = localStorage.getItem("hideTutorial") === null
   })
-  run(() => {
-    if (browser) {
-      $showTutorial = localStorage.getItem("hideTutorial") === null
+
+  onNavigate((navigation) => {
+    if (navigation.to?.route?.id !== navigation.from?.route?.id) {
+      shared.navbarConfig = getNavbarConfig(navigation.to?.route?.id ?? "/")
     }
   })
 </script>
@@ -1075,7 +188,7 @@
 
 <div
   class="flex flex-col flex-nowrap md:h-screen"
-  class:h-screen={$searchActive}
+  class:h-screen={shared.searchActive}
 >
   <NavBar />
 
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 7d677202f4fe2d3c3ff46e6abd4cdde2c6956a3a..5cc6a390b1788090751e325a7fa87ae82e3f2f27 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -17,23 +17,18 @@
   import * as htmlToImage from "html-to-image"
   import introJs from "intro.js"
   import type { IntroStep } from "intro.js/src/core/steps"
-  import { getContext, setContext, mount, unmount } from "svelte"
+  import { getContext, setContext, mount, unmount, untrack } from "svelte"
   import { quartOut } from "svelte/easing"
   import { writable, type Writable } from "svelte/store"
   import { fade, fly } from "svelte/transition"
 
   import type { PageData } from "./$types"
 
-  import { browser } from "$app/environment"
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
   import { auditSimulationHash } from "$lib/auditors/hashes"
   import { auditQueryArray, auditQuerySingleton } from "$lib/auditors/queries"
-  import type { BudgetSimulation } from "$lib/budgets"
-  import {
-    requestAllBudgetCalculations,
-    type RequestedCalculations,
-  } from "$lib/calculations.svelte"
+  import { requestAllBudgetCalculations } from "$lib/calculations.svelte"
   import BudgetLayout from "$lib/components/budget/BudgetLayout.svelte"
   import BudgetConnexionModal from "$lib/components/BudgetConnexionModal.svelte"
   import BudgetSimulationSharingModal from "$lib/components/BudgetSimulationSharingModal.svelte"
@@ -60,8 +55,6 @@
     getDecompositionParentName,
     getLatestCalculation,
     waterfalls,
-    type DecompositionByName,
-    type EvaluationByName,
   } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { entityByKey } from "$lib/entities"
@@ -71,7 +64,14 @@
     trackTestCaseEdit,
   } from "$lib/matomo"
   import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
+  import {
+    billActive,
+    billName,
+    budgetDate,
+    date,
+    shared,
+    year,
+  } from "$lib/shared.svelte"
   import { publishTestCaseSimulation } from "$lib/simulations"
   import { getPopulationReservedKeys, type Situation } from "$lib/situations"
   import type { TabsConfig } from "$lib/tabs"
@@ -82,7 +82,6 @@
     budgetVariablesConfig,
     budgetVariablesName,
     budgetVariablesNameRelated,
-    type ValuesByCalculationNameByVariableName,
     variableSummaryByName,
     variableSummaryByNameByReformName,
   } from "$lib/variables"
@@ -91,27 +90,16 @@
     data: PageData
   }
 
-  const { appTitle, baseUrl, reformName } = publicConfig
+  const { appTitle, baseUrl } = publicConfig
+
   let { data }: Props = $props()
 
   let animationEndedTimeoutId = undefined
-  const billActive = getContext("billActive") as Writable<boolean>
-  const budgetSimulation = getContext("budgetSimulation") as Writable<
-    BudgetSimulation | undefined
-  >
-  const budgetDate = getContext("budgetDate") as Writable<string>
   let clipboardElement: HTMLElement = $state()
-  const date = getContext("date") as Writable<string>
-  const decompositionByName = getContext(
-    "decompositionByName",
-  ) as Writable<DecompositionByName>
   let displayMode: DisplayMode = $state({
     testCasesIndex: [],
     waterfallName: waterfalls[0].name,
   })
-  const displayModeWritable = getContext("displayMode") as Writable<
-    DisplayMode | undefined
-  >
   const dispositifsTypes = [
     {
       title: "Impôt sur le revenu",
@@ -217,22 +205,12 @@
       ],
     },
   ]
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
   const formatLongOrdinalSup = (n: number) => {
     const rule = ordinalPluralRules.select(n)
     const suffix = longOrdinalSuffixes.get(rule)
     return `${n}<sup>${suffix}</sup>`
   }
   let highlightDecomposition = false
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
   let isBudgetConnexionModalOpen = $state(false)
   let isBudgetSharingModalOpen = $state(false)
   let isTestCaseSelectModalOpen = $state(false)
@@ -243,14 +221,6 @@
   setContext("newSelfTargetAProps", newSelfTargetAProps)
   setContext("onCopyParameterLink", onCopyParameterLink)
   const ordinalPluralRules = new Intl.PluralRules("fr-FR", { type: "ordinal" })
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const searchActive = getContext("searchActive") as Writable<boolean>
-  const searchVariableName = getContext("searchVariableName") as Writable<
-    string | undefined
-  >
-  const showTutorial = getContext("showTutorial") as Writable<boolean>
   const tabsConfig = $state({
     defaultTab: "fiche_de_paie",
     tabs: [
@@ -272,20 +242,13 @@
       },
     ],
   } as TabsConfig)
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
   let testCaseSharingModal: { open: boolean; token?: string } = $state({
     open: false,
   })
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
   const variableModalOpen: Writable<boolean> = writable(false)
   setContext("variableModalOpen", variableModalOpen)
   let variablesHistory: string[] = $state([])
-  const waterfall = getContext("waterfall") as Writable<Waterfall>
   let windowInnerWidth: number | undefined = $state(undefined)
-  const year = getContext("year") as Writable<number>
 
   function auditSimulationQuery(
     audit: Audit,
@@ -336,7 +299,7 @@
         auditStringToNumber,
         auditInteger,
         auditTest(
-          (index) => index >= 0 && index < $testCases.length,
+          (index) => index >= 0 && index < shared.testCases.length,
           "Ce numéro ne correspond à aucun cas type",
         ),
       ),
@@ -368,7 +331,7 @@
         auditStringToNumber,
         auditInteger,
         auditTest(
-          (index) => index >= 0 && index < $testCases.length,
+          (index) => index >= 0 && index < shared.testCases.length,
           "Ce numéro ne correspond à aucun cas type",
         ),
       ),
@@ -469,7 +432,7 @@
 
   // function changeBillName({ target }: Event) {
   //   const { value } = target as HTMLSelectElement
-  //   reformName = value === "undefined" ? undefined : value
+  //   billName = value === "undefined" ? undefined : value
   //   $requestedCalculations = requestTestCasesCalculation(
   //     $requestedCalculations,
   //     "bill",
@@ -494,13 +457,6 @@
     changeSituation(situationIndex, situation)
   }
 
-  function changeDecompositionByName(
-    situationIndex: number,
-    newDecompositionByName: DecompositionByName,
-  ): void {
-    $decompositionByName = newDecompositionByName
-  }
-
   function changeInputInstantsByVariableName(
     situationIndex: number,
     inputInstantsByVariableName: {
@@ -508,17 +464,18 @@
     },
   ): void {
     const newInputInstantsByVariableNameArray = [
-      ...$inputInstantsByVariableNameArray,
+      ...shared.inputInstantsByVariableNameArray,
     ]
     newInputInstantsByVariableNameArray[situationIndex] =
       inputInstantsByVariableName
-    $inputInstantsByVariableNameArray = newInputInstantsByVariableNameArray
+    shared.inputInstantsByVariableNameArray =
+      newInputInstantsByVariableNameArray
   }
 
   function changeSituation(situationIndex: number, situation: Situation): void {
-    const situations = [...$testCases]
+    const situations = [...shared.testCases]
     situations[situationIndex] = situation
-    $testCases = situations
+    shared.testCases = situations
   }
 
   function changeTestCasesIndex(testCasesIndex: number[]): void {
@@ -594,8 +551,8 @@
       ...validQueryDisplayMode,
       ...validHashDisplayMode,
     }
-    $testCasesIndex = displayMode.testCasesIndex
-    $waterfall = waterfalls.find(
+    shared.testCasesIndex = displayMode.testCasesIndex
+    shared.waterfall = waterfalls.find(
       ({ name }) => name === displayMode.waterfallName,
     )
 
@@ -607,7 +564,7 @@
     ) {
       // Only called once, when the page has been loaded from the server
       // with a budget=true query parameter
-      $budgetSimulation = undefined
+      shared.budgetSimulation = undefined
       setTimeout(() => {
         requestAllBudgetCalculations(displayMode.parametersVariableName)
       }, 300)
@@ -617,19 +574,13 @@
     if (displayMode.parametersVariableName !== undefined) {
       for (let variableName = displayMode.parametersVariableName; ; ) {
         const parentVariableName = getDecompositionParentName(
-          $decompositionByName,
+          shared.decompositionByName,
           variableName,
         )
         if (parentVariableName === undefined) {
           break
         }
-        $decompositionByName = {
-          ...$decompositionByName,
-          [parentVariableName]: {
-            ...$decompositionByName[parentVariableName],
-            open: true,
-          },
-        }
+        shared.decompositionByName[parentVariableName].open = true
         variableName = parentVariableName
       }
     }
@@ -671,7 +622,7 @@
       { noScroll: true },
     )
 
-    $searchVariableName = undefined
+    shared.searchVariableName = undefined
   }
 
   function newSelfTargetAProps(urlPath: string): SelfTargetAProps {
@@ -702,19 +653,20 @@
           parameterHash: parameterName,
           mobileLaw: true,
         },
-        inputInstantsByVariableNameArray: $inputInstantsByVariableNameArray.map(
-          (inputInstantsByVariableName) =>
-            Object.fromEntries(
-              Object.entries(inputInstantsByVariableName).map(
-                ([variableName, inputInstants]) => [
-                  variableName,
-                  [...inputInstants],
-                ],
+        inputInstantsByVariableNameArray:
+          shared.inputInstantsByVariableNameArray.map(
+            (inputInstantsByVariableName) =>
+              Object.fromEntries(
+                Object.entries(inputInstantsByVariableName).map(
+                  ([variableName, inputInstants]) => [
+                    variableName,
+                    [...inputInstants],
+                  ],
+                ),
               ),
-            ),
-        ),
-        parametricReform: $parametricReform,
-        testCases: $testCases,
+          ),
+        parametricReform: shared.parametricReform,
+        testCases: shared.testCases,
       }),
     )
 
@@ -766,10 +718,10 @@
 
     const token = await publishTestCaseSimulation(
       blob,
-      $displayModeWritable!,
-      $inputInstantsByVariableNameArray,
-      $parametricReform,
-      $testCases,
+      shared.displayMode!,
+      shared.inputInstantsByVariableNameArray,
+      shared.parametricReform,
+      shared.testCases,
     )
 
     if (token !== undefined) {
@@ -795,25 +747,31 @@
     }
   }
   let { user } = $derived(data)
-  run(() => {
+  if ($page.url.searchParams || $page.url.hash) {
     ensureValidDisplayMode($page.url.searchParams, $page.url.hash)
+  }
+  $effect(() => {
+    if ($page.url.searchParams || $page.url.hash) {
+      untrack(() =>
+        ensureValidDisplayMode($page.url.searchParams, $page.url.hash),
+      )
+    }
   })
-  run(() => {
-    $displayModeWritable = displayMode
+  $effect(() => {
+    shared.displayMode = displayMode
   })
-  run(() => {
+  $effect(() => {
     if (displayMode?.parameterHash !== undefined) {
       clearParameterHash()
     }
   })
-  run(() => {
+  $effect(() => {
     if (
-      browser &&
       windowInnerWidth !== undefined &&
       windowInnerWidth >= 768 &&
-      $showTutorial
+      shared.showTutorial
     ) {
-      $showTutorial = false
+      shared.showTutorial = false
       localStorage.setItem("hideTutorial", "true")
       introJs()
         .setOptions({
@@ -937,8 +895,8 @@
         .start()
     }
   })
-  run(() => {
-    loadSearchVariable($searchVariableName)
+  $effect(() => {
+    loadSearchVariable(shared.searchVariableName)
   })
   let mobileLawTab = $derived(
     windowInnerWidth !== undefined &&
@@ -946,7 +904,7 @@
       displayMode.mobileLaw,
   )
   let modificationsAmendmentCount = $derived(
-    Object.keys($parametricReform).length,
+    Object.keys(shared.parametricReform).length,
   )
   let showBudgetBlurred = $derived(
     displayMode.budget &&
@@ -954,21 +912,21 @@
       (!mobileLawTab ||
         (windowInnerWidth !== undefined && windowInnerWidth >= 768)) &&
       displayMode.parametersVariableName !== undefined &&
-      Object.keys($parametricReform).filter((parameterName) =>
+      Object.keys(shared.parametricReform).filter((parameterName) =>
         budgetEditableParametersName.has(parameterName),
       ).length > 0 &&
-      Object.keys($parametricReform).length > 0 &&
-      $budgetSimulation !== undefined &&
-      ($budgetSimulation.errors == null ||
-        $budgetSimulation.errors.length === 0) &&
-      $budgetSimulation?.result?.amendement === undefined,
+      Object.keys(shared.parametricReform).length > 0 &&
+      shared.budgetSimulation !== undefined &&
+      (shared.budgetSimulation.errors == null ||
+        shared.budgetSimulation.errors.length === 0) &&
+      shared.budgetSimulation?.result?.amendement === undefined,
   )
   let showPublicSimulationPanel = $derived(
     displayMode.budget &&
       !mobileLawTab &&
       displayMode.parametersVariableName !== undefined &&
-      Object.keys($parametricReform).length > 0 &&
-      $budgetSimulation?.result?.amendement !== undefined,
+      Object.keys(shared.parametricReform).length > 0 &&
+      shared.budgetSimulation?.result?.amendement !== undefined,
   )
   run(() => {
     tabsConfig.tabs[0].disabled =
@@ -992,7 +950,7 @@
 
 <main
   class="relative flex h-full flex-1 overflow-x-clip bg-graph-paper md:overflow-hidden"
-  class:overflow-hidden={$searchActive}
+  class:overflow-hidden={shared.searchActive}
 >
   <div
     class="flex w-full flex-col {displayMode.edit !== undefined
@@ -1070,7 +1028,7 @@
         class="flex min-w-0 flex-[1_0_100%] overflow-y-scroll bg-white shadow-lg transition-transform duration-500 ease-out-quart md:z-10 md:!h-full md:flex-[0_0_33.3%] md:translate-x-0 md:overflow-visible md:!p-0"
         class:-translate-x-full={!mobileLawTab}
         class:!h-[calc(100vh-96px)]={!mobileLawTab}
-        class:pb-24={$testCasesIndex.length === 1 &&
+        class:pb-24={shared.testCasesIndex.length === 1 &&
           displayMode.parametersVariableName === undefined}
         id="situation_left_part_law"
       >
@@ -1103,7 +1061,7 @@
                     Sélectionner un impôt, une cotisation ou une
                     prestation&nbsp;:
                   </h2>
-                  {#if $billActive}
+                  {#if billActive}
                     <PlfVariablesListIntro {displayMode} />
                   {/if}
                   {#key displayMode.budget}
@@ -1267,7 +1225,7 @@
                       in:fade={{ delay: 150, duration: 150 }}
                     >
                       <VariableReferredParameters
-                        date={$budgetDate}
+                        date={budgetDate}
                         {displayMode}
                         name={displayMode.parametersVariableName}
                       />
@@ -1304,7 +1262,7 @@
                 class="rounded border-1 text-xs"
                 on:blur={changeBillName}
                 on:change={changeBillName}
-                value={reformName}
+                value={billName}
               >
                 <option value={undefined}>Pas de projet/proposition de loi</option>
                 {#each metadata.reforms as { label, name }}
@@ -1383,9 +1341,9 @@
                 class="absolute -bottom-4 right-2 z-30 flex items-center gap-2 rounded border border-le-bleu bg-white px-5 py-2 text-sm font-bold uppercase tracking-[0.085em] text-le-bleu shadow-lg transition-all duration-200 ease-out-back hover:bg-gray-100 active:bg-gray-200 disabled:scale-90 disabled:opacity-0 lg:right-5 xl:right-10"
                 onclick={() => (isBudgetSharingModalOpen = true)}
                 disabled={displayMode.parametersVariableName === undefined ||
-                  $budgetSimulation === undefined ||
-                  ($budgetSimulation.errors != null &&
-                    $budgetSimulation.errors.length > 0)}
+                  shared.budgetSimulation === undefined ||
+                  (shared.budgetSimulation.errors != null &&
+                    shared.budgetSimulation.errors.length > 0)}
               >
                 <span class="hidden lg:inline">Enregistrer / partager</span>
                 <iconify-icon class="text-lg" icon="ri:share-fill"
@@ -1426,7 +1384,7 @@
                     >
                       {#if !budgetVariablesName.has(displayMode.parametersVariableName) && !budgetVariablesNameRelated.has(displayMode.parametersVariableName)}
                         {@const variable =
-                          $decompositionByName[
+                          shared.decompositionByName[
                             displayMode.parametersVariableName
                           ] ??
                           variableSummaryByName[
@@ -1443,7 +1401,7 @@
 
                         <!--Panneau indicateur que d'autres dispositifs sont disponibles en budgétaire-->
                         <WithoutBudgetCard {displayMode} {variable} />
-                      {:else if $budgetSimulation === undefined && !budgetVariablesNameRelated.has(displayMode.parametersVariableName)}
+                      {:else if shared.budgetSimulation === undefined && !budgetVariablesNameRelated.has(displayMode.parametersVariableName)}
                         <!--Skeleton Loader qui apparait quand le budget charge-->
                         {@const budgetVariableName =
                           displayMode.parametersVariableName !== undefined
@@ -1455,11 +1413,11 @@
                           ? {
                               ...budgetVariablesConfig[budgetVariableName],
                               label:
-                                $decompositionByName[budgetVariableName]
+                                shared.decompositionByName[budgetVariableName]
                                   ?.short_label ??
                                 variableSummaryByName[budgetVariableName]
                                   ?.short_label ??
-                                $decompositionByName[budgetVariableName]
+                                shared.decompositionByName[budgetVariableName]
                                   ?.label ??
                                 variableSummaryByName[budgetVariableName]
                                   ?.label ??
@@ -1471,7 +1429,7 @@
                           {budgetVariable?.label}
                         </div>
                         <SkeletonLoaderBudget />
-                      {:else if $budgetSimulation !== undefined && $budgetSimulation.errors != null && $budgetSimulation.errors.length > 0}
+                      {:else if shared.budgetSimulation !== undefined && shared.budgetSimulation.errors != null && shared.budgetSimulation.errors.length > 0}
                         <div
                           class="mx-auto flex w-fit flex-col items-center gap-10 rounded-lg border border-gray-200 bg-white p-10 shadow-md md:mt-32"
                         >
@@ -1479,14 +1437,14 @@
                             class="text-6xl"
                             icon="material-symbols:report-outline"
                           ></iconify-icon>
-                          {#each $budgetSimulation.errors as error}
+                          {#each shared.budgetSimulation.errors as error}
                             <span>{error}</span>
                           {/each}
                         </div>
                       {:else}
                         <BudgetLayout
                           blur={showBudgetBlurred}
-                          budgetSimulation={$budgetSimulation}
+                          budgetSimulation={shared.budgetSimulation}
                           {displayMode}
                         />
                       {/if}
@@ -1543,7 +1501,7 @@
                 </div>
               {/key}
             {:else}
-              {#key $testCasesIndex.length || displayMode.parametersVariableName}
+              {#key shared.testCasesIndex.length || displayMode.parametersVariableName}
                 <div
                   class={!displayMode.edit
                     ? "px-3 py-4 md:px-5 xl:px-10 xl:py-8"
@@ -1555,39 +1513,34 @@
                     {displayMode}
                     bind:isOpen={isTestCaseSelectModalOpen}
                     on:changeTestCasesIndex
-                    year={$year}
+                    {year}
                   />
-                  {#if $testCasesIndex.length > 0}
+                  {#if shared.testCasesIndex.length > 0}
                     <!-- Cas types avec leur waterfall -->
-                    {#if $testCasesIndex.length === 1}
+                    {#if shared.testCasesIndex.length === 1}
                       <TestCaseView
-                        decompositionByName={$decompositionByName}
                         {displayMode}
                         {highlightDecomposition}
-                        on:changeDecompositionByName={({ detail }) =>
-                          changeDecompositionByName($testCasesIndex[0], detail)}
                         on:changeSituation={({ detail }) =>
-                          changeSituation($testCasesIndex[0], detail)}
+                          changeSituation(shared.testCasesIndex[0], detail)}
                         on:changeTestCasesIndex={({ detail }) =>
                           changeTestCasesIndex(detail)}
                         on:changeTestCaseToEditIndex={({ detail }) => {
                           changeTestCaseToEditIndex(detail)
                           trackTestCaseEdit()
                         }}
-                        situation={$testCases[$testCasesIndex[0]]}
-                        situationIndex={$testCasesIndex[0]}
+                        situation={shared.testCases[shared.testCasesIndex[0]]}
+                        situationIndex={shared.testCasesIndex[0]}
                         {tabsConfig}
-                        valuesByCalculationNameByVariableName={$valuesByCalculationNameByVariableNameArray[
-                          $testCasesIndex[0]
+                        valuesByCalculationNameByVariableName={shared
+                          .valuesByCalculationNameByVariableNameArray[
+                          shared.testCasesIndex[0]
                         ]}
-                        year={$year}
+                        {year}
                       />
                     {:else}
                       <TestCaseCompareView
-                        decompositionByName={$decompositionByName}
                         {displayMode}
-                        on:changeDecompositionByName={({ detail }) =>
-                          changeDecompositionByName($testCasesIndex[0], detail)}
                         on:changeSituation={changeCompareSituation}
                         on:changeTestCasesIndex={({ detail }) =>
                           changeTestCasesIndex(detail)}
@@ -1595,8 +1548,8 @@
                           changeTestCaseToEditIndex(detail)
                           trackTestCaseEdit()
                         }}
-                        situationsToCompareIndex={$testCasesIndex}
-                        year={$year}
+                        situationsToCompareIndex={shared.testCasesIndex}
+                        {year}
                       />
                     {/if}
                   {:else}
@@ -1609,15 +1562,15 @@
                         </h2>
                       {:else}
                         {@const variableSummary =
-                          reformName === undefined
+                          billName === undefined
                             ? variableSummaryByName[
                                 displayMode.parametersVariableName
                               ]
-                            : variableSummaryByNameByReformName[reformName][
+                            : variableSummaryByNameByReformName[billName][
                                 displayMode.parametersVariableName
                               ]}
                         {#if variableSummary !== undefined}
-                          {@const indexedTestCases = $testCases
+                          {@const indexedTestCases = shared.testCases
                             .map((situation, situationIndex) => ({
                               situation,
                               situationIndex,
@@ -1666,11 +1619,11 @@
                                   : 0
                                 : 1,
                             )}
-                          {@const nonNullTestCases = $testCases.reduce(
+                          {@const nonNullTestCases = shared.testCases.reduce(
                             (arr, curr, index) => {
                               const latestCalculationValue =
                                 getLatestCalculation(
-                                  $evaluationByNameArray[index][
+                                  shared.evaluationByNameArray[index][
                                     displayMode.parametersVariableName
                                   ]?.calculationEvaluationByName,
                                 )?.deltaAtVectorIndex
@@ -1694,7 +1647,7 @@
                             [],
                           )}
                           {@const shortLabel =
-                            $decompositionByName[
+                            shared.decompositionByName[
                               displayMode.parametersVariableName
                             ]?.short_label ?? variableSummary.short_label}
 
@@ -1741,10 +1694,11 @@
                                           mode="select"
                                           {situation}
                                           situationIndex={index}
-                                          valuesByCalculationNameByVariableName={$valuesByCalculationNameByVariableNameArray[
+                                          valuesByCalculationNameByVariableName={shared
+                                            .valuesByCalculationNameByVariableNameArray[
                                             index
                                           ]}
-                                          year={$year}
+                                          {year}
                                         />
                                       </div>
                                       <div
@@ -1758,9 +1712,8 @@
                                           {shortLabel}&nbsp;:
                                           <VariableValueChange
                                             bold={true}
-                                            evaluationByName={$evaluationByNameArray[
-                                              index
-                                            ]}
+                                            evaluationByName={shared
+                                              .evaluationByNameArray[index]}
                                             inline
                                             name={displayMode.parametersVariableName}
                                           />
@@ -1834,7 +1787,7 @@
                                           <TestCasePictos
                                             classes="[&>svg]:w-7 [&>svg]:h-7 col-span-3 last:odd:col-start-3 justify-center"
                                             situation={situations[0]}
-                                            year={$year}
+                                            {year}
                                           />
                                         </div>
                                       {/if}
@@ -1858,9 +1811,8 @@
                                           {/if}
                                           <VariableValueChange
                                             bold={true}
-                                            evaluationByName={$evaluationByNameArray[
-                                              index
-                                            ]}
+                                            evaluationByName={shared
+                                              .evaluationByNameArray[index]}
                                             inline
                                             name={displayMode.parametersVariableName}
                                           />
@@ -1887,16 +1839,16 @@
                     >
                       {#if displayMode.parametersVariableName !== undefined}
                         {@const variableSummary =
-                          reformName === undefined
+                          billName === undefined
                             ? variableSummaryByName[
                                 displayMode.parametersVariableName
                               ]
-                            : variableSummaryByNameByReformName[reformName][
+                            : variableSummaryByNameByReformName[billName][
                                 displayMode.parametersVariableName
                               ]}
                         {#if displayMode.testCasesIndex.length > 0}
                           {@const shortLabel =
-                            $decompositionByName[
+                            shared.decompositionByName[
                               displayMode.parametersVariableName
                             ]?.short_label ?? variableSummary.short_label}
                           <a
@@ -2015,21 +1967,20 @@
       </div>
       <div class="overflow-y-scroll">
         <TestCaseEdit
-          date={$date}
-          inputInstantsByVariableName={$inputInstantsByVariableNameArray[
+          {date}
+          inputInstantsByVariableName={shared.inputInstantsByVariableNameArray[
             displayMode.edit
           ] ?? {}}
           on:changeInputInstantsByVariableName={({ detail }) =>
             changeInputInstantsByVariableName(displayMode.edit, detail)}
           on:changeSituation={({ detail }) =>
             changeSituation(displayMode.edit, detail)}
-          situation={$testCases[displayMode.edit] ?? {}}
+          situation={shared.testCases[displayMode.edit] ?? {}}
           situationIndex={displayMode.edit}
-          valuesByCalculationNameByVariableName={$valuesByCalculationNameByVariableNameArray[
-            displayMode.edit
-          ]}
+          valuesByCalculationNameByVariableName={shared
+            .valuesByCalculationNameByVariableNameArray[displayMode.edit]}
           variableName={displayMode.variableName}
-          year={$year}
+          {year}
         />
         <!-- #75 !253 : cache le panneau, on pourrait le mettre en tooltip/modale plus tard -->
         <!--        <div class="m-4 rounded bg-le-bleu-light p-2 text-gray-700 shadow-md">-->
@@ -2137,15 +2088,14 @@
 
 {#if displayMode.testCasesIndex !== undefined && displayMode.testCasesIndex.length > 0}
   {@const testCaseIndex = displayMode.testCasesIndex[0]}
-  {@const testCase = $testCases[testCaseIndex]}
+  {@const testCase = shared.testCases[testCaseIndex]}
   <TestCaseScreenshotLayout
-    decompositionByName={$decompositionByName}
     {displayMode}
-    evaluationByNameArray={$evaluationByNameArray}
+    evaluationByNameArray={shared.evaluationByNameArray}
     {testCase}
     {testCaseIndex}
-    valuesByCalculationNameByVariableNameArray={$valuesByCalculationNameByVariableNameArray}
-    year={$year}
+    valuesByCalculationNameByVariableNameArray={shared.valuesByCalculationNameByVariableNameArray}
+    {year}
   />
 {/if}
 
diff --git a/src/routes/accueil/+page.svelte b/src/routes/accueil/+page.svelte
index b74ae8ddcfe9468cbc01bfa93e61b4e31a38c5b0..3a6e2a358c994cb0e73b55f25e9ee4eab1bfac11 100644
--- a/src/routes/accueil/+page.svelte
+++ b/src/routes/accueil/+page.svelte
@@ -10,9 +10,6 @@
   import { getContext } from "svelte"
   import type { Writable } from "svelte/store"
 
-  import type { PageData } from "./$types"
-
-  import { browser } from "$app/environment"
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
   import { auditQuerySingleton } from "$lib/auditors/queries"
@@ -28,8 +25,8 @@
   import { waterfalls, withLinkedVariableNames } from "$lib/decompositions"
   import type { DisplayMode } from "$lib/displays"
   import { trackSearchVariable } from "$lib/matomo"
-  import type { NavbarConfig } from "$lib/navbar"
   import publicConfig from "$lib/public_config"
+  import { billActive, shared } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
 
   const { appTitle } = publicConfig
@@ -38,8 +35,6 @@
     testCasesIndex: [],
     waterfallName: waterfalls[0].name,
   })
-  const billActive = getContext("billActive") as Writable<boolean>
-  const navbarConfig = getContext("navbarConfig") as Writable<NavbarConfig>
   const searchVariableName = getContext("searchVariableName") as Writable<
     string | undefined
   >
@@ -188,29 +183,27 @@
       { noScroll: true },
     )
 
-    $searchVariableName = undefined
+    shared.searchVariableName = undefined
   }
-  run(() => {
+  $effect(() => {
     ensureValidDisplayMode($page.url.searchParams)
   })
-  run(() => {
-    loadSearchVariable($searchVariableName)
+  $effect(() => {
+    loadSearchVariable(shared.searchVariableName)
   })
   let variablesCount = $derived(withLinkedVariableNames.length - 100)
-  run(() => {
-    if (browser) {
-      if (displayMode.parametersVariableName !== undefined) {
-        document.body.classList.add("overflow-hidden")
-        $navbarConfig = {
-          position: "fixed",
-          showSearch: true,
-        }
-      } else {
-        document.body.classList.remove("overflow-hidden")
-        $navbarConfig = {
-          position: "fixed",
-          showSearch: false,
-        }
+  $effect(() => {
+    if (displayMode.parametersVariableName !== undefined) {
+      document.body.classList.add("overflow-hidden")
+      shared.navbarConfig = {
+        position: "fixed",
+        showSearch: true,
+      }
+    } else {
+      document.body.classList.remove("overflow-hidden")
+      shared.navbarConfig = {
+        position: "fixed",
+        showSearch: false,
       }
     }
   })
@@ -227,8 +220,8 @@
 <main class="h-full bg-yellow-50 pt-24 md:pt-12 2xl:pt-14">
   <section
     class="fond relative py-10 before:absolute before:inset-x-0 before:top-0 before:h-[50vh] before:bg-gradient-to-b before:from-[#9AAAB4] before:to-transparent"
-    class:max-h-none={$billActive}
-    class:h-[78vh]={!$billActive}
+    class:max-h-none={billActive}
+    class:h-[78vh]={!billActive}
   >
     <div
       class="relative z-10 flex h-full flex-col items-center justify-evenly text-base md:text-lg 2xl:text-2xl"
@@ -321,7 +314,7 @@
             ></iconify-icon></a
           >
         </div>
-        {#if $billActive}
+        {#if billActive}
           <div>
             <h2 class="mt-10 text-xl font-bold xl:text-2xl 2xl:text-3xl">
               Consulter les impacts du PLF / PLFSS 2025&nbsp;:
diff --git a/src/routes/auth/prepare/+page.svelte b/src/routes/auth/prepare/+page.svelte
index 3105b2e435a6b5956e650f27fbe5bd03db4663a6..abd35ca512d1c4fcee8a61d6f226ce7c688ad5c9 100644
--- a/src/routes/auth/prepare/+page.svelte
+++ b/src/routes/auth/prepare/+page.svelte
@@ -1,49 +1,32 @@
 <script lang="ts">
-  import { getContext, onMount } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { onMount } from "svelte"
 
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
-  import type { DisplayMode } from "$lib/displays"
-  import type { ParametricReform } from "$lib/reforms"
-  import type { Situation } from "$lib/situations"
-
-  const displayMode = getContext("displayMode") as Writable<
-    DisplayMode | undefined
-  >
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const testCases = getContext("testCases") as Writable<Situation[]>
+  import { shared } from "$lib/shared.svelte"
 
   onMount(() => {
     localStorage.setItem(
       "simulatorState",
       JSON.stringify({
         displayMode: {
-          ...$displayMode,
+          ...shared.displayMode,
           parameterHash: undefined,
         },
-        inputInstantsByVariableNameArray: $inputInstantsByVariableNameArray.map(
-          (inputInstantsByVariableName) =>
-            Object.fromEntries(
-              Object.entries(inputInstantsByVariableName).map(
-                ([variableName, inputInstants]) => [
-                  variableName,
-                  [...inputInstants],
-                ],
+        inputInstantsByVariableNameArray:
+          shared.inputInstantsByVariableNameArray.map(
+            (inputInstantsByVariableName) =>
+              Object.fromEntries(
+                Object.entries(inputInstantsByVariableName).map(
+                  ([variableName, inputInstants]) => [
+                    variableName,
+                    [...inputInstants],
+                  ],
+                ),
               ),
-            ),
-        ),
-        parametricReform: $parametricReform,
-        testCases: $testCases,
+          ),
+        parametricReform: shared.parametricReform,
+        testCases: shared.testCases,
       }),
     )
 
diff --git a/src/routes/auth/restore_state/+page.svelte b/src/routes/auth/restore_state/+page.svelte
index 1197e8e70a3ba8d1ff1771a4b36464cefbd8f736..f9952e9038859580c6c5b9feb8df2d7367c55a9a 100644
--- a/src/routes/auth/restore_state/+page.svelte
+++ b/src/routes/auth/restore_state/+page.svelte
@@ -1,42 +1,17 @@
 <script lang="ts">
-  import { getContext, onMount } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { onMount } from "svelte"
 
   import { goto } from "$app/navigation"
-  import {
-    requestAllTestCasesCalculations,
-    type RequestedCalculations,
-  } from "$lib/calculations.svelte"
-  import type { EvaluationByName } from "$lib/decompositions"
-  import type { ParametricReform } from "$lib/reforms"
-  import type { Situation } from "$lib/situations"
+  import { requestAllTestCasesCalculations } from "$lib/calculations.svelte"
+  import { shared } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
-  import type { ValuesByCalculationNameByVariableName } from "$lib/variables"
-
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
 
   onMount(() => {
     const simulatorStateString = localStorage.getItem("simulatorState")
     if (simulatorStateString != undefined && simulatorStateString != null) {
       const simulatorState = JSON.parse(simulatorStateString)
 
-      $inputInstantsByVariableNameArray =
+      shared.inputInstantsByVariableNameArray =
         simulatorState.inputInstantsByVariableNameArray.map(
           (inputInstantsByVariableName) =>
             Object.fromEntries(
@@ -48,16 +23,16 @@
               ),
             ),
         )
-      $parametricReform = simulatorState.parametricReform
-      $testCases = simulatorState.testCases.map((situation) => {
+      shared.parametricReform = simulatorState.parametricReform
+      shared.testCases = simulatorState.testCases.map((situation) => {
         // Delete slider from each situation, because the activation of a slider
         // at initialization is not implemented.
         delete situation.slider
         return situation
       })
-      $evaluationByNameArray = new Array($testCases.length).fill({})
-      $valuesByCalculationNameByVariableNameArray = new Array(
-        $testCases.length,
+      shared.evaluationByNameArray = new Array(shared.testCases.length).fill({})
+      shared.valuesByCalculationNameByVariableNameArray = new Array(
+        shared.testCases.length,
       ).fill({})
 
       requestAllTestCasesCalculations(null)
diff --git a/src/routes/budgets/simulations/+page.svelte b/src/routes/budgets/simulations/+page.svelte
index 0dd8f4cf08d6b613783c58710c52f592ef78a288..1a7f89e94a9622707f801b0fba27dd70f8b3d215 100644
--- a/src/routes/budgets/simulations/+page.svelte
+++ b/src/routes/budgets/simulations/+page.svelte
@@ -1,17 +1,13 @@
 <script lang="ts">
-  import { getContext, onMount } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { onMount } from "svelte"
   import { fade } from "svelte/transition"
 
   import { goto } from "$app/navigation"
-  import type { DisplayMode } from "$lib/displays"
+  import { shared } from "$lib/shared.svelte"
   import type { CachedSimulation } from "$lib/simulations"
   import { newSimulationUrl } from "$lib/urls"
 
   let cachedSimulations: CachedSimulation[] = $state([])
-  const displayMode = getContext("displayMode") as Writable<
-    DisplayMode | undefined
-  >
   let loading = $state(true)
 
   onMount(async () => {
@@ -34,7 +30,11 @@
       class="inline-flex items-center gap-2 rounded-md border border-gray-700 bg-white px-5 py-2 text-sm font-bold uppercase tracking-[0.085em] text-gray-700 hover:bg-gray-100 active:bg-gray-200"
       title="Retour au simulateur"
       onclick={() =>
-        goto($displayMode === undefined ? "/" : newSimulationUrl($displayMode))}
+        goto(
+          shared.displayMode === undefined
+            ? "/"
+            : newSimulationUrl(shared.displayMode),
+        )}
     >
       <iconify-icon class="align-[-0.25rem] text-xl" icon="ri-arrow-left-line"
       ></iconify-icon>
diff --git a/src/routes/budgets/simulations/[simulation]/+page.svelte b/src/routes/budgets/simulations/[simulation]/+page.svelte
index 3f1411b347f2bee3745be4f86ecf0b7536f88ba7..56382f6efbb5e4ea37e23f3ede65f503c6990a0f 100644
--- a/src/routes/budgets/simulations/[simulation]/+page.svelte
+++ b/src/routes/budgets/simulations/[simulation]/+page.svelte
@@ -1,12 +1,11 @@
 <script lang="ts">
-  import { getContext, onMount } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { onMount } from "svelte"
 
   import type { PageData } from "./$types"
 
   import { goto } from "$app/navigation"
-  import type { ParametricReform } from "$lib/reforms"
   import { newSimulationUrl } from "$lib/urls"
+  import { shared } from "$lib/shared.svelte"
 
   interface Props {
     data: PageData
@@ -14,14 +13,10 @@
 
   let { data }: Props = $props()
 
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-
   let { simulation } = $derived(data)
 
   onMount(() => {
-    $parametricReform = simulation.parametricReform
+    shared.parametricReform = simulation.parametricReform
     goto(
       simulation.displayMode === undefined
         ? "/"
diff --git a/src/routes/test/+page.svelte b/src/routes/test/+page.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..5543ba48bed86fe0dd2dea125f4b9556b1c0d0e9
--- /dev/null
+++ b/src/routes/test/+page.svelte
@@ -0,0 +1,45 @@
+<script lang="ts">
+  import TestComponent from "$lib/components/TestComponent.svelte"
+
+  let variable = $state({
+    a: 1,
+    b: 2,
+  })
+
+  setTimeout(() => {
+    variable = undefined
+  }, 3000)
+</script>
+
+{#if variable !== undefined}
+  <TestComponent {variable} />
+{:else}
+  success
+{/if}
+
+<!--<script lang="ts">-->
+<!--  import { untrack } from "svelte"-->
+
+<!--  let x = $state(0)-->
+<!--  let variable = $state({-->
+<!--    a: 1,-->
+<!--    b: 2,-->
+<!--  })-->
+
+<!--  $effect(() => {-->
+<!--    if (x) {-->
+<!--      untrack(() => {-->
+<!--        variable = {-->
+<!--          a: 3,-->
+<!--          b: 4,-->
+<!--        }-->
+
+<!--        $inspect(variable.a)-->
+<!--      })-->
+<!--    }-->
+<!--  })-->
+<!--</script>-->
+
+<!--<button onclick={() => x++}> Plus </button>-->
+
+<!--{x}-->
diff --git a/src/routes/test_cases/simulations/[simulation]/+page.svelte b/src/routes/test_cases/simulations/[simulation]/+page.svelte
index 9b532594c567b384e8d6caac62096023dd209eaa..2022b6eb57f173034c709b6a642ad983a8df62bf 100644
--- a/src/routes/test_cases/simulations/[simulation]/+page.svelte
+++ b/src/routes/test_cases/simulations/[simulation]/+page.svelte
@@ -1,25 +1,15 @@
 <script lang="ts">
-  import { getContext, onMount } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { onMount } from "svelte"
 
   import type { PageData } from "./$types"
 
   import { goto } from "$app/navigation"
   import { page } from "$app/stores"
-  import {
-    requestAllTestCasesCalculations,
-    type RequestedCalculations,
-  } from "$lib/calculations.svelte"
+  import { requestAllTestCasesCalculations } from "$lib/calculations.svelte"
   import OpenGraph from "$lib/components/transverse_pages/OpenGraph.svelte"
-  import type {
-    EvaluationByName,
-    DecompositionByName,
-  } from "$lib/decompositions"
   import publicConfig from "$lib/public_config"
-  import type { ParametricReform } from "$lib/reforms"
-  import type { Situation } from "$lib/situations"
+  import { shared } from "$lib/shared.svelte"
   import { newSimulationUrl } from "$lib/urls"
-  import type { ValuesByCalculationNameByVariableName } from "$lib/variables"
   import { variableSummaryByName } from "$lib/variables.js"
 
   interface Props {
@@ -27,33 +17,13 @@
   }
 
   const { baseUrl } = publicConfig
-  let { data }: Props = $props()
 
-  const decompositionByName = getContext(
-    "decompositionByName",
-  ) as Writable<DecompositionByName>
-  const evaluationByNameArray = getContext("evaluationByNameArray") as Writable<
-    EvaluationByName[]
-  >
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const parametricReform = getContext(
-    "parametricReform",
-  ) as Writable<ParametricReform>
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
+  let { data }: Props = $props()
 
   let { simulation } = $derived(data)
 
   onMount(() => {
-    $inputInstantsByVariableNameArray =
+    shared.inputInstantsByVariableNameArray =
       simulation.inputInstantsByVariableNameArray.map(
         (inputInstantsByVariableName) =>
           Object.fromEntries(
@@ -65,11 +35,11 @@
             ),
           ),
       )
-    $parametricReform = simulation.parametricReform
-    $testCases = simulation.testCases
-    $evaluationByNameArray = new Array($testCases.length).fill({})
-    $valuesByCalculationNameByVariableNameArray = new Array(
-      $testCases.length,
+    shared.parametricReform = simulation.parametricReform
+    shared.testCases = simulation.testCases
+    shared.evaluationByNameArray = new Array(shared.testCases.length).fill({})
+    shared.valuesByCalculationNameByVariableNameArray = new Array(
+      shared.testCases.length,
     ).fill({})
 
     requestAllTestCasesCalculations(null)
@@ -87,12 +57,12 @@
 
 {#if simulation.displayMode.parametersVariableName !== undefined}
   <OpenGraph
-    description="➡️ Voici l'impact du dispositif «{$decompositionByName[
+    description="➡️ Voici l'impact du dispositif «{shared.decompositionByName[
       simulation.displayMode.parametersVariableName
     ]?.short_label ??
       variableSummaryByName[simulation.displayMode.parametersVariableName]
         ?.short_label ??
-      $decompositionByName[simulation.displayMode.parametersVariableName]
+      shared.decompositionByName[simulation.displayMode.parametersVariableName]
         ?.label ??
       variableSummaryByName[simulation.displayMode.parametersVariableName]
         ?.label}» sur ce cas type ! Le simulateur permet aussi de connaître les impôts, cotisations et prestations sociales de ce foyer."
diff --git a/src/routes/variables/[variable]/+page.svelte b/src/routes/variables/[variable]/+page.svelte
index 01152a9770bf653db5c081bd2fcc22c78d5ca83a..1274c8ca85be5d47bc3badab9bbdfd974ee20b7a 100644
--- a/src/routes/variables/[variable]/+page.svelte
+++ b/src/routes/variables/[variable]/+page.svelte
@@ -1,15 +1,14 @@
 <script lang="ts">
   import { run } from "svelte/legacy"
 
-  import { getContext, setContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { setContext } from "svelte"
 
   import type { PageData } from "./$types"
 
   import { goto } from "$app/navigation"
   import VariableView from "$lib/components/variables/VariableView.svelte"
-  import type { DisplayMode } from "$lib/displays"
   import publicConfig from "$lib/public_config"
+  import { shared } from "$lib/shared.svelte"
   import type { Situation } from "$lib/situations"
   import { newSelfTargetAProps, newSimulationUrl } from "$lib/urls"
   import type { ValuesByCalculationNameByVariableName } from "$lib/variables"
@@ -19,25 +18,8 @@
   }
 
   const { appTitle } = publicConfig
-  let { data }: Props = $props()
 
-  const date = getContext("date") as Writable<string>
-  const displayMode = getContext("displayMode") as Writable<
-    DisplayMode | undefined
-  >
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
-  const year = getContext("year") as Writable<number>
+  let { data }: Props = $props()
 
   setContext("newSelfTargetAProps", newSelfTargetAProps)
 
@@ -46,25 +28,26 @@
   }): void {
     if (
       inputInstantsByVariableName ===
-      $inputInstantsByVariableNameArray[testCaseIndex]
+      shared.inputInstantsByVariableNameArray[testCaseIndex]
     ) {
       return
     }
     const updatedInputInstantsByVariableNameArray = [
-      ...$inputInstantsByVariableNameArray,
+      ...shared.inputInstantsByVariableNameArray,
     ]
     updatedInputInstantsByVariableNameArray[testCaseIndex] =
       inputInstantsByVariableName
-    $inputInstantsByVariableNameArray = updatedInputInstantsByVariableNameArray
+    shared.inputInstantsByVariableNameArray =
+      updatedInputInstantsByVariableNameArray
   }
 
   function updateSituation(situation: Situation): void {
-    if (situation === $testCases[testCaseIndex]) {
+    if (situation === shared.testCases[testCaseIndex]) {
       return
     }
-    const situations = [...$testCases]
+    const situations = [...shared.testCases]
     situations[testCaseIndex] = situation
-    $testCases = situations
+    shared.testCases = situations
   }
 
   function updateValuesByCalculationNameByVariableName(
@@ -72,33 +55,33 @@
   ): void {
     if (
       valuesByCalculationNameByVariableName ===
-      $valuesByCalculationNameByVariableNameArray[testCaseIndex]
+      shared.valuesByCalculationNameByVariableNameArray[testCaseIndex]
     ) {
       return
     }
     const updatedValuesByCalculationNameByVariableNameArray = [
-      ...$valuesByCalculationNameByVariableNameArray,
+      ...shared.valuesByCalculationNameByVariableNameArray,
     ]
     updatedValuesByCalculationNameByVariableNameArray[testCaseIndex] =
       valuesByCalculationNameByVariableName
-    $valuesByCalculationNameByVariableNameArray =
+    shared.valuesByCalculationNameByVariableNameArray =
       updatedValuesByCalculationNameByVariableNameArray
   }
   let { variable } = $derived(data)
-  let testCaseIndex = $derived($testCasesIndex?.[0] ?? 0)
+  let testCaseIndex = $derived(shared.testCasesIndex?.[0] ?? 0)
   let inputInstantsByVariableName
   run(() => {
     inputInstantsByVariableName =
-      $inputInstantsByVariableNameArray[testCaseIndex]
+      shared.inputInstantsByVariableNameArray[testCaseIndex]
   })
   let situation
   run(() => {
-    situation = $testCases[testCaseIndex]
+    situation = shared.testCases[testCaseIndex]
   })
   let valuesByCalculationNameByVariableName
   run(() => {
     valuesByCalculationNameByVariableName =
-      $valuesByCalculationNameByVariableNameArray[testCaseIndex]
+      shared.valuesByCalculationNameByVariableNameArray[testCaseIndex]
   })
   run(() => {
     updateInputInstantsByVariableName(inputInstantsByVariableName)
@@ -122,20 +105,22 @@
     <button
       class="ml-5 mt-5 inline-flex cursor-pointer items-center rounded bg-gray-200 p-2 pr-3 text-sm text-black shadow-md hover:bg-gray-300 active:bg-gray-400 md:ml-10"
       onclick={() =>
-        goto($displayMode === undefined ? "/" : newSimulationUrl($displayMode))}
+        goto(
+          shared.displayMode === undefined
+            ? "/"
+            : newSimulationUrl(shared.displayMode),
+        )}
     >
       <iconify-icon class="text-2xl" icon="ri-arrow-left-line"></iconify-icon>
       <span class="ml-3">Retour au simulateur</span>
     </button>
     <VariableView
-      date={$date}
       editable
       bind:inputInstantsByVariableName
       bind:situation
       situationIndex={testCaseIndex}
       bind:valuesByCalculationNameByVariableName
       {variable}
-      year={$year}
     />
   </div>
 </main>
diff --git a/src/routes/variables/[variable]/inputs/[date]/+page.svelte b/src/routes/variables/[variable]/inputs/[date]/+page.svelte
index 531801b710417017b5a8f447e5047c21e533afd4..3544b8f8ff42503d87f4919267f14a6bb7832935 100644
--- a/src/routes/variables/[variable]/inputs/[date]/+page.svelte
+++ b/src/routes/variables/[variable]/inputs/[date]/+page.svelte
@@ -1,17 +1,16 @@
 <script lang="ts">
   import { run } from "svelte/legacy"
 
-  import { getContext, setContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { setContext } from "svelte"
 
   import type { PageData } from "./$types"
 
   import { page } from "$app/stores"
   import VariableReferredInputs from "$lib/components/variables/VariableReferredInputs.svelte"
+  import publicConfig from "$lib/public_config"
   import type { Situation } from "$lib/situations"
+  import { shared, year } from "$lib/shared.svelte"
   import { newSelfTargetAProps } from "$lib/urls"
-  import type { ValuesByCalculationNameByVariableName } from "$lib/variables"
-  import publicConfig from "$lib/public_config"
 
   interface Props {
     data: PageData
@@ -20,20 +19,6 @@
   const { appTitle } = publicConfig
   let { data }: Props = $props()
 
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [variableName: string]: Set<string>
-    }>
-  >
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const valuesByCalculationNameByVariableNameArray = getContext(
-    "valuesByCalculationNameByVariableNameArray",
-  ) as Writable<ValuesByCalculationNameByVariableName[]>
-  const year = getContext("year") as Writable<number>
-
   setContext("newSelfTargetAProps", newSelfTargetAProps)
 
   function updateInputInstantsByVariableName(inputInstantsByVariableName: {
@@ -41,45 +26,39 @@
   }): void {
     if (
       inputInstantsByVariableName ===
-      $inputInstantsByVariableNameArray[testCaseIndex]
+      shared.inputInstantsByVariableNameArray[testCaseIndex]
     ) {
       return
     }
     const newInputInstantsByVariableNameArray = [
-      ...$inputInstantsByVariableNameArray,
+      ...shared.inputInstantsByVariableNameArray,
     ]
     newInputInstantsByVariableNameArray[testCaseIndex] =
       inputInstantsByVariableName
-    $inputInstantsByVariableNameArray = newInputInstantsByVariableNameArray
+    shared.inputInstantsByVariableNameArray =
+      newInputInstantsByVariableNameArray
   }
 
   function updateSituation(situation: Situation): void {
-    if (situation === $testCases[testCaseIndex]) {
+    if (situation === shared.testCases[testCaseIndex]) {
       return
     }
-    const situations = [...$testCases]
+    const situations = [...shared.testCases]
     situations[testCaseIndex] = situation
-    $testCases = situations
+    shared.testCases = situations
   }
   let { inputs, variable } = $derived(data)
-  let testCaseIndex = $derived($testCasesIndex?.[0] ?? 0)
+  let testCaseIndex = $derived(shared.testCasesIndex?.[0] ?? 0)
   let params = $derived($page.params)
   let date = $derived(params.date)
   let name = $derived(params.variable)
-  let inputInstantsByVariableName
-  run(() => {
-    inputInstantsByVariableName =
-      $inputInstantsByVariableNameArray[testCaseIndex]
-  })
-  let situation
-  run(() => {
-    situation = $testCases[testCaseIndex]
-  })
-  let valuesByCalculationNameByVariableName
-  run(() => {
-    valuesByCalculationNameByVariableName =
-      $valuesByCalculationNameByVariableNameArray[testCaseIndex]
-  })
+  let inputInstantsByVariableName = $derived(
+    shared.inputInstantsByVariableNameArray[testCaseIndex],
+  )
+  let situation = $derived(shared.testCases[testCaseIndex])
+  let valuesByCalculationNameByVariableName = $derived(
+    shared.valuesByCalculationNameByVariableNameArray[testCaseIndex],
+  )
   run(() => {
     updateInputInstantsByVariableName(inputInstantsByVariableName)
   })
@@ -101,6 +80,6 @@
     situationIndex={testCaseIndex}
     bind:valuesByCalculationNameByVariableName
     {variable}
-    year={$year}
+    {year}
   />
 </main>
diff --git a/src/routes/variables/[variable]/parameters/[date]/+page.svelte b/src/routes/variables/[variable]/parameters/[date]/+page.svelte
index 0e21126461669d777d10f270c6fc71ff0daaf1db..59f36b02494347362d8e88565d1a43aedde4e316 100644
--- a/src/routes/variables/[variable]/parameters/[date]/+page.svelte
+++ b/src/routes/variables/[variable]/parameters/[date]/+page.svelte
@@ -1,6 +1,5 @@
 <script lang="ts">
-  import { getContext, setContext } from "svelte"
-  import type { Writable } from "svelte/store"
+  import { setContext } from "svelte"
 
   import { page } from "$app/stores"
   import VariableReferredParameters from "$lib/components/variables/VariableReferredParameters.svelte"
@@ -8,14 +7,14 @@
   import type { DisplayMode } from "$lib/displays"
   import publicConfig from "$lib/public_config"
   import { newSelfTargetAProps } from "$lib/urls"
+  import { shared } from "$lib/shared.svelte"
 
   const { appTitle } = publicConfig
   let displayMode: DisplayMode = $derived({
-    testCasesIndex: $testCasesIndex ?? [0],
+    testCasesIndex: shared.testCasesIndex ?? [0],
     variableName: name,
     waterfallName: waterfalls[0].name,
   })
-  const testCasesIndex = getContext("testCasesIndex") as Writable<number[]>
 
   setContext("newSelfTargetAProps", newSelfTargetAProps)
 
diff --git a/src/routes/variables/[variable]/xlsx/+page.svelte b/src/routes/variables/[variable]/xlsx/+page.svelte
index ce22a6925dd79f5f19ac3d44531a60f35ad5343e..6b3cb48160c7754ad125aea9097e5ebd7ecfb2e4 100644
--- a/src/routes/variables/[variable]/xlsx/+page.svelte
+++ b/src/routes/variables/[variable]/xlsx/+page.svelte
@@ -14,8 +14,6 @@
     type RoleBase,
     type Variable,
   } from "@openfisca/json-model"
-  import { getContext } from "svelte"
-  import type { Writable } from "svelte/store"
   import { v4 as uuidV4 } from "uuid"
   import XLSX from "xlsx-js-style"
 
@@ -26,10 +24,10 @@
   import { entityByKey, personEntityKey } from "$lib/entities"
   import { rootParameter } from "$lib/parameters"
   import publicConfig from "$lib/public_config"
+  import { shared, year } from "$lib/shared.svelte"
   import {
     getPopulationReservedKeys,
     // type Axis,
-    type Situation,
     type SituationWithAxes,
   } from "$lib/situations"
   import {
@@ -44,6 +42,7 @@
   }
 
   const { apiBaseUrls } = publicConfig
+
   let { data }: Props = $props()
 
   type ValuesByCalculationNameByPeriodByVariableName = {
@@ -53,23 +52,14 @@
   }
 
   // const axes = getContext("axes") as Writable<Axis[][]>
-  const inputInstantsByVariableNameArray = getContext(
-    "inputInstantsByVariableNameArray",
-  ) as Writable<
-    Array<{
-      [name: string]: Set<string>
-    }>
-  >
-  const testCases = getContext("testCases") as Writable<Situation[]>
-  const year = getContext("year") as Writable<number>
 
   async function calculate(variables: Variable[]) {
     const aggregatedSituation: SituationWithAxes = {}
     const entities = Object.values(entityByKey)
     // Aggregate every situations into a single one without calculated variables.
-    for (const [situationIndex, situation] of $testCases.entries()) {
+    for (const [situationIndex, situation] of shared.testCases.entries()) {
       const inputInstantsByVariableName =
-        $inputInstantsByVariableNameArray[situationIndex]
+        shared.inputInstantsByVariableNameArray[situationIndex]
       const situationPrefix = `Cas type n°${situationIndex + 1} | `
       for (const entity of entities) {
         let entitySituation = situation[entity.key_plural as string]
@@ -134,8 +124,8 @@
       }
     }
 
-    // if ($axes.length > 0) {
-    //   aggregatedSituation.axes = $axes
+    // if (axes.length > 0) {
+    //   aggregatedSituation.axes = axes
     // }
 
     // Note: crypto.randomUUID() is not supported by Safari before version 15.4.
@@ -146,7 +136,7 @@
     const apiBaseUrl = apiBaseUrls[apiBaseUrlIndex]
     const response = await fetch(new URL("simulations", apiBaseUrl), {
       body: JSON.stringify({
-        period: $year.toString(),
+        period: year.toString(),
         situation: aggregatedSituation,
         title: "law",
         token,
@@ -219,7 +209,7 @@
         "Tableur créé automatiquement par le simulateur socio-fiscal Leximpact, utilisant le moteur libre OpenFisca",
       Company: "Assemblée nationale",
       CreatedDate: new Date(),
-      Title: `${lastVariable.short_label ?? lastVariable.name} en ${$year}`,
+      Title: `${lastVariable.short_label ?? lastVariable.name} en ${year}`,
     }
     workbook.Workbook = {
       Names: [],
@@ -253,7 +243,7 @@
     } = {}
     const rowIndexByEntityKey: { [entityKey: string]: number } = {}
     const tableByEntityKey: { [key: string]: Array<Array<unknown>> } = {} // Array of rows
-    for (const [situationIndex, situation] of $testCases.entries()) {
+    for (const [situationIndex, situation] of shared.testCases.entries()) {
       const groupInfosByIdByEntityKey: {
         [entityKey: string]: {
           [groupId: string]: { groupIndex: number; personsId: string[] }
@@ -361,7 +351,7 @@
           }
         }
         table = tableByEntityKey[entityKey] = [header]
-        for (const [situationIndex, situation] of $testCases.entries()) {
+        for (const [situationIndex, situation] of shared.testCases.entries()) {
           let entitySituation = situation[entity.key_plural as string]
           if (entitySituation === undefined) {
             continue
@@ -615,7 +605,7 @@
 
     XLSX.writeFile(
       workbook,
-      `leximpact_${requestedVariableName}_${$year}.xlsx`,
+      `leximpact_${requestedVariableName}_${year}.xlsx`,
       { compression: true },
     )
   }