diff --git a/src/app/ui/Layout.svelte b/src/app/ui/Layout.svelte
index 920662e..1764df0 100644
--- a/src/app/ui/Layout.svelte
+++ b/src/app/ui/Layout.svelte
@@ -24,6 +24,8 @@ let { children } = $props();
+
+
diff --git a/src/entities/Font/model/store/appliedFontsStore/appliedFontsStore.svelte.ts b/src/entities/Font/model/store/appliedFontsStore/appliedFontsStore.svelte.ts
new file mode 100644
index 0000000..6e8fa63
--- /dev/null
+++ b/src/entities/Font/model/store/appliedFontsStore/appliedFontsStore.svelte.ts
@@ -0,0 +1,143 @@
+import { SvelteMap } from 'svelte/reactivity';
+
+export type FontStatus = 'loading' | 'loaded' | 'error';
+
+class AppliedFontsManager {
+ // Stores: slug -> timestamp of last visibility
+ #usageTracker = new Map();
+ // Stores: slug -> batchId
+ #slugToBatch = new Map();
+ // Stores: batchId -> HTMLLinkElement (for physical cleanup)
+ #batchElements = new Map();
+
+ #queue = new Set();
+ #timeoutId: ReturnType | null = null;
+ #PURGE_INTERVAL = 60000; // Check every minute
+ #TTL = 5 * 60 * 1000; // 5 minutes
+ #CHUNK_SIZE = 3;
+
+ statuses = new SvelteMap();
+
+ constructor() {
+ if (typeof window !== 'undefined') {
+ // Start the "Janitor" loop
+ setInterval(() => this.#purgeUnused(), this.#PURGE_INTERVAL);
+ }
+ }
+
+ /**
+ * Updates the 'last seen' timestamp for fonts.
+ * Prevents them from being purged while they are on screen.
+ */
+ touch(slugs: string[]) {
+ const now = Date.now();
+ const toRegister: string[] = [];
+
+ slugs.forEach(slug => {
+ this.#usageTracker.set(slug, now);
+ if (!this.#slugToBatch.has(slug)) {
+ toRegister.push(slug);
+ }
+ });
+
+ if (toRegister.length > 0) this.registerFonts(toRegister);
+ }
+
+ registerFonts(slugs: string[]) {
+ const newSlugs = slugs.filter(s => !this.#slugToBatch.has(s) && !this.#queue.has(s));
+ if (newSlugs.length === 0) return;
+
+ newSlugs.forEach(s => this.#queue.add(s));
+
+ if (this.#timeoutId) clearTimeout(this.#timeoutId);
+ this.#timeoutId = setTimeout(() => this.#processQueue(), 50);
+ }
+
+ getFontStatus(slug: string) {
+ return this.statuses.get(slug);
+ }
+
+ #processQueue() {
+ const fullQueue = Array.from(this.#queue);
+ if (fullQueue.length === 0) return;
+
+ for (let i = 0; i < fullQueue.length; i += this.#CHUNK_SIZE) {
+ this.#createBatch(fullQueue.slice(i, i + this.#CHUNK_SIZE));
+ }
+
+ this.#queue.clear();
+ this.#timeoutId = null;
+ }
+
+ #createBatch(slugs: string[]) {
+ if (typeof document === 'undefined') return;
+
+ const batchId = crypto.randomUUID();
+ // font-display=swap included for better UX
+ const query = slugs.map(s => `f[]=${s.toLowerCase()}@400`).join('&');
+ const url = `https://api.fontshare.com/v2/css?${query}&display=swap`;
+
+ // Mark all as loading immediately
+ slugs.forEach(slug => this.statuses.set(slug, 'loading'));
+
+ const link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.href = url;
+ link.dataset.batchId = batchId;
+ document.head.appendChild(link);
+
+ this.#batchElements.set(batchId, link);
+ slugs.forEach(slug => {
+ this.#slugToBatch.set(slug, batchId);
+
+ // Use the Native Font Loading API
+ // format: "font-size font-family"
+ document.fonts.load(`1em "${slug}"`)
+ .then(loadedFonts => {
+ if (loadedFonts.length > 0) {
+ this.statuses.set(slug, 'loaded');
+ } else {
+ this.statuses.set(slug, 'error');
+ }
+ })
+ .catch(() => {
+ this.statuses.set(slug, 'error');
+ });
+ });
+ }
+
+ #purgeUnused() {
+ const now = Date.now();
+ const batchesToPotentialDelete = new Set();
+ const slugsToDelete: string[] = [];
+
+ // Identify expired slugs
+ for (const [slug, lastUsed] of this.#usageTracker.entries()) {
+ if (now - lastUsed > this.#TTL) {
+ const batchId = this.#slugToBatch.get(slug);
+ if (batchId) batchesToPotentialDelete.add(batchId);
+ slugsToDelete.push(slug);
+ }
+ }
+
+ // Only remove a batch if ALL fonts in that batch are expired
+ batchesToPotentialDelete.forEach(batchId => {
+ const batchSlugs = Array.from(this.#slugToBatch.entries())
+ .filter(([_, bId]) => bId === batchId)
+ .map(([slug]) => slug);
+
+ const allExpired = batchSlugs.every(s => slugsToDelete.includes(s));
+
+ if (allExpired) {
+ this.#batchElements.get(batchId)?.remove();
+ this.#batchElements.delete(batchId);
+ batchSlugs.forEach(s => {
+ this.#slugToBatch.delete(s);
+ this.#usageTracker.delete(s);
+ });
+ }
+ });
+ }
+}
+
+export const appliedFontsManager = new AppliedFontsManager();