Index: .dockerignore
===================================================================
--- .dockerignore	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ .dockerignore	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,14 @@
+**/.vs
+**/.vscode
+**/bin
+**/obj
+**/.git
+**/.gitignore
+**/.dockerignore
+**/Dockerfile
+**/docker-compose.*
+**/*.md
+**/charts
+**/secrets.*.yaml
+**/.env
+**/appsettings.Development.json
Index: .gitattributes
===================================================================
--- .gitattributes	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ .gitattributes	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain
Index: .gitignore
===================================================================
--- .gitignore	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ .gitignore	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -1,41 +1,365 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.*
-.yarn/*
-!.yarn/patches
-!.yarn/plugins
-!.yarn/releases
-!.yarn/versions
-
-# testing
-/coverage
-
-# next.js
-/.next/
-/out/
-
-# production
-/build
-
-# misc
-.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-.pnpm-debug.log*
-
-# env files (can opt-in for committing if needed)
-.env*
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
-next-env.d.ts
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+# Local DB credentials (see appsettings.Development.json.example)
+appsettings.Development.json
Index: Dockerfile
===================================================================
--- Dockerfile	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ Dockerfile	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,27 @@
+# Use the official .NET SDK image for building
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
+WORKDIR /src
+
+# Copy csproj and restore dependencies
+COPY ["iknow-api/iknow-api.csproj", "iknow-api/"]
+RUN dotnet restore "iknow-api/iknow-api.csproj"
+
+# Copy the rest of the files and build
+COPY . .
+WORKDIR "/src/iknow-api"
+RUN dotnet build "iknow-api.csproj" -c Release -o /app/build
+
+# Publish the application
+FROM build AS publish
+RUN dotnet publish "iknow-api.csproj" -c Release -o /app/publish /p:UseAppHost=false
+
+# Use the runtime image for the final stage
+FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
+WORKDIR /app
+EXPOSE 8080
+COPY --from=publish /app/publish .
+
+# Set environment variables
+ENV ASPNETCORE_URLS=http://+:8080
+
+ENTRYPOINT ["dotnet", "iknow-api.dll"]
Index: ADME.md
===================================================================
--- README.md	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,36 +1,0 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
-
-## Getting Started
-
-First, run the development server:
-
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
-```
-
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
-
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
-
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
-
-## Learn More
-
-To learn more about Next.js, take a look at the following resources:
-
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
-
-## Deploy on Vercel
-
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
-
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Index: mponents.json
===================================================================
--- components.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,22 +1,0 @@
-{
-  "$schema": "https://ui.shadcn.com/schema.json",
-  "style": "new-york",
-  "rsc": true,
-  "tsx": true,
-  "tailwind": {
-    "config": "",
-    "css": "src/app/globals.css",
-    "baseColor": "neutral",
-    "cssVariables": true,
-    "prefix": ""
-  },
-  "iconLibrary": "lucide",
-  "aliases": {
-    "components": "@/components",
-    "utils": "@/lib/utils",
-    "ui": "@/components/ui",
-    "lib": "@/lib",
-    "hooks": "@/hooks"
-  },
-  "registries": {}
-}
Index: lint.config.mjs
===================================================================
--- eslint.config.mjs	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,25 +1,0 @@
-import { dirname } from "path";
-import { fileURLToPath } from "url";
-import { FlatCompat } from "@eslint/eslintrc";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
-
-const compat = new FlatCompat({
-  baseDirectory: __dirname,
-});
-
-const eslintConfig = [
-  ...compat.extends("next/core-web-vitals", "next/typescript"),
-  {
-    ignores: [
-      "node_modules/**",
-      ".next/**",
-      "out/**",
-      "build/**",
-      "next-env.d.ts",
-    ],
-  },
-];
-
-export default eslintConfig;
Index: frontend/.gitignore
===================================================================
--- frontend/.gitignore	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/.gitignore	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,41 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/versions
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# env files (can opt-in for committing if needed)
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
Index: frontend/README.md
===================================================================
--- frontend/README.md	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/README.md	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Index: frontend/components.json
===================================================================
--- frontend/components.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/components.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,22 @@
+{
+  "$schema": "https://ui.shadcn.com/schema.json",
+  "style": "new-york",
+  "rsc": true,
+  "tsx": true,
+  "tailwind": {
+    "config": "",
+    "css": "src/app/globals.css",
+    "baseColor": "neutral",
+    "cssVariables": true,
+    "prefix": ""
+  },
+  "iconLibrary": "lucide",
+  "aliases": {
+    "components": "@/components",
+    "utils": "@/lib/utils",
+    "ui": "@/components/ui",
+    "lib": "@/lib",
+    "hooks": "@/hooks"
+  },
+  "registries": {}
+}
Index: frontend/eslint.config.mjs
===================================================================
--- frontend/eslint.config.mjs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/eslint.config.mjs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,25 @@
+import { dirname } from "path";
+import { fileURLToPath } from "url";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const compat = new FlatCompat({
+  baseDirectory: __dirname,
+});
+
+const eslintConfig = [
+  ...compat.extends("next/core-web-vitals", "next/typescript"),
+  {
+    ignores: [
+      "node_modules/**",
+      ".next/**",
+      "out/**",
+      "build/**",
+      "next-env.d.ts",
+    ],
+  },
+];
+
+export default eslintConfig;
Index: frontend/next.config.ts
===================================================================
--- frontend/next.config.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/next.config.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,7 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+  /* config options here */
+};
+
+export default nextConfig;
Index: frontend/package-lock.json
===================================================================
--- frontend/package-lock.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/package-lock.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,7383 @@
+{
+  "name": "iknow-remaster",
+  "version": "0.1.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "iknow-remaster",
+      "version": "0.1.0",
+      "dependencies": {
+        "@fortawesome/fontawesome-svg-core": "^7.0.1",
+        "@fortawesome/free-brands-svg-icons": "^7.0.1",
+        "@fortawesome/free-regular-svg-icons": "^7.0.1",
+        "@fortawesome/free-solid-svg-icons": "^7.0.1",
+        "@fortawesome/react-fontawesome": "^3.0.2",
+        "class-variance-authority": "^0.7.1",
+        "clsx": "^2.1.1",
+        "i18next": "^25.8.0",
+        "jspdf": "^4.1.0",
+        "jspdf-autotable": "^5.0.7",
+        "lucide-react": "^0.544.0",
+        "next": "^16.1.6",
+        "next-intl": "^4.8.0",
+        "next-themes": "^0.4.6",
+        "react": "^19.2.4",
+        "react-dom": "^19.2.4",
+        "react-i18next": "^16.5.4",
+        "tailwind-merge": "^3.3.1"
+      },
+      "devDependencies": {
+        "@eslint/eslintrc": "^3",
+        "@tailwindcss/postcss": "^4",
+        "@types/node": "^20",
+        "@types/react": "^19",
+        "@types/react-dom": "^19",
+        "autoprefixer": "^10.4.21",
+        "eslint": "^9",
+        "eslint-config-next": "15.5.4",
+        "postcss": "^8.5.6",
+        "tailwindcss": "^4.1.13",
+        "tw-animate-css": "^1.4.0",
+        "typescript": "^5"
+      }
+    },
+    "node_modules/@alloc/quick-lru": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+      "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
+      "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@emnapi/core": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz",
+      "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/wasi-threads": "1.1.0",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/runtime": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
+      "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/wasi-threads": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
+      "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+      "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.12.2",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+      "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/config-array": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
+      "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.7",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/config-helpers": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+      "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/core": "^0.17.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+      "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/json-schema": "^7.0.15"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
+      "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.1",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "9.39.2",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
+      "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+      "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+      "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/core": "^0.17.0",
+        "levn": "^0.4.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@formatjs/ecma402-abstract": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-3.1.0.tgz",
+      "integrity": "sha512-CjP1sUzM7XiQW6YluDreN+dMvcKZysO/J4ikvuDjDyd6nSOoSqAK9gvD1s75ZFaJVXtYOsz+y3CUXPZ1sKxcxw==",
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/fast-memoize": "3.1.0",
+        "@formatjs/intl-localematcher": "0.8.0",
+        "decimal.js": "^10.6.0",
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.0.tgz",
+      "integrity": "sha512-zgMYWdUlmEZpX2Io+v3LHrfq9xZ6khpQVf9UAw2xYWhGerGgI9XgH1HvL/A34jWiruUJpYlP5pk4g8nIcaDrXQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/fast-memoize": "3.1.0",
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/@formatjs/fast-memoize": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.0.tgz",
+      "integrity": "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/@formatjs/icu-messageformat-parser": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.0.tgz",
+      "integrity": "sha512-Q01XuvtbDVCJQsG/E2MSfMZ+UdUoZV8v4Aex8tTH44SqKJZCeu5LjuclaKFUS0o1YoXndfEinJen5k1T1GR1vg==",
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/ecma402-abstract": "3.1.0",
+        "@formatjs/icu-skeleton-parser": "2.1.0",
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/@formatjs/icu-skeleton-parser": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.0.tgz",
+      "integrity": "sha512-wNer4imHDFBVAJnMb2OGoSyM4wL/uuLnuo5mrenliqkDaNjRbG4jzlJcwTTDEBhai8iCjnzUsE7xwNJC29SfWw==",
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/ecma402-abstract": "3.1.0",
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/@formatjs/intl-localematcher": {
+      "version": "0.5.10",
+      "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz",
+      "integrity": "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "2"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-common-types": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.1.0.tgz",
+      "integrity": "sha512-l/BQM7fYntsCI//du+6sEnHOP6a74UixFyOYUyz2DLMXKx+6DEhfR3F2NYGE45XH1JJuIamacb4IZs9S0ZOWLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-svg-core": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz",
+      "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "7.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/free-brands-svg-icons": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-7.1.0.tgz",
+      "integrity": "sha512-9byUd9bgNfthsZAjBl6GxOu1VPHgBuRUP9juI7ZoM98h8xNPTCTagfwUFyYscdZq4Hr7gD1azMfM9s5tIWKZZA==",
+      "license": "(CC-BY-4.0 AND MIT)",
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "7.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/free-regular-svg-icons": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-7.1.0.tgz",
+      "integrity": "sha512-0e2fdEyB4AR+e6kU4yxwA/MonnYcw/CsMEP9lH82ORFi9svA6/RhDyhxIv5mlJaldmaHLLYVTb+3iEr+PDSZuQ==",
+      "license": "(CC-BY-4.0 AND MIT)",
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "7.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/free-solid-svg-icons": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.1.0.tgz",
+      "integrity": "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA==",
+      "license": "(CC-BY-4.0 AND MIT)",
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "7.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/react-fontawesome": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-3.1.1.tgz",
+      "integrity": "sha512-EDllr9hpodc21odmUywHS1alXNiCd4E8sp5GJ5s7wYINz8vSmMiNWpALTiuYODb865YyQ/NlyiN4mbXp7HCNqg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=20"
+      },
+      "peerDependencies": {
+        "@fortawesome/fontawesome-svg-core": "~6 || ~7",
+        "react": "^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.7",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+      "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.4.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+      "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@img/colour": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
+      "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@img/sharp-darwin-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+      "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-darwin-arm64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-darwin-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+      "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-darwin-x64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-libvips-darwin-arm64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+      "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-darwin-x64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+      "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-arm": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+      "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-arm64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+      "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-ppc64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+      "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-riscv64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+      "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-s390x": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+      "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linux-x64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+      "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+      "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+      "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-linux-arm": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+      "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-arm": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+      "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-arm64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-ppc64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+      "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-ppc64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-riscv64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+      "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-riscv64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-s390x": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+      "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-s390x": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linux-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+      "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linux-x64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linuxmusl-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+      "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-linuxmusl-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+      "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+      }
+    },
+    "node_modules/@img/sharp-wasm32": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+      "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+      "cpu": [
+        "wasm32"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/runtime": "^1.7.0"
+      },
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-win32-arm64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+      "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-win32-ia32": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+      "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@img/sharp-win32-x64": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+      "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND LGPL-3.0-or-later",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@napi-rs/wasm-runtime": {
+      "version": "0.2.12",
+      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+      "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/core": "^1.4.3",
+        "@emnapi/runtime": "^1.4.3",
+        "@tybys/wasm-util": "^0.10.0"
+      }
+    },
+    "node_modules/@next/env": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
+      "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
+      "license": "MIT"
+    },
+    "node_modules/@next/eslint-plugin-next": {
+      "version": "15.5.4",
+      "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.4.tgz",
+      "integrity": "sha512-SR1vhXNNg16T4zffhJ4TS7Xn7eq4NfKfcOsRwea7RIAHrjRpI9ALYbamqIJqkAhowLlERffiwk0FMvTLNdnVtw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-glob": "3.3.1"
+      }
+    },
+    "node_modules/@next/swc-darwin-arm64": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
+      "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-darwin-x64": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
+      "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-gnu": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
+      "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-musl": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
+      "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-gnu": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
+      "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-musl": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
+      "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-arm64-msvc": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
+      "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-x64-msvc": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
+      "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nolyfill/is-core-module": {
+      "version": "1.0.39",
+      "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
+      "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.4.0"
+      }
+    },
+    "node_modules/@parcel/watcher": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
+      "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "detect-libc": "^2.0.3",
+        "is-glob": "^4.0.3",
+        "node-addon-api": "^7.0.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher-android-arm64": "2.5.6",
+        "@parcel/watcher-darwin-arm64": "2.5.6",
+        "@parcel/watcher-darwin-x64": "2.5.6",
+        "@parcel/watcher-freebsd-x64": "2.5.6",
+        "@parcel/watcher-linux-arm-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm-musl": "2.5.6",
+        "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm64-musl": "2.5.6",
+        "@parcel/watcher-linux-x64-glibc": "2.5.6",
+        "@parcel/watcher-linux-x64-musl": "2.5.6",
+        "@parcel/watcher-win32-arm64": "2.5.6",
+        "@parcel/watcher-win32-ia32": "2.5.6",
+        "@parcel/watcher-win32-x64": "2.5.6"
+      }
+    },
+    "node_modules/@parcel/watcher-android-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+      "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+      "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+      "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-freebsd-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+      "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+      "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+      "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+      "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+      "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+      "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+      "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+      "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-ia32": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+      "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+      "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher/node_modules/picomatch": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/@rtsao/scc": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+      "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@rushstack/eslint-patch": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz",
+      "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@schummar/icu-type-parser": {
+      "version": "1.21.5",
+      "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz",
+      "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==",
+      "license": "MIT"
+    },
+    "node_modules/@swc/core-darwin-arm64": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.11.tgz",
+      "integrity": "sha512-QoIupRWVH8AF1TgxYyeA5nS18dtqMuxNwchjBIwJo3RdwLEFiJq6onOx9JAxHtuPwUkIVuU2Xbp+jCJ7Vzmgtg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-darwin-x64": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.11.tgz",
+      "integrity": "sha512-S52Gu1QtPSfBYDiejlcfp9GlN+NjTZBRRNsz8PNwBgSE626/FUf2PcllVUix7jqkoMC+t0rS8t+2/aSWlMuQtA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm-gnueabihf": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.11.tgz",
+      "integrity": "sha512-lXJs8oXo6Z4yCpimpQ8vPeCjkgoHu5NoMvmJZ8qxDyU99KVdg6KwU9H79vzrmB+HfH+dCZ7JGMqMF//f8Cfvdg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-gnu": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.11.tgz",
+      "integrity": "sha512-chRsz1K52/vj8Mfq/QOugVphlKPWlMh10V99qfH41hbGvwAU6xSPd681upO4bKiOr9+mRIZZW+EfJqY42ZzRyA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-musl": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.11.tgz",
+      "integrity": "sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-gnu": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.11.tgz",
+      "integrity": "sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-musl": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.11.tgz",
+      "integrity": "sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-arm64-msvc": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.11.tgz",
+      "integrity": "sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-ia32-msvc": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.11.tgz",
+      "integrity": "sha512-6XnzORkZCQzvTQ6cPrU7iaT9+i145oLwnin8JrfsLG41wl26+5cNQ2XV3zcbrnFEV6esjOceom9YO1w9mGJByw==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-x64-msvc": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.11.tgz",
+      "integrity": "sha512-IQ2n6af7XKLL6P1gIeZACskSxK8jWtoKpJWLZmdXTDj1MGzktUy4i+FvpdtxFmJWNavRWH1VmTr6kAubRDHeKw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/counter": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+      "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@swc/helpers": {
+      "version": "0.5.15",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+      "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.8.0"
+      }
+    },
+    "node_modules/@swc/types": {
+      "version": "0.1.25",
+      "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz",
+      "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@swc/counter": "^0.1.3"
+      }
+    },
+    "node_modules/@tailwindcss/node": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
+      "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/remapping": "^2.3.4",
+        "enhanced-resolve": "^5.18.3",
+        "jiti": "^2.6.1",
+        "lightningcss": "1.30.2",
+        "magic-string": "^0.30.21",
+        "source-map-js": "^1.2.1",
+        "tailwindcss": "4.1.18"
+      }
+    },
+    "node_modules/@tailwindcss/oxide": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz",
+      "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10"
+      },
+      "optionalDependencies": {
+        "@tailwindcss/oxide-android-arm64": "4.1.18",
+        "@tailwindcss/oxide-darwin-arm64": "4.1.18",
+        "@tailwindcss/oxide-darwin-x64": "4.1.18",
+        "@tailwindcss/oxide-freebsd-x64": "4.1.18",
+        "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18",
+        "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18",
+        "@tailwindcss/oxide-linux-arm64-musl": "4.1.18",
+        "@tailwindcss/oxide-linux-x64-gnu": "4.1.18",
+        "@tailwindcss/oxide-linux-x64-musl": "4.1.18",
+        "@tailwindcss/oxide-wasm32-wasi": "4.1.18",
+        "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18",
+        "@tailwindcss/oxide-win32-x64-msvc": "4.1.18"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-android-arm64": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz",
+      "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-darwin-arm64": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz",
+      "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-darwin-x64": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz",
+      "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-freebsd-x64": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz",
+      "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz",
+      "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz",
+      "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz",
+      "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz",
+      "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz",
+      "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz",
+      "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==",
+      "bundleDependencies": [
+        "@napi-rs/wasm-runtime",
+        "@emnapi/core",
+        "@emnapi/runtime",
+        "@tybys/wasm-util",
+        "@emnapi/wasi-threads",
+        "tslib"
+      ],
+      "cpu": [
+        "wasm32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/core": "^1.7.1",
+        "@emnapi/runtime": "^1.7.1",
+        "@emnapi/wasi-threads": "^1.1.0",
+        "@napi-rs/wasm-runtime": "^1.1.0",
+        "@tybys/wasm-util": "^0.10.1",
+        "tslib": "^2.4.0"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
+      "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz",
+      "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@tailwindcss/postcss": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz",
+      "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@alloc/quick-lru": "^5.2.0",
+        "@tailwindcss/node": "4.1.18",
+        "@tailwindcss/oxide": "4.1.18",
+        "postcss": "^8.4.41",
+        "tailwindcss": "4.1.18"
+      }
+    },
+    "node_modules/@tybys/wasm-util": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+      "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/json5": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "20.19.30",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz",
+      "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.21.0"
+      }
+    },
+    "node_modules/@types/pako": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
+      "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
+      "license": "MIT"
+    },
+    "node_modules/@types/raf": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
+      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@types/react": {
+      "version": "19.2.10",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz",
+      "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "csstype": "^3.2.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "19.2.3",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+      "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "^19.2.0"
+      }
+    },
+    "node_modules/@types/trusted-types": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+      "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
+      "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.12.2",
+        "@typescript-eslint/scope-manager": "8.54.0",
+        "@typescript-eslint/type-utils": "8.54.0",
+        "@typescript-eslint/utils": "8.54.0",
+        "@typescript-eslint/visitor-keys": "8.54.0",
+        "ignore": "^7.0.5",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^2.4.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^8.54.0",
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
+      "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "8.54.0",
+        "@typescript-eslint/types": "8.54.0",
+        "@typescript-eslint/typescript-estree": "8.54.0",
+        "@typescript-eslint/visitor-keys": "8.54.0",
+        "debug": "^4.4.3"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/project-service": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
+      "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/tsconfig-utils": "^8.54.0",
+        "@typescript-eslint/types": "^8.54.0",
+        "debug": "^4.4.3"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
+      "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.54.0",
+        "@typescript-eslint/visitor-keys": "8.54.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/tsconfig-utils": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
+      "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
+      "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.54.0",
+        "@typescript-eslint/typescript-estree": "8.54.0",
+        "@typescript-eslint/utils": "8.54.0",
+        "debug": "^4.4.3",
+        "ts-api-utils": "^2.4.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
+      "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
+      "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/project-service": "8.54.0",
+        "@typescript-eslint/tsconfig-utils": "8.54.0",
+        "@typescript-eslint/types": "8.54.0",
+        "@typescript-eslint/visitor-keys": "8.54.0",
+        "debug": "^4.4.3",
+        "minimatch": "^9.0.5",
+        "semver": "^7.7.3",
+        "tinyglobby": "^0.2.15",
+        "ts-api-utils": "^2.4.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
+      "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.9.1",
+        "@typescript-eslint/scope-manager": "8.54.0",
+        "@typescript-eslint/types": "8.54.0",
+        "@typescript-eslint/typescript-estree": "8.54.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "8.54.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
+      "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.54.0",
+        "eslint-visitor-keys": "^4.2.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@unrs/resolver-binding-android-arm-eabi": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
+      "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-android-arm64": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
+      "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-darwin-arm64": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
+      "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-darwin-x64": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
+      "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-freebsd-x64": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
+      "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
+      "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
+      "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
+      "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
+      "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
+      "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
+      "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
+      "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
+      "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
+      "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-linux-x64-musl": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
+      "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-wasm32-wasi": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
+      "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
+      "cpu": [
+        "wasm32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@napi-rs/wasm-runtime": "^0.2.11"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
+      "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
+      "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
+      "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/acorn": {
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true,
+      "license": "Python-2.0"
+    },
+    "node_modules/aria-query": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+      "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+      "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "is-array-buffer": "^3.0.5"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array-includes": {
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+      "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.24.0",
+        "es-object-atoms": "^1.1.1",
+        "get-intrinsic": "^1.3.0",
+        "is-string": "^1.1.1",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.findlast": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+      "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.findlastindex": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+      "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.9",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "es-shim-unscopables": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.flat": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+      "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.flatmap": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+      "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.tosorted": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+      "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.3",
+        "es-errors": "^1.3.0",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/arraybuffer.prototype.slice": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+      "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.1",
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "is-array-buffer": "^3.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/ast-types-flow": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
+      "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/async-function": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+      "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.4.23",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz",
+      "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "browserslist": "^4.28.1",
+        "caniuse-lite": "^1.0.30001760",
+        "fraction.js": "^5.3.4",
+        "picocolors": "^1.1.1",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "possible-typed-array-names": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/axe-core": {
+      "version": "4.11.1",
+      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz",
+      "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==",
+      "dev": true,
+      "license": "MPL-2.0",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/axobject-query": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+      "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/base64-arraybuffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.9.19",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
+      "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.js"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.28.1",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
+      "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "baseline-browser-mapping": "^2.9.0",
+        "caniuse-lite": "^1.0.30001759",
+        "electron-to-chromium": "^1.5.263",
+        "node-releases": "^2.0.27",
+        "update-browserslist-db": "^1.2.0"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.0",
+        "es-define-property": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "get-intrinsic": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001766",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
+      "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/canvg": {
+      "version": "3.0.11",
+      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
+      "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@babel/runtime": "^7.12.5",
+        "@types/raf": "^3.4.0",
+        "core-js": "^3.8.3",
+        "raf": "^3.4.1",
+        "regenerator-runtime": "^0.13.7",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^2.0.0",
+        "svg-pathdata": "^6.0.3"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/class-variance-authority": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+      "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "clsx": "^2.1.1"
+      },
+      "funding": {
+        "url": "https://polar.sh/cva"
+      }
+    },
+    "node_modules/client-only": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+      "license": "MIT"
+    },
+    "node_modules/clsx": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+      "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/core-js": {
+      "version": "3.48.0",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz",
+      "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/css-line-break": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/damerau-levenshtein": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
+      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/data-view-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+      "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-length": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+      "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/inspect-js"
+      }
+    },
+    "node_modules/data-view-byte-offset": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+      "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decimal.js": {
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+      "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+      "license": "MIT"
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/dompurify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
+      "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
+      "license": "(MPL-2.0 OR Apache-2.0)",
+      "optional": true,
+      "optionalDependencies": {
+        "@types/trusted-types": "^2.0.7"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.282",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.282.tgz",
+      "integrity": "sha512-FCPkJtpst28UmFzd903iU7PdeVTfY0KAeJy+Lk0GLZRwgwYHn/irRcaCbQQOmr5Vytc/7rcavsYLvTM8RiHYhQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/enhanced-resolve": {
+      "version": "5.18.4",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
+      "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/es-abstract": {
+      "version": "1.24.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
+      "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.2",
+        "arraybuffer.prototype.slice": "^1.0.4",
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "data-view-buffer": "^1.0.2",
+        "data-view-byte-length": "^1.0.2",
+        "data-view-byte-offset": "^1.0.1",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "es-set-tostringtag": "^2.1.0",
+        "es-to-primitive": "^1.3.0",
+        "function.prototype.name": "^1.1.8",
+        "get-intrinsic": "^1.3.0",
+        "get-proto": "^1.0.1",
+        "get-symbol-description": "^1.1.0",
+        "globalthis": "^1.0.4",
+        "gopd": "^1.2.0",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "internal-slot": "^1.1.0",
+        "is-array-buffer": "^3.0.5",
+        "is-callable": "^1.2.7",
+        "is-data-view": "^1.0.2",
+        "is-negative-zero": "^2.0.3",
+        "is-regex": "^1.2.1",
+        "is-set": "^2.0.3",
+        "is-shared-array-buffer": "^1.0.4",
+        "is-string": "^1.1.1",
+        "is-typed-array": "^1.1.15",
+        "is-weakref": "^1.1.1",
+        "math-intrinsics": "^1.1.0",
+        "object-inspect": "^1.13.4",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.7",
+        "own-keys": "^1.0.1",
+        "regexp.prototype.flags": "^1.5.4",
+        "safe-array-concat": "^1.1.3",
+        "safe-push-apply": "^1.0.0",
+        "safe-regex-test": "^1.1.0",
+        "set-proto": "^1.0.0",
+        "stop-iteration-iterator": "^1.1.0",
+        "string.prototype.trim": "^1.2.10",
+        "string.prototype.trimend": "^1.0.9",
+        "string.prototype.trimstart": "^1.0.8",
+        "typed-array-buffer": "^1.0.3",
+        "typed-array-byte-length": "^1.0.3",
+        "typed-array-byte-offset": "^1.0.4",
+        "typed-array-length": "^1.0.7",
+        "unbox-primitive": "^1.1.0",
+        "which-typed-array": "^1.1.19"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-iterator-helpers": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz",
+      "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.24.1",
+        "es-errors": "^1.3.0",
+        "es-set-tostringtag": "^2.1.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.3.0",
+        "globalthis": "^1.0.4",
+        "gopd": "^1.2.0",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "internal-slot": "^1.1.0",
+        "iterator.prototype": "^1.1.5",
+        "safe-array-concat": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-shim-unscopables": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+      "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-to-primitive": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+      "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-callable": "^1.2.7",
+        "is-date-object": "^1.0.5",
+        "is-symbol": "^1.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "9.39.2",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
+      "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.8.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.21.1",
+        "@eslint/config-helpers": "^0.4.2",
+        "@eslint/core": "^0.17.0",
+        "@eslint/eslintrc": "^3.3.1",
+        "@eslint/js": "9.39.2",
+        "@eslint/plugin-kit": "^0.4.1",
+        "@humanfs/node": "^0.16.6",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@humanwhocodes/retry": "^0.4.2",
+        "@types/estree": "^1.0.6",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.6",
+        "debug": "^4.3.2",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^8.4.0",
+        "eslint-visitor-keys": "^4.2.1",
+        "espree": "^10.4.0",
+        "esquery": "^1.5.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^8.0.0",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "ignore": "^5.2.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      },
+      "peerDependencies": {
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-config-next": {
+      "version": "15.5.4",
+      "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.4.tgz",
+      "integrity": "sha512-BzgVVuT3kfJes8i2GHenC1SRJ+W3BTML11lAOYFOOPzrk2xp66jBOAGEFRw+3LkYCln5UzvFsLhojrshb5Zfaw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@next/eslint-plugin-next": "15.5.4",
+        "@rushstack/eslint-patch": "^1.10.3",
+        "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+        "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+        "eslint-import-resolver-node": "^0.3.6",
+        "eslint-import-resolver-typescript": "^3.5.2",
+        "eslint-plugin-import": "^2.31.0",
+        "eslint-plugin-jsx-a11y": "^6.10.0",
+        "eslint-plugin-react": "^7.37.0",
+        "eslint-plugin-react-hooks": "^5.0.0"
+      },
+      "peerDependencies": {
+        "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
+        "typescript": ">=3.3.1"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-import-resolver-node": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+      "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^3.2.7",
+        "is-core-module": "^2.13.0",
+        "resolve": "^1.22.4"
+      }
+    },
+    "node_modules/eslint-import-resolver-node/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/eslint-import-resolver-typescript": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz",
+      "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@nolyfill/is-core-module": "1.0.39",
+        "debug": "^4.4.0",
+        "get-tsconfig": "^4.10.0",
+        "is-bun-module": "^2.0.0",
+        "stable-hash": "^0.0.5",
+        "tinyglobby": "^0.2.13",
+        "unrs-resolver": "^1.6.2"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint-import-resolver-typescript"
+      },
+      "peerDependencies": {
+        "eslint": "*",
+        "eslint-plugin-import": "*",
+        "eslint-plugin-import-x": "*"
+      },
+      "peerDependenciesMeta": {
+        "eslint-plugin-import": {
+          "optional": true
+        },
+        "eslint-plugin-import-x": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-module-utils": {
+      "version": "2.12.1",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
+      "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^3.2.7"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependenciesMeta": {
+        "eslint": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-module-utils/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/eslint-plugin-import": {
+      "version": "2.32.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+      "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@rtsao/scc": "^1.1.0",
+        "array-includes": "^3.1.9",
+        "array.prototype.findlastindex": "^1.2.6",
+        "array.prototype.flat": "^1.3.3",
+        "array.prototype.flatmap": "^1.3.3",
+        "debug": "^3.2.7",
+        "doctrine": "^2.1.0",
+        "eslint-import-resolver-node": "^0.3.9",
+        "eslint-module-utils": "^2.12.1",
+        "hasown": "^2.0.2",
+        "is-core-module": "^2.16.1",
+        "is-glob": "^4.0.3",
+        "minimatch": "^3.1.2",
+        "object.fromentries": "^2.0.8",
+        "object.groupby": "^1.0.3",
+        "object.values": "^1.2.1",
+        "semver": "^6.3.1",
+        "string.prototype.trimend": "^1.0.9",
+        "tsconfig-paths": "^3.15.0"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
+      }
+    },
+    "node_modules/eslint-plugin-import/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/eslint-plugin-import/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/eslint-plugin-jsx-a11y": {
+      "version": "6.10.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz",
+      "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "aria-query": "^5.3.2",
+        "array-includes": "^3.1.8",
+        "array.prototype.flatmap": "^1.3.2",
+        "ast-types-flow": "^0.0.8",
+        "axe-core": "^4.10.0",
+        "axobject-query": "^4.1.0",
+        "damerau-levenshtein": "^1.0.8",
+        "emoji-regex": "^9.2.2",
+        "hasown": "^2.0.2",
+        "jsx-ast-utils": "^3.3.5",
+        "language-tags": "^1.0.9",
+        "minimatch": "^3.1.2",
+        "object.fromentries": "^2.0.8",
+        "safe-regex-test": "^1.0.3",
+        "string.prototype.includes": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependencies": {
+        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
+      }
+    },
+    "node_modules/eslint-plugin-react": {
+      "version": "7.37.5",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+      "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "array-includes": "^3.1.8",
+        "array.prototype.findlast": "^1.2.5",
+        "array.prototype.flatmap": "^1.3.3",
+        "array.prototype.tosorted": "^1.1.4",
+        "doctrine": "^2.1.0",
+        "es-iterator-helpers": "^1.2.1",
+        "estraverse": "^5.3.0",
+        "hasown": "^2.0.2",
+        "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.9",
+        "object.fromentries": "^2.0.8",
+        "object.values": "^1.2.1",
+        "prop-types": "^15.8.1",
+        "resolve": "^2.0.0-next.5",
+        "semver": "^6.3.1",
+        "string.prototype.matchall": "^4.0.12",
+        "string.prototype.repeat": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+      }
+    },
+    "node_modules/eslint-plugin-react-hooks": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
+      "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
+      }
+    },
+    "node_modules/eslint-plugin-react/node_modules/resolve": {
+      "version": "2.0.0-next.5",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+      "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/eslint-plugin-react/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "8.4.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+      "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+      "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree": {
+      "version": "10.4.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+      "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "acorn": "^8.15.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^4.2.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+      "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-png": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
+      "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/pako": "^2.0.3",
+        "iobuffer": "^5.3.2",
+        "pako": "^2.1.0"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+      "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fflate": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
+      "license": "MIT"
+    },
+    "node_modules/file-entry-cache": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+      "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flat-cache": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+      "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.4"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/for-each": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+      "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-callable": "^1.2.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "5.3.4",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
+      "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/rawify"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/function.prototype.name": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+      "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "functions-have-names": "^1.2.3",
+        "hasown": "^2.0.2",
+        "is-callable": "^1.2.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/generator-function": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+      "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/get-symbol-description": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+      "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-tsconfig": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
+      "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "resolve-pkg-maps": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.2.1",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/has-bigints": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+      "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+      "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/html-parse-stringify": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+      "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+      "license": "MIT",
+      "dependencies": {
+        "void-elements": "3.1.0"
+      }
+    },
+    "node_modules/html2canvas": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "css-line-break": "^2.1.0",
+        "text-segmentation": "^1.0.3"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/i18next": {
+      "version": "25.8.0",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.0.tgz",
+      "integrity": "sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://locize.com"
+        },
+        {
+          "type": "individual",
+          "url": "https://locize.com/i18next.html"
+        },
+        {
+          "type": "individual",
+          "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.28.4"
+      },
+      "peerDependencies": {
+        "typescript": "^5"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/icu-minify": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.8.0.tgz",
+      "integrity": "sha512-CY90QvJwc5ghNW+2gepxz4RWogCnM0ynHEFWSDTfGmE4ZPCPDQfkU36AntjbLcwv1Js2AofIGkxNq/LVVpCCbQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/amannn"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/icu-messageformat-parser": "^3.4.0"
+      }
+    },
+    "node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/internal-slot": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+      "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "hasown": "^2.0.2",
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/intl-messageformat": {
+      "version": "11.1.1",
+      "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.1.1.tgz",
+      "integrity": "sha512-vnrF2f4vfsdaFY6tuLZfzGcx1GZFMFAq6c7QdK3HSXNcGXEIQncNgbeAcnpjAOszQzq3Jbol2SwgshIGY08WyA==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@formatjs/ecma402-abstract": "3.1.0",
+        "@formatjs/fast-memoize": "3.1.0",
+        "@formatjs/icu-messageformat-parser": "3.5.0",
+        "tslib": "^2.8.1"
+      }
+    },
+    "node_modules/iobuffer": {
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
+      "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
+      "license": "MIT"
+    },
+    "node_modules/is-array-buffer": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+      "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-async-function": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+      "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "async-function": "^1.0.0",
+        "call-bound": "^1.0.3",
+        "get-proto": "^1.0.1",
+        "has-tostringtag": "^1.0.2",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-bigint": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+      "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-bigints": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-boolean-object": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+      "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-bun-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
+      "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^7.7.1"
+      }
+    },
+    "node_modules/is-callable": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.16.1",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-data-view": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+      "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "get-intrinsic": "^1.2.6",
+        "is-typed-array": "^1.1.13"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-date-object": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+      "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-finalizationregistry": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+      "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-generator-function": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+      "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.4",
+        "generator-function": "^2.0.0",
+        "get-proto": "^1.0.1",
+        "has-tostringtag": "^1.0.2",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-negative-zero": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+      "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-number-object": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+      "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-regex": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+      "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-set": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-shared-array-buffer": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+      "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-string": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+      "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-symbol": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+      "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-symbols": "^1.1.0",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typed-array": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+      "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "which-typed-array": "^1.1.16"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakmap": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakref": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+      "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakset": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+      "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/iterator.prototype": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
+      "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.6",
+        "get-proto": "^1.0.0",
+        "has-symbols": "^1.1.0",
+        "set-function-name": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/jiti": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+      "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jiti": "lib/jiti-cli.mjs"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+      "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json5": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+      "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "json5": "lib/cli.js"
+      }
+    },
+    "node_modules/jspdf": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.1.0.tgz",
+      "integrity": "sha512-xd1d/XRkwqnsq6FP3zH1Q+Ejqn2ULIJeDZ+FTKpaabVpZREjsJKRJwuokTNgdqOU+fl55KgbvgZ1pRTSWCP2kQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.28.4",
+        "fast-png": "^6.2.0",
+        "fflate": "^0.8.1"
+      },
+      "optionalDependencies": {
+        "canvg": "^3.0.11",
+        "core-js": "^3.6.0",
+        "dompurify": "^3.3.1",
+        "html2canvas": "^1.0.0-rc.5"
+      }
+    },
+    "node_modules/jspdf-autotable": {
+      "version": "5.0.7",
+      "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.7.tgz",
+      "integrity": "sha512-2wr7H6liNDBYNwt25hMQwXkEWFOEopgKIvR1Eukuw6Zmprm/ZcnmLTQEjW7Xx3FCbD3v7pflLcnMAv/h1jFDQw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "jspdf": "^2 || ^3 || ^4"
+      }
+    },
+    "node_modules/jsx-ast-utils": {
+      "version": "3.3.5",
+      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+      "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "array-includes": "^3.1.6",
+        "array.prototype.flat": "^1.3.1",
+        "object.assign": "^4.1.4",
+        "object.values": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "node_modules/language-subtag-registry": {
+      "version": "0.3.23",
+      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+      "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
+      "dev": true,
+      "license": "CC0-1.0"
+    },
+    "node_modules/language-tags": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
+      "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "language-subtag-registry": "^0.3.20"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/lightningcss": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
+      "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
+      "dev": true,
+      "license": "MPL-2.0",
+      "dependencies": {
+        "detect-libc": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "lightningcss-android-arm64": "1.30.2",
+        "lightningcss-darwin-arm64": "1.30.2",
+        "lightningcss-darwin-x64": "1.30.2",
+        "lightningcss-freebsd-x64": "1.30.2",
+        "lightningcss-linux-arm-gnueabihf": "1.30.2",
+        "lightningcss-linux-arm64-gnu": "1.30.2",
+        "lightningcss-linux-arm64-musl": "1.30.2",
+        "lightningcss-linux-x64-gnu": "1.30.2",
+        "lightningcss-linux-x64-musl": "1.30.2",
+        "lightningcss-win32-arm64-msvc": "1.30.2",
+        "lightningcss-win32-x64-msvc": "1.30.2"
+      }
+    },
+    "node_modules/lightningcss-android-arm64": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
+      "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-arm64": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
+      "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-x64": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
+      "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-freebsd-x64": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
+      "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm-gnueabihf": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
+      "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-gnu": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
+      "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-musl": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
+      "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-gnu": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
+      "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-musl": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
+      "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-arm64-msvc": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
+      "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-x64-msvc": {
+      "version": "1.30.2",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
+      "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/lucide-react": {
+      "version": "0.544.0",
+      "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz",
+      "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==",
+      "license": "ISC",
+      "peerDependencies": {
+        "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.21",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.5"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/napi-postinstall": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
+      "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "napi-postinstall": "lib/cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/napi-postinstall"
+      }
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/negotiator": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+      "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/next": {
+      "version": "16.1.6",
+      "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
+      "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
+      "license": "MIT",
+      "dependencies": {
+        "@next/env": "16.1.6",
+        "@swc/helpers": "0.5.15",
+        "baseline-browser-mapping": "^2.8.3",
+        "caniuse-lite": "^1.0.30001579",
+        "postcss": "8.4.31",
+        "styled-jsx": "5.1.6"
+      },
+      "bin": {
+        "next": "dist/bin/next"
+      },
+      "engines": {
+        "node": ">=20.9.0"
+      },
+      "optionalDependencies": {
+        "@next/swc-darwin-arm64": "16.1.6",
+        "@next/swc-darwin-x64": "16.1.6",
+        "@next/swc-linux-arm64-gnu": "16.1.6",
+        "@next/swc-linux-arm64-musl": "16.1.6",
+        "@next/swc-linux-x64-gnu": "16.1.6",
+        "@next/swc-linux-x64-musl": "16.1.6",
+        "@next/swc-win32-arm64-msvc": "16.1.6",
+        "@next/swc-win32-x64-msvc": "16.1.6",
+        "sharp": "^0.34.4"
+      },
+      "peerDependencies": {
+        "@opentelemetry/api": "^1.1.0",
+        "@playwright/test": "^1.51.1",
+        "babel-plugin-react-compiler": "*",
+        "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+        "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+        "sass": "^1.3.0"
+      },
+      "peerDependenciesMeta": {
+        "@opentelemetry/api": {
+          "optional": true
+        },
+        "@playwright/test": {
+          "optional": true
+        },
+        "babel-plugin-react-compiler": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/next-intl": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.8.0.tgz",
+      "integrity": "sha512-HiKCfG0pQMJ2GhtkQur6C7mpMUBs6lc0+HAZTUDm/5Nwh3dSYi/uAcAl0SiQTd01GmDou6dobd2th4U802lxOg==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/amannn"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/intl-localematcher": "^0.5.4",
+        "@parcel/watcher": "^2.4.1",
+        "@swc/core": "^1.15.2",
+        "icu-minify": "^4.8.0",
+        "negotiator": "^1.0.0",
+        "next-intl-swc-plugin-extractor": "^4.8.0",
+        "po-parser": "^2.1.1",
+        "use-intl": "^4.8.0"
+      },
+      "peerDependencies": {
+        "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0",
+        "typescript": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/next-intl-swc-plugin-extractor": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.8.0.tgz",
+      "integrity": "sha512-+uooJAaUUnctq/IZrKJrpoA8yB6/z5kDeraySZlT1+XaoU1i+Onaimo2y/vwlqSKPHVRdqx3aqhwRZPuh71LAw==",
+      "license": "MIT"
+    },
+    "node_modules/next-intl/node_modules/@swc/core": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.11.tgz",
+      "integrity": "sha512-iLmLTodbYxU39HhMPaMUooPwO/zqJWvsqkrXv1ZI38rMb048p6N7qtAtTp37sw9NzSrvH6oli8EdDygo09IZ/w==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@swc/counter": "^0.1.3",
+        "@swc/types": "^0.1.25"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/swc"
+      },
+      "optionalDependencies": {
+        "@swc/core-darwin-arm64": "1.15.11",
+        "@swc/core-darwin-x64": "1.15.11",
+        "@swc/core-linux-arm-gnueabihf": "1.15.11",
+        "@swc/core-linux-arm64-gnu": "1.15.11",
+        "@swc/core-linux-arm64-musl": "1.15.11",
+        "@swc/core-linux-x64-gnu": "1.15.11",
+        "@swc/core-linux-x64-musl": "1.15.11",
+        "@swc/core-win32-arm64-msvc": "1.15.11",
+        "@swc/core-win32-ia32-msvc": "1.15.11",
+        "@swc/core-win32-x64-msvc": "1.15.11"
+      },
+      "peerDependencies": {
+        "@swc/helpers": ">=0.5.17"
+      },
+      "peerDependenciesMeta": {
+        "@swc/helpers": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/next-themes": {
+      "version": "0.4.6",
+      "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
+      "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
+      }
+    },
+    "node_modules/next/node_modules/postcss": {
+      "version": "8.4.31",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.6",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "license": "MIT"
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.27",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+      "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.assign": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+      "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0",
+        "has-symbols": "^1.1.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.entries": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+      "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.fromentries": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.groupby": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+      "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.values": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+      "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.5"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/own-keys": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+      "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "get-intrinsic": "^1.2.6",
+        "object-keys": "^1.1.1",
+        "safe-push-apply": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pako": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
+      "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
+      "license": "(MIT AND Zlib)"
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/po-parser": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz",
+      "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==",
+      "license": "MIT"
+    },
+    "node_modules/possible-typed-array-names": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+      "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.6",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+      "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "nanoid": "^3.3.11",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/raf": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "performance-now": "^2.1.0"
+      }
+    },
+    "node_modules/react": {
+      "version": "19.2.4",
+      "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
+      "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "19.2.4",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
+      "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "scheduler": "^0.27.0"
+      },
+      "peerDependencies": {
+        "react": "^19.2.4"
+      }
+    },
+    "node_modules/react-i18next": {
+      "version": "16.5.4",
+      "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.4.tgz",
+      "integrity": "sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.28.4",
+        "html-parse-stringify": "^3.0.1",
+        "use-sync-external-store": "^1.6.0"
+      },
+      "peerDependencies": {
+        "i18next": ">= 25.6.2",
+        "react": ">= 16.8.0",
+        "typescript": "^5"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        },
+        "react-native": {
+          "optional": true
+        },
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/reflect.getprototypeof": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+      "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.9",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.7",
+        "get-proto": "^1.0.1",
+        "which-builtin-type": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+      "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-errors": "^1.3.0",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "set-function-name": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "1.22.11",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
+      "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.16.1",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/resolve-pkg-maps": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
+      "optional": true,
+      "engines": {
+        "node": ">= 0.8.15"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-array-concat": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+      "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "get-intrinsic": "^1.2.6",
+        "has-symbols": "^1.1.0",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">=0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safe-push-apply": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+      "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safe-regex-test": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+      "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-regex": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/scheduler": {
+      "version": "0.27.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+      "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+      "license": "MIT"
+    },
+    "node_modules/semver": {
+      "version": "7.7.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+      "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+      "devOptional": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-function-name": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-proto": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+      "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/sharp": {
+      "version": "0.34.5",
+      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+      "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@img/colour": "^1.0.0",
+        "detect-libc": "^2.1.2",
+        "semver": "^7.7.3"
+      },
+      "engines": {
+        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/libvips"
+      },
+      "optionalDependencies": {
+        "@img/sharp-darwin-arm64": "0.34.5",
+        "@img/sharp-darwin-x64": "0.34.5",
+        "@img/sharp-libvips-darwin-arm64": "1.2.4",
+        "@img/sharp-libvips-darwin-x64": "1.2.4",
+        "@img/sharp-libvips-linux-arm": "1.2.4",
+        "@img/sharp-libvips-linux-arm64": "1.2.4",
+        "@img/sharp-libvips-linux-ppc64": "1.2.4",
+        "@img/sharp-libvips-linux-riscv64": "1.2.4",
+        "@img/sharp-libvips-linux-s390x": "1.2.4",
+        "@img/sharp-libvips-linux-x64": "1.2.4",
+        "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+        "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+        "@img/sharp-linux-arm": "0.34.5",
+        "@img/sharp-linux-arm64": "0.34.5",
+        "@img/sharp-linux-ppc64": "0.34.5",
+        "@img/sharp-linux-riscv64": "0.34.5",
+        "@img/sharp-linux-s390x": "0.34.5",
+        "@img/sharp-linux-x64": "0.34.5",
+        "@img/sharp-linuxmusl-arm64": "0.34.5",
+        "@img/sharp-linuxmusl-x64": "0.34.5",
+        "@img/sharp-wasm32": "0.34.5",
+        "@img/sharp-win32-arm64": "0.34.5",
+        "@img/sharp-win32-ia32": "0.34.5",
+        "@img/sharp-win32-x64": "0.34.5"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3",
+        "side-channel-list": "^1.0.0",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stable-hash": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
+      "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/stackblur-canvas": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.1.14"
+      }
+    },
+    "node_modules/stop-iteration-iterator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+      "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "internal-slot": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/string.prototype.includes": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
+      "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/string.prototype.matchall": {
+      "version": "4.0.12",
+      "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+      "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.6",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.6",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "internal-slot": "^1.1.0",
+        "regexp.prototype.flags": "^1.5.3",
+        "set-function-name": "^2.0.2",
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.repeat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+      "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.5"
+      }
+    },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.10",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+      "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "define-data-property": "^1.1.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-object-atoms": "^1.0.0",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimend": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+      "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimstart": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/styled-jsx": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+      "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+      "license": "MIT",
+      "dependencies": {
+        "client-only": "0.0.1"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "peerDependencies": {
+        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        },
+        "babel-plugin-macros": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/svg-pathdata": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/tailwind-merge": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
+      "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/dcastil"
+      }
+    },
+    "node_modules/tailwindcss": {
+      "version": "4.1.18",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
+      "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tapable": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+      "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/text-segmentation": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "utrie": "^1.0.2"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.15",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+      "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/tinyglobby/node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/tinyglobby/node_modules/picomatch": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-api-utils": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
+      "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.12"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4"
+      }
+    },
+    "node_modules/tsconfig-paths": {
+      "version": "3.15.0",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+      "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.2",
+        "minimist": "^1.2.6",
+        "strip-bom": "^3.0.0"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD"
+    },
+    "node_modules/tw-animate-css": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
+      "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/Wombosvideo"
+      }
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/typed-array-buffer": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+      "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/typed-array-byte-length": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+      "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-proto": "^1.2.0",
+        "is-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-byte-offset": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+      "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-proto": "^1.2.0",
+        "is-typed-array": "^1.1.15",
+        "reflect.getprototypeof": "^1.0.9"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-length": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+      "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "is-typed-array": "^1.1.13",
+        "possible-typed-array-names": "^1.0.0",
+        "reflect.getprototypeof": "^1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.9.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+      "devOptional": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/unbox-primitive": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+      "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.1.0",
+        "which-boxed-primitive": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/unrs-resolver": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
+      "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "napi-postinstall": "^0.3.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unrs-resolver"
+      },
+      "optionalDependencies": {
+        "@unrs/resolver-binding-android-arm-eabi": "1.11.1",
+        "@unrs/resolver-binding-android-arm64": "1.11.1",
+        "@unrs/resolver-binding-darwin-arm64": "1.11.1",
+        "@unrs/resolver-binding-darwin-x64": "1.11.1",
+        "@unrs/resolver-binding-freebsd-x64": "1.11.1",
+        "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1",
+        "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1",
+        "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1",
+        "@unrs/resolver-binding-linux-arm64-musl": "1.11.1",
+        "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1",
+        "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1",
+        "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1",
+        "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1",
+        "@unrs/resolver-binding-linux-x64-gnu": "1.11.1",
+        "@unrs/resolver-binding-linux-x64-musl": "1.11.1",
+        "@unrs/resolver-binding-wasm32-wasi": "1.11.1",
+        "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1",
+        "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1",
+        "@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/use-intl": {
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.8.0.tgz",
+      "integrity": "sha512-IH56txyiaW26QQzneQf/0PWTa1Os3BMZvwbyDiS8cBjl6mm8dlhlKsgSU6TiSZjV6ZhMv763584jNBEyQV8vtQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/amannn"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@formatjs/fast-memoize": "^3.1.0",
+        "@schummar/icu-type-parser": "1.21.5",
+        "icu-minify": "^4.8.0",
+        "intl-messageformat": "^11.1.0"
+      },
+      "peerDependencies": {
+        "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/use-sync-external-store": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+      "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/utrie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "base64-arraybuffer": "^1.0.2"
+      }
+    },
+    "node_modules/void-elements": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+      "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/which-boxed-primitive": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+      "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-bigint": "^1.1.0",
+        "is-boolean-object": "^1.2.1",
+        "is-number-object": "^1.1.1",
+        "is-string": "^1.1.1",
+        "is-symbol": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-builtin-type": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+      "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "function.prototype.name": "^1.1.6",
+        "has-tostringtag": "^1.0.2",
+        "is-async-function": "^2.0.0",
+        "is-date-object": "^1.1.0",
+        "is-finalizationregistry": "^1.1.0",
+        "is-generator-function": "^1.0.10",
+        "is-regex": "^1.2.1",
+        "is-weakref": "^1.0.2",
+        "isarray": "^2.0.5",
+        "which-boxed-primitive": "^1.1.0",
+        "which-collection": "^1.0.2",
+        "which-typed-array": "^1.1.16"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-collection": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-map": "^2.0.3",
+        "is-set": "^2.0.3",
+        "is-weakmap": "^2.0.2",
+        "is-weakset": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-typed-array": {
+      "version": "1.1.20",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
+      "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "for-each": "^0.3.5",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  }
+}
Index: frontend/package.json
===================================================================
--- frontend/package.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/package.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,45 @@
+{
+  "name": "iknow-remaster",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "dev": "next dev",
+    "build": "next build",
+    "start": "next start",
+    "lint": "eslint"
+  },
+  "dependencies": {
+    "@fortawesome/fontawesome-svg-core": "^7.0.1",
+    "@fortawesome/free-brands-svg-icons": "^7.0.1",
+    "@fortawesome/free-regular-svg-icons": "^7.0.1",
+    "@fortawesome/free-solid-svg-icons": "^7.0.1",
+    "@fortawesome/react-fontawesome": "^3.0.2",
+    "class-variance-authority": "^0.7.1",
+    "clsx": "^2.1.1",
+    "i18next": "^25.8.0",
+    "jspdf": "^4.1.0",
+    "jspdf-autotable": "^5.0.7",
+    "lucide-react": "^0.544.0",
+    "next": "^16.1.6",
+    "next-intl": "^4.8.0",
+    "next-themes": "^0.4.6",
+    "react": "^19.2.4",
+    "react-dom": "^19.2.4",
+    "react-i18next": "^16.5.4",
+    "tailwind-merge": "^3.3.1"
+  },
+  "devDependencies": {
+    "@eslint/eslintrc": "^3",
+    "@tailwindcss/postcss": "^4",
+    "@types/node": "^20",
+    "@types/react": "^19",
+    "@types/react-dom": "^19",
+    "autoprefixer": "^10.4.21",
+    "eslint": "^9",
+    "eslint-config-next": "15.5.4",
+    "postcss": "^8.5.6",
+    "tailwindcss": "^4.1.13",
+    "tw-animate-css": "^1.4.0",
+    "typescript": "^5"
+  }
+}
Index: frontend/postcss.config.mjs
===================================================================
--- frontend/postcss.config.mjs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/postcss.config.mjs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,5 @@
+const config = {
+  plugins: ["@tailwindcss/postcss"],
+};
+
+export default config;
Index: frontend/public/file.svg
===================================================================
--- frontend/public/file.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/public/file.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,1 @@
+<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
Index: frontend/public/globe.svg
===================================================================
--- frontend/public/globe.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/public/globe.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,1 @@
+<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
Index: frontend/public/next.svg
===================================================================
--- frontend/public/next.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/public/next.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
Index: frontend/public/vercel.svg
===================================================================
--- frontend/public/vercel.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/public/vercel.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,1 @@
+<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
Index: frontend/public/window.svg
===================================================================
--- frontend/public/window.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/public/window.svg	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,1 @@
+<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
Index: frontend/src/app/[locale]/layout.tsx
===================================================================
--- frontend/src/app/[locale]/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/[locale]/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,5 @@
+import React from 'react';
+
+export default function LocaleLayout({ children }: { children: React.ReactNode }) {
+	return <>{children}</>;
+}
Index: frontend/src/app/admin/layout.tsx
===================================================================
--- frontend/src/app/admin/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/admin/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,27 @@
+import type { Metadata } from "next";
+import { Geist, Geist_Mono } from "next/font/google";
+import "../globals.css";
+import "@fortawesome/fontawesome-svg-core/styles.css";
+import { config } from "@fortawesome/fontawesome-svg-core";
+import Header from "@/components/header";
+import AdminNavbar from "@/components/admin-navbar";
+
+config.autoAddCss = false;
+
+const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
+const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
+
+export const metadata: Metadata = {
+  title: "IKnow - Admin Portal",
+  description: "Administration of subjects, semesters and teaching assignments",
+};
+
+export default function AdminLayout({ children }: Readonly<{ children: React.ReactNode }>) {
+  return (
+    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
+      <Header />
+      <AdminNavbar />
+      {children}
+    </div>
+  );
+}
Index: frontend/src/app/admin/page.tsx
===================================================================
--- frontend/src/app/admin/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/admin/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,5 @@
+import { redirect } from "next/navigation";
+
+export default function AdminIndex() {
+  redirect("/admin/subjects");
+}
Index: frontend/src/app/admin/schedule/page.tsx
===================================================================
--- frontend/src/app/admin/schedule/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/admin/schedule/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,224 @@
+"use client";
+
+import { useCallback, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { adminGet, adminSend, type AdminSemester, type Schedule } from "@/lib/admin-api";
+
+export default function AdminSchedulePage() {
+  const { t } = useTranslation();
+
+  const [semesters, setSemesters] = useState<AdminSemester[]>([]);
+  const [semesterId, setSemesterId] = useState<number | null>(null);
+  const [schedule, setSchedule] = useState<Schedule | null>(null);
+
+  const [loading, setLoading] = useState(true);
+  const [busy, setBusy] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [notice, setNotice] = useState<string | null>(null);
+
+  const [subjectId, setSubjectId] = useState<number | "">("");
+  const [professorId, setProfessorId] = useState<number | "">("");
+
+  useEffect(() => {
+    (async () => {
+      try {
+        const list = await adminGet<AdminSemester[]>("/api/admin/semesters");
+        setSemesters(list);
+        setSemesterId(list[0]?.id ?? null);
+      } catch (e) {
+        setError(e instanceof Error ? e.message : String(e));
+      } finally {
+        setLoading(false);
+      }
+    })();
+  }, []);
+
+  const loadSchedule = useCallback(async (id: number) => {
+    setLoading(true);
+    setError(null);
+    try {
+      setSchedule(await adminGet<Schedule>(`/api/admin/schedule/${id}`));
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    if (semesterId !== null) void loadSchedule(semesterId);
+  }, [semesterId, loadSchedule]);
+
+  async function run(action: () => Promise<{ message?: string }>) {
+    setBusy(true);
+    setError(null);
+    setNotice(null);
+    try {
+      const result = await action();
+      setNotice(result.message ?? null);
+      if (semesterId !== null) await loadSchedule(semesterId);
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setBusy(false);
+    }
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <h1 className="text-3xl font-bold mb-2">{t("admin_schedule")}</h1>
+        <p className="text-lg opacity-90">{t("admin_schedule_intro")}</p>
+      </div>
+
+      {error && (
+        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>
+      )}
+      {notice && (
+        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">{notice}</div>
+      )}
+
+      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
+        <div className="flex flex-wrap items-end gap-4">
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("semester")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={semesterId ?? ""}
+              onChange={(e) => setSemesterId(Number(e.target.value))}
+            >
+              {semesters.map((s) => (
+                <option key={s.id} value={s.id}>{s.name}</option>
+              ))}
+            </select>
+          </label>
+
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("subject")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={subjectId}
+              onChange={(e) => setSubjectId(e.target.value === "" ? "" : Number(e.target.value))}
+            >
+              <option value="">{t("admin_pick_subject")}</option>
+              {schedule?.allSubjects.map((s) => (
+                <option key={s.id} value={s.id}>{s.code} — {s.name}</option>
+              ))}
+            </select>
+          </label>
+
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_professor")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={professorId}
+              onChange={(e) => setProfessorId(e.target.value === "" ? "" : Number(e.target.value))}
+            >
+              <option value="">{t("admin_pick_professor")}</option>
+              {schedule?.professors.map((p) => (
+                <option key={p.id} value={p.id}>{p.name}</option>
+              ))}
+            </select>
+          </label>
+
+          <button
+            className="rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+            disabled={busy || subjectId === "" || professorId === "" || semesterId === null}
+            onClick={() =>
+              void run(() =>
+                adminSend("/api/admin/schedule", "POST", {
+                  ProfessorId: professorId,
+                  SemesterId: semesterId,
+                  SubjectId: subjectId,
+                }),
+              )
+            }
+          >
+            {t("admin_assign")}
+          </button>
+        </div>
+      </div>
+
+      {schedule && schedule.uncoveredSubjects.length > 0 && (
+        <div className="mb-6 rounded-lg border border-yellow-200 bg-yellow-50 px-4 py-3 text-sm text-yellow-900">
+          <strong>{t("admin_uncovered_count", { count: schedule.uncoveredSubjects.length })}</strong>
+          <span className="ml-2">{t("admin_uncovered_hint")}</span>
+          <div className="mt-2 font-mono text-xs">
+            {schedule.uncoveredSubjects.map((u) => u.code).join(", ")}
+          </div>
+        </div>
+      )}
+
+      <div className="grid gap-6 lg:grid-cols-3">
+        <div className="lg:col-span-2 bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+          <div className="bg-primary text-white px-6 py-4">
+            <h2 className="text-xl font-bold">
+              {t("admin_assignments")} {schedule ? `— ${schedule.semesterName}` : ""}
+            </h2>
+          </div>
+          <div className="overflow-x-auto">
+            <table className="w-full">
+              <thead className="bg-accent">
+                <tr>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_code")}</th>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("subject")}</th>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_professor")}</th>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
+                </tr>
+              </thead>
+              <tbody>
+                {loading ? (
+                  <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("loading")}</td></tr>
+                ) : !schedule || schedule.assignments.length === 0 ? (
+                  <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("admin_no_assignments")}</td></tr>
+                ) : (
+                  schedule.assignments.map((a) => (
+                    <tr key={`${a.subjectId}-${a.professorId}`} className="hover:bg-accent">
+                      <td className="px-4 py-3 border-b font-mono text-card-foreground">{a.subjectCode}</td>
+                      <td className="px-4 py-3 border-b text-card-foreground">{a.subjectName}</td>
+                      <td className="px-4 py-3 border-b text-card-foreground">{a.professorName}</td>
+                      <td className="px-4 py-3 border-b">
+                        <button
+                          className="rounded-lg bg-gray-800 px-3 py-1.5 text-sm text-white disabled:opacity-50"
+                          disabled={busy}
+                          onClick={() =>
+                            void run(() =>
+                              adminSend("/api/admin/schedule", "DELETE", {
+                                ProfessorId: a.professorId,
+                                SemesterId: schedule.semesterId,
+                                SubjectId: a.subjectId,
+                              }),
+                            )
+                          }
+                        >
+                          {t("admin_remove")}
+                        </button>
+                      </td>
+                    </tr>
+                  ))
+                )}
+              </tbody>
+            </table>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+          <div className="bg-primary text-white px-6 py-4">
+            <h2 className="text-xl font-bold">{t("admin_load")}</h2>
+          </div>
+          <ul className="divide-y divide-border">
+            {schedule?.load.map((l) => (
+              <li key={l.professorId} className="flex items-center justify-between px-4 py-3">
+                <span className="text-card-foreground">{l.professorName}</span>
+                <span className="rounded-full bg-accent px-2 py-0.5 text-sm text-muted-foreground">{l.subjects}</span>
+              </li>
+            ))}
+            {!schedule?.load.length && (
+              <li className="px-4 py-3 text-muted-foreground">{t("admin_no_professors")}</li>
+            )}
+          </ul>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/admin/semesters/page.tsx
===================================================================
--- frontend/src/app/admin/semesters/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/admin/semesters/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,173 @@
+"use client";
+
+import { useCallback, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { adminGet, adminSend, type AdminSemester } from "@/lib/admin-api";
+
+export default function AdminSemestersPage() {
+  const { t } = useTranslation();
+
+  const [semesters, setSemesters] = useState<AdminSemester[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [busy, setBusy] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [notice, setNotice] = useState<string | null>(null);
+
+  const [year, setYear] = useState(new Date().getFullYear());
+  const [type, setType] = useState<"winter" | "summer">("winter");
+  const [expandedId, setExpandedId] = useState<number | null>(null);
+
+  const refresh = useCallback(async () => {
+    setLoading(true);
+    setError(null);
+    try {
+      setSemesters(await adminGet<AdminSemester[]>("/api/admin/semesters"));
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    void refresh();
+  }, [refresh]);
+
+  async function create() {
+    setBusy(true);
+    setError(null);
+    setNotice(null);
+    try {
+      const result = await adminSend("/api/admin/semesters", "POST", { Year: year, Type: type });
+      setNotice(result.message ?? null);
+      await refresh();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setBusy(false);
+    }
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <h1 className="text-3xl font-bold mb-2">{t("admin_semesters")}</h1>
+        <p className="text-lg opacity-90">{t("admin_semesters_intro")}</p>
+      </div>
+
+      {error && (
+        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>
+      )}
+      {notice && (
+        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">{notice}</div>
+      )}
+
+      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
+        <h2 className="text-xl font-semibold mb-4 text-card-foreground">{t("admin_new_semester")}</h2>
+        <div className="flex flex-wrap items-end gap-4">
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_year")}</span>
+            <input
+              type="number"
+              min={2000}
+              max={2100}
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={year}
+              onChange={(e) => setYear(Number(e.target.value))}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_type")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={type}
+              onChange={(e) => setType(e.target.value as "winter" | "summer")}
+            >
+              <option value="winter">{t("admin_winter")}</option>
+              <option value="summer">{t("admin_summer")}</option>
+            </select>
+          </label>
+          <button
+            disabled={busy}
+            className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+            onClick={() => void create()}
+          >
+            {t("admin_open_semester")}
+          </button>
+        </div>
+      </div>
+
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">{t("admin_open_semesters")}</h2>
+        </div>
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("semester")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_enrolments")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_coverage")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
+              </tr>
+            </thead>
+            <tbody>
+              {loading ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("loading")}</td></tr>
+              ) : semesters.length === 0 ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("admin_no_semesters")}</td></tr>
+              ) : (
+                semesters.map((s) => {
+                  const uncovered = s.uncoveredSubjects.length;
+                  return (
+                    <>
+                      <tr key={s.id} className="hover:bg-accent">
+                        <td className="px-4 py-3 border-b text-card-foreground">{s.name}</td>
+                        <td className="px-4 py-3 border-b text-card-foreground">{s.enrolmentCount}</td>
+                        <td className="px-4 py-3 border-b">
+                          {uncovered === 0 ? (
+                            <span className="rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-800">
+                              {t("admin_fully_covered")}
+                            </span>
+                          ) : (
+                            <span className="rounded-full bg-yellow-100 px-2 py-0.5 text-xs text-yellow-900">
+                              {t("admin_uncovered_count", { count: uncovered })}
+                            </span>
+                          )}
+                        </td>
+                        <td className="px-4 py-3 border-b">
+                          {uncovered > 0 && (
+                            <button
+                              className="rounded-lg border border-border px-3 py-1.5 text-sm"
+                              onClick={() => setExpandedId(expandedId === s.id ? null : s.id)}
+                            >
+                              {expandedId === s.id ? t("admin_close") : t("admin_show_uncovered")}
+                            </button>
+                          )}
+                        </td>
+                      </tr>
+                      {expandedId === s.id && uncovered > 0 && (
+                        <tr key={`${s.id}-detail`}>
+                          <td colSpan={4} className="border-b bg-accent/40 px-4 py-4 text-sm">
+                            <p className="mb-2 text-muted-foreground">{t("admin_uncovered_hint")}</p>
+                            <ul className="grid gap-1 sm:grid-cols-2 lg:grid-cols-3">
+                              {s.uncoveredSubjects.map((u) => (
+                                <li key={u.id} className="text-card-foreground">
+                                  <span className="font-mono">{u.code}</span> — {u.name}
+                                </li>
+                              ))}
+                            </ul>
+                          </td>
+                        </tr>
+                      )}
+                    </>
+                  );
+                })
+              )}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/admin/subjects/page.tsx
===================================================================
--- frontend/src/app/admin/subjects/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/admin/subjects/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,409 @@
+"use client";
+
+import { useCallback, useEffect, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import {
+  adminGet,
+  adminSend,
+  type AdminSubject,
+  type SubjectRef,
+} from "@/lib/admin-api";
+
+const EMPTY_FORM = { name: "", code: "", awardedCredits: 6, dependencyCredit: 0 };
+
+export default function AdminSubjectsPage() {
+  const { t } = useTranslation();
+
+  const [subjects, setSubjects] = useState<AdminSubject[]>([]);
+  const [majors, setMajors] = useState<SubjectRef[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [busy, setBusy] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [notice, setNotice] = useState<string | null>(null);
+
+  const [form, setForm] = useState(EMPTY_FORM);
+  const [editingId, setEditingId] = useState<number | null>(null);
+  const [expandedId, setExpandedId] = useState<number | null>(null);
+  const [query, setQuery] = useState("");
+
+  const refresh = useCallback(async () => {
+    setLoading(true);
+    setError(null);
+    try {
+      const [s, m] = await Promise.all([
+        adminGet<AdminSubject[]>("/api/admin/subjects"),
+        adminGet<SubjectRef[]>("/api/admin/majors"),
+      ]);
+      setSubjects(s);
+      setMajors(m);
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    void refresh();
+  }, [refresh]);
+
+  async function run(action: () => Promise<{ message?: string }>) {
+    setBusy(true);
+    setError(null);
+    setNotice(null);
+    try {
+      const result = await action();
+      setNotice(result.message ?? null);
+      await refresh();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setBusy(false);
+    }
+  }
+
+  const filtered = useMemo(() => {
+    const q = query.trim().toLowerCase();
+    if (!q) return subjects;
+    return subjects.filter(
+      (s) =>
+        (s.name ?? "").toLowerCase().includes(q) ||
+        (s.code ?? "").toLowerCase().includes(q),
+    );
+  }, [subjects, query]);
+
+  function startEdit(s: AdminSubject) {
+    setEditingId(s.id);
+    setForm({
+      name: s.name ?? "",
+      code: s.code ?? "",
+      awardedCredits: s.awardedCredits,
+      dependencyCredit: s.dependencyCredit ?? 0,
+    });
+    window.scrollTo({ top: 0, behavior: "smooth" });
+  }
+
+  function cancelEdit() {
+    setEditingId(null);
+    setForm(EMPTY_FORM);
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <h1 className="text-3xl font-bold mb-2">{t("admin_subjects")}</h1>
+        <p className="text-lg opacity-90">{t("admin_subjects_intro")}</p>
+      </div>
+
+      {error && (
+        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
+          {error}
+        </div>
+      )}
+      {notice && (
+        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">
+          {notice}
+        </div>
+      )}
+
+      {/* create / edit */}
+      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
+        <h2 className="text-xl font-semibold mb-4 text-card-foreground">
+          {editingId === null ? t("admin_new_subject") : t("admin_edit_subject")}
+        </h2>
+        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_subject_name")}</span>
+            <input
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={form.name}
+              onChange={(e) => setForm({ ...form, name: e.target.value })}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_subject_code")}</span>
+            <input
+              className="rounded-lg border border-border bg-background px-3 py-2 font-mono"
+              value={form.code}
+              onChange={(e) => setForm({ ...form, code: e.target.value })}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_credits")}</span>
+            <input
+              type="number"
+              min={1}
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={form.awardedCredits}
+              onChange={(e) => setForm({ ...form, awardedCredits: Number(e.target.value) })}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_dependency_credit")}</span>
+            <input
+              type="number"
+              min={0}
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={form.dependencyCredit}
+              onChange={(e) => setForm({ ...form, dependencyCredit: Number(e.target.value) })}
+            />
+          </label>
+        </div>
+        <div className="mt-4 flex gap-3">
+          <button
+            disabled={busy}
+            className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+            onClick={() =>
+              void run(async () => {
+                const body = {
+                  Name: form.name,
+                  Code: form.code,
+                  AwardedCredits: form.awardedCredits,
+                  DependencyCredit: form.dependencyCredit,
+                };
+                const result =
+                  editingId === null
+                    ? await adminSend("/api/admin/subjects", "POST", body)
+                    : await adminSend(`/api/admin/subjects/${editingId}`, "PUT", body);
+                cancelEdit();
+                return result;
+              })
+            }
+          >
+            {editingId === null ? t("admin_create") : t("admin_save")}
+          </button>
+          {editingId !== null && (
+            <button
+              className="rounded-lg border border-border px-4 py-2 text-sm font-medium"
+              onClick={cancelEdit}
+              disabled={busy}
+            >
+              {t("cancel")}
+            </button>
+          )}
+        </div>
+      </div>
+
+      {/* list */}
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="flex items-center justify-between gap-4 bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">
+            {t("admin_subjects")} ({filtered.length})
+          </h2>
+          <input
+            className="rounded-lg px-3 py-2 text-card-foreground bg-background"
+            placeholder={t("admin_search_subject")}
+            value={query}
+            onChange={(e) => setQuery(e.target.value)}
+          />
+        </div>
+
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_code")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_name")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_credits")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_majors")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_prerequisites")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
+              </tr>
+            </thead>
+            <tbody>
+              {loading ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={6}>{t("loading")}</td></tr>
+              ) : filtered.length === 0 ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={6}>{t("admin_no_subjects")}</td></tr>
+              ) : (
+                filtered.map((s) => (
+                  <ExpandableRow
+                    key={s.id}
+                    subject={s}
+                    majors={majors}
+                    subjects={subjects}
+                    busy={busy}
+                    expanded={expandedId === s.id}
+                    onToggle={() => setExpandedId(expandedId === s.id ? null : s.id)}
+                    onEdit={() => startEdit(s)}
+                    run={run}
+                  />
+                ))
+              )}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  );
+}
+
+function ExpandableRow({
+  subject,
+  majors,
+  subjects,
+  busy,
+  expanded,
+  onToggle,
+  onEdit,
+  run,
+}: {
+  subject: AdminSubject;
+  majors: SubjectRef[];
+  subjects: AdminSubject[];
+  busy: boolean;
+  expanded: boolean;
+  onToggle: () => void;
+  onEdit: () => void;
+  run: (action: () => Promise<{ message?: string }>) => Promise<void>;
+}) {
+  const { t } = useTranslation();
+  const [majorId, setMajorId] = useState<number | "">("");
+  const [semester, setSemester] = useState(1);
+  const [prereqId, setPrereqId] = useState<number | "">("");
+
+  // A subject already taken by students cannot be deleted; the FK forbids it.
+  const deletable = subject.enrolledCount === 0;
+
+  return (
+    <>
+      <tr className="hover:bg-accent">
+        <td className="px-4 py-3 border-b font-mono text-card-foreground">{subject.code}</td>
+        <td className="px-4 py-3 border-b text-card-foreground">{subject.name}</td>
+        <td className="px-4 py-3 border-b text-card-foreground">{subject.awardedCredits}</td>
+        <td className="px-4 py-3 border-b text-sm text-muted-foreground">
+          {subject.majors.length === 0 ? "—" : subject.majors.map((m) => `${m.majorName} (${m.mandatorySemester})`).join(", ")}
+        </td>
+        <td className="px-4 py-3 border-b text-sm text-muted-foreground">
+          {subject.prerequisites.length === 0 ? "—" : subject.prerequisites.map((p) => p.code).join(", ")}
+        </td>
+        <td className="px-4 py-3 border-b">
+          <div className="flex flex-wrap gap-2">
+            <button className="rounded-lg border border-border px-3 py-1.5 text-sm" onClick={onToggle}>
+              {expanded ? t("admin_close") : t("admin_manage")}
+            </button>
+            <button className="rounded-lg bg-blue-600 px-3 py-1.5 text-sm text-white disabled:opacity-50" onClick={onEdit} disabled={busy}>
+              {t("edit_grade") === "Измени оценка" ? "Измени" : "Edit"}
+            </button>
+            <button
+              className="rounded-lg bg-gray-800 px-3 py-1.5 text-sm text-white disabled:opacity-40"
+              disabled={busy || !deletable}
+              title={deletable ? undefined : t("admin_delete_blocked", { count: subject.enrolledCount })}
+              onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}`, "DELETE"))}
+            >
+              {t("admin_delete")}
+            </button>
+          </div>
+        </td>
+      </tr>
+
+      {expanded && (
+        <tr>
+          <td colSpan={6} className="border-b bg-accent/40 px-4 py-4">
+            <div className="grid gap-6 lg:grid-cols-2">
+              {/* majors */}
+              <div>
+                <h3 className="font-semibold text-card-foreground mb-2">{t("admin_majors")}</h3>
+                <ul className="mb-3 space-y-1 text-sm">
+                  {subject.majors.map((m) => (
+                    <li key={m.majorId} className="flex items-center justify-between gap-2">
+                      <span>{m.majorName} — {t("enroll_semester_short")} {m.mandatorySemester}</span>
+                      <button
+                        className="text-red-700 hover:underline"
+                        disabled={busy}
+                        onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}/majors/${m.majorId}`, "DELETE"))}
+                      >
+                        {t("admin_remove")}
+                      </button>
+                    </li>
+                  ))}
+                  {subject.majors.length === 0 && <li className="text-muted-foreground">—</li>}
+                </ul>
+                <div className="flex flex-wrap gap-2">
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
+                    value={majorId}
+                    onChange={(e) => setMajorId(e.target.value === "" ? "" : Number(e.target.value))}
+                  >
+                    <option value="">{t("admin_pick_major")}</option>
+                    {majors.map((m) => (
+                      <option key={m.id} value={m.id}>{m.name}</option>
+                    ))}
+                  </select>
+                  <input
+                    type="number"
+                    min={1}
+                    className="w-24 rounded-lg border border-border bg-background px-3 py-2 text-sm"
+                    value={semester}
+                    onChange={(e) => setSemester(Number(e.target.value))}
+                  />
+                  <button
+                    className="rounded-lg bg-green-600 px-3 py-2 text-sm text-white disabled:opacity-50"
+                    disabled={busy || majorId === ""}
+                    onClick={() =>
+                      void run(() =>
+                        adminSend(`/api/admin/subjects/${subject.id}/majors`, "POST", {
+                          MajorId: majorId,
+                          MandatorySemester: semester,
+                        }),
+                      )
+                    }
+                  >
+                    {t("admin_add")}
+                  </button>
+                </div>
+              </div>
+
+              {/* prerequisites */}
+              <div>
+                <h3 className="font-semibold text-card-foreground mb-2">{t("admin_prerequisites")}</h3>
+                <ul className="mb-3 space-y-1 text-sm">
+                  {subject.prerequisites.map((p) => (
+                    <li key={p.id} className="flex items-center justify-between gap-2">
+                      <span>{p.code} — {p.name}</span>
+                      <button
+                        className="text-red-700 hover:underline"
+                        disabled={busy}
+                        onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}/prerequisites/${p.id}`, "DELETE"))}
+                      >
+                        {t("admin_remove")}
+                      </button>
+                    </li>
+                  ))}
+                  {subject.prerequisites.length === 0 && <li className="text-muted-foreground">—</li>}
+                </ul>
+                <div className="flex flex-wrap gap-2">
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
+                    value={prereqId}
+                    onChange={(e) => setPrereqId(e.target.value === "" ? "" : Number(e.target.value))}
+                  >
+                    <option value="">{t("admin_pick_prerequisite")}</option>
+                    {subjects
+                      .filter((other) => other.id !== subject.id)
+                      .map((other) => (
+                        <option key={other.id} value={other.id}>{other.code} — {other.name}</option>
+                      ))}
+                  </select>
+                  <button
+                    className="rounded-lg bg-green-600 px-3 py-2 text-sm text-white disabled:opacity-50"
+                    disabled={busy || prereqId === ""}
+                    onClick={() =>
+                      void run(() =>
+                        adminSend(`/api/admin/subjects/${subject.id}/prerequisites`, "POST", {
+                          DependencyId: prereqId,
+                        }),
+                      )
+                    }
+                  >
+                    {t("admin_add")}
+                  </button>
+                </div>
+              </div>
+            </div>
+          </td>
+        </tr>
+      )}
+    </>
+  );
+}
Index: frontend/src/app/globals.css
===================================================================
--- frontend/src/app/globals.css	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/globals.css	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,122 @@
+@import "tailwindcss";
+@import "tw-animate-css";
+
+@custom-variant dark (&:is(.dark *));
+
+@theme inline {
+  --color-background: var(--background);
+  --color-foreground: var(--foreground);
+  --font-sans: var(--font-geist-sans);
+  --font-mono: var(--font-geist-mono);
+  --color-sidebar-ring: var(--sidebar-ring);
+  --color-sidebar-border: var(--sidebar-border);
+  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+  --color-sidebar-accent: var(--sidebar-accent);
+  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+  --color-sidebar-primary: var(--sidebar-primary);
+  --color-sidebar-foreground: var(--sidebar-foreground);
+  --color-sidebar: var(--sidebar);
+  --color-chart-5: var(--chart-5);
+  --color-chart-4: var(--chart-4);
+  --color-chart-3: var(--chart-3);
+  --color-chart-2: var(--chart-2);
+  --color-chart-1: var(--chart-1);
+  --color-ring: var(--ring);
+  --color-input: var(--input);
+  --color-border: var(--border);
+  --color-destructive: var(--destructive);
+  --color-accent-foreground: var(--accent-foreground);
+  --color-accent: var(--accent);
+  --color-muted-foreground: var(--muted-foreground);
+  --color-muted: var(--muted);
+  --color-secondary-foreground: var(--secondary-foreground);
+  --color-secondary: var(--secondary);
+  --color-primary-foreground: var(--primary-foreground);
+  --color-primary: var(--primary);
+  --color-popover-foreground: var(--popover-foreground);
+  --color-popover: var(--popover);
+  --color-card-foreground: var(--card-foreground);
+  --color-card: var(--card);
+  --radius-sm: calc(var(--radius) - 4px);
+  --radius-md: calc(var(--radius) - 2px);
+  --radius-lg: var(--radius);
+  --radius-xl: calc(var(--radius) + 4px);
+}
+
+:root {
+  --radius: 0.625rem;
+  --background: #F4FAFF;
+  --foreground: oklch(0.145 0 0);
+  --card: oklch(1 0 0);
+  --card-foreground: oklch(0.145 0 0);
+  --popover: oklch(1 0 0);
+  --popover-foreground: oklch(0.145 0 0);
+  --primary: #0272D1;
+  --primary-foreground: oklch(0.985 0 0);
+  --secondary: oklch(0.97 0 0);
+  --secondary-foreground: oklch(0.205 0 0);
+  --muted: oklch(0.97 0 0);
+  --muted-foreground: oklch(0.556 0 0);
+  --accent: oklch(0.97 0 0);
+  --accent-foreground: oklch(0.205 0 0);
+  --destructive: oklch(0.577 0.245 27.325);
+  --border: oklch(0.922 0 0);
+  --input: oklch(0.922 0 0);
+  --ring: oklch(0.708 0 0);
+  --chart-1: oklch(0.646 0.222 41.116);
+  --chart-2: oklch(0.6 0.118 184.704);
+  --chart-3: oklch(0.398 0.07 227.392);
+  --chart-4: oklch(0.828 0.189 84.429);
+  --chart-5: oklch(0.769 0.188 70.08);
+  --sidebar: oklch(0.985 0 0);
+  --sidebar-foreground: oklch(0.145 0 0);
+  --sidebar-primary: oklch(0.205 0 0);
+  --sidebar-primary-foreground: oklch(0.985 0 0);
+  --sidebar-accent: oklch(0.97 0 0);
+  --sidebar-accent-foreground: oklch(0.205 0 0);
+  --sidebar-border: oklch(0.922 0 0);
+  --sidebar-ring: oklch(0.708 0 0);
+}
+
+.dark {
+  --background: oklch(0.15 0.01 240);
+  --foreground: oklch(0.95 0.01 240);
+  --card: oklch(0.18 0.01 240);
+  --card-foreground: oklch(0.95 0.01 240);
+  --popover: oklch(0.18 0.01 240);
+  --popover-foreground: oklch(0.95 0.01 240);
+  --primary: #3b82f6;
+  --primary-foreground: oklch(0.98 0 0);
+  --secondary: oklch(0.25 0.01 240);
+  --secondary-foreground: oklch(0.95 0.01 240);
+  --muted: oklch(0.25 0.01 240);
+  --muted-foreground: oklch(0.65 0.01 240);
+  --accent: oklch(0.25 0.01 240);
+  --accent-foreground: oklch(0.95 0.01 240);
+  --destructive: oklch(0.6 0.22 25);
+  --border: oklch(0.3 0.01 240);
+  --input: oklch(0.25 0.01 240);
+  --ring: oklch(0.5 0.15 240);
+  --chart-1: oklch(0.6 0.2 270);
+  --chart-2: oklch(0.65 0.18 180);
+  --chart-3: oklch(0.7 0.19 90);
+  --chart-4: oklch(0.6 0.24 310);
+  --chart-5: oklch(0.65 0.22 30);
+  --sidebar: oklch(0.18 0.01 240);
+  --sidebar-foreground: oklch(0.95 0.01 240);
+  --sidebar-primary: oklch(0.5 0.2 260);
+  --sidebar-primary-foreground: oklch(0.98 0 0);
+  --sidebar-accent: oklch(0.25 0.01 240);
+  --sidebar-accent-foreground: oklch(0.95 0.01 240);
+  --sidebar-border: oklch(0.3 0.01 240);
+  --sidebar-ring: oklch(0.5 0.15 240);
+}
+
+@layer base {
+  * {
+    @apply border-border outline-ring/50;
+  }
+  body {
+    @apply text-foreground bg-background;
+  }
+}
Index: frontend/src/app/layout.tsx
===================================================================
--- frontend/src/app/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,44 @@
+"use client";
+import { Geist, Geist_Mono } from "next/font/google";
+import "./globals.css";
+import '@fortawesome/fontawesome-svg-core/styles.css';
+import { config } from '@fortawesome/fontawesome-svg-core';
+import { I18nextProvider } from 'react-i18next';
+import i18n from '../i18n';
+import { ThemeProvider } from '../components/theme-provider';
+import { ThemeToggle } from '../components/theme-toggle';
+import ContactBubble from '../components/contact-bubble';
+
+config.autoAddCss = false;
+
+const geistSans = Geist({
+  variable: "--font-geist-sans",
+  subsets: ["latin"],
+});
+
+const geistMono = Geist_Mono({
+  variable: "--font-geist-mono",
+  subsets: ["latin"],
+});
+
+export default function RootLayout({
+  children,
+}: Readonly<{
+  children: React.ReactNode;
+}>) {
+  return (
+    <html lang="en" suppressHydrationWarning>
+      <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
+        <ThemeProvider attribute="class" defaultTheme="light" enableSystem>
+          <I18nextProvider i18n={i18n}>
+            <div className="fixed top-4 right-4 z-50">
+              <ThemeToggle />
+            </div>
+            <div className="mx-auto max-w-6xl px-4">{children}</div>
+            <ContactBubble />
+          </I18nextProvider>
+        </ThemeProvider>
+      </body>
+    </html>
+  );
+}
Index: frontend/src/app/page.tsx
===================================================================
--- frontend/src/app/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,242 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { 
+  faUser, 
+  faLock, 
+  faEye, 
+  faEyeSlash,
+  faSignInAlt,
+  faGraduationCap
+} from '@fortawesome/free-solid-svg-icons';
+import { useState } from 'react';
+import { login } from '@/lib/auth';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from '@/components/LanguageSwitcher';
+
+export default function LoginPage() {
+  const { t } = useTranslation();
+  const [showPassword, setShowPassword] = useState(false);
+  const [isSubmitting, setIsSubmitting] = useState(false);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const [formData, setFormData] = useState({
+    email: '',
+    password: ''
+  });
+
+  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    const { name, value } = e.target;
+    setFormData(prev => ({
+      ...prev,
+      [name]: value
+    }));
+  };
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    setErrorMessage(null);
+    setIsSubmitting(true);
+    try {
+      const session = await login({ email: formData.email, password: formData.password });
+      // Admins previously fell through to /students, where they have no
+      // enrolments and every page renders empty.
+      const home =
+        session.role === 'Professor' ? '/professor'
+        : session.role === 'Admin'   ? '/admin'
+        : '/students';
+      window.location.href = home;
+    } catch (err) {
+      setErrorMessage(err instanceof Error ? err.message : 'Login failed.');
+    } finally {
+      setIsSubmitting(false);
+    }
+  };
+
+  return (
+    <div className="container mx-auto px-4">
+      <div className="min-h-screen ">
+        {/* Login Form */}
+        <div className="flex items-center justify-center min-h-[calc(100vh-160px)] p-4">
+          <div className="w-full max-w-5xl">
+            <div className="grid grid-cols-1 gap-6 lg:grid-cols-[24rem_28rem_24rem] lg:items-start lg:justify-center">
+              {/* Sticky Notes */}
+              <div className="w-full flex flex-col gap-4">
+                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
+                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_student_title')}</div>
+                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
+                    {t('login_student_example')}
+                  </div>
+                  <div className="mt-3 text-xs text-blue-600 font-medium">
+                    {t('login_demo_note')}
+                  </div>
+                </div>
+
+                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
+                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_professor_title')}</div>
+                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
+                    {t('login_professor_example')}
+                  </div>
+                  <div className="mt-3 text-xs text-blue-600 font-medium">
+                    {t('login_demo_note')}
+                  </div>
+                </div>
+
+                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
+                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_admin_title')}</div>
+                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
+                    {t('login_admin_example')}
+                  </div>
+                  <div className="mt-3 text-xs text-blue-600 font-medium">
+                    {t('login_demo_note')}
+                  </div>
+                </div>
+              </div>
+
+              {/* Login Card Column */}
+              <div className="w-full max-w-md lg:max-w-none lg:w-[28rem] mx-auto">
+                {/* Login Card */}
+                <div className="bg-card rounded-2xl shadow-xl border border-border overflow-hidden">
+                {/* Header */}
+                <div className="bg-primary text-white px-8 py-6 text-center">
+              <div className="mb-4">
+                <div className="inline-flex items-center justify-center w-16 h-16 bg-white rounded-full shadow-lg">
+                  <FontAwesomeIcon icon={faUser} className="text-2xl text-[#0272D1]" />
+                </div>
+              </div>
+              <h1 className="text-2xl font-bold mb-2">{t('login_welcome')}</h1>
+              <p className="text-blue-100 text-sm">
+                {t('login_subtitle')}
+              </p>
+            </div>
+
+            {/* Form */}
+            <div className="p-8">
+              {/* Language Switcher above email field, centered */}
+              <div className="flex justify-center mb-6">
+                <LanguageSwitcher />
+              </div>
+              <form onSubmit={handleSubmit} className="space-y-6">
+                {/* Email Field */}
+                <div>
+                  <label htmlFor="email" className="block text-sm font-medium text-muted-foreground mb-2">
+                    {t('login_email_label')}
+                  </label>
+                  <div className="relative">
+                    <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
+                      <FontAwesomeIcon icon={faUser} className="h-4 w-4 text-muted-foreground" />
+                    </div>
+                    <input
+                      id="email"
+                      name="email"
+                      type="email"
+                      required
+                      value={formData.email}
+                      onChange={handleInputChange}
+                      className="w-full pl-10 pr-4 py-3 border border-input rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors"
+                      placeholder={t('login_email_placeholder')}
+                    />
+                  </div>
+                </div>
+
+                {/* Password Field */}
+                <div>
+                  <label htmlFor="password" className="block text-sm font-medium text-muted-foreground mb-2">
+                    {t('login_password_label')}
+                  </label>
+                  <div className="relative">
+                    <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
+                      <FontAwesomeIcon icon={faLock} className="h-4 w-4 text-muted-foreground" />
+                    </div>
+                    <input
+                      id="password"
+                      name="password"
+                      type={showPassword ? "text" : "password"}
+                      required
+                      value={formData.password}
+                      onChange={handleInputChange}
+                      className="w-full pl-10 pr-12 py-3 border border-input rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors"
+                      placeholder={t('login_password_placeholder')}
+                    />
+                    <button
+                      type="button"
+                      onClick={() => setShowPassword(!showPassword)}
+                      className="absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground transition-colors"
+                    >
+                      <FontAwesomeIcon 
+                        icon={showPassword ? faEyeSlash : faEye} 
+                        className="h-4 w-4" 
+                      />
+                    </button>
+                  </div>
+                </div>
+
+                {/* Remember Me & Forgot Password */}
+                <div className="flex items-center justify-between">
+                  <div className="flex items-center">
+                    <input
+                      id="remember"
+                      name="remember"
+                      type="checkbox"
+                      className="h-4 w-4 text-primary focus:ring-primary border-input rounded"
+                    />
+                    <label htmlFor="remember" className="ml-2 block text-sm text-muted-foreground">
+                      {t('login_remember_me')}
+                    </label>
+                  </div>
+                  <button
+                    type="button"
+                    className="text-sm text-primary hover:text-blue-700 font-medium transition-colors"
+                  >
+                    {t('login_forgot_password')}
+                  </button>
+                </div>
+
+                {errorMessage && (
+                  <div className="rounded-lg border border-destructive/20 bg-destructive/10 px-4 py-3 text-sm text-destructive">
+                    {t(errorMessage) || errorMessage}
+                  </div>
+                )}
+
+                {/* Submit Button */}
+                <button
+                  type="submit"
+                  disabled={isSubmitting}
+                  className="w-full bg-primary hover:bg-blue-700 disabled:opacity-60 disabled:hover:bg-primary text-white font-medium py-3 px-4 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
+                >
+                  <FontAwesomeIcon icon={faSignInAlt} className="h-4 w-4" />
+                  {isSubmitting ? t('login_button_loading') : t('login_button')}
+                </button>
+              </form>
+            </div>
+
+            {/* Footer */}
+            <div className="bg-accent px-8 py-4 border-t border-border">
+              <p className="text-center text-sm text-muted-foreground">
+                {t('login_no_account')}{' '}
+                <button className="text-primary hover:text-blue-700 font-medium transition-colors">
+                  {t('login_contact_admin')}
+                </button>
+              </p>
+            </div>
+                </div>
+
+                {/* Additional Info */}
+                <div className="mt-6 text-center">
+                  <div className="inline-flex items-center gap-2 px-4 py-2 bg-card bg-opacity-80 rounded-lg shadow-sm">
+                    <FontAwesomeIcon icon={faGraduationCap} className="text-primary" />
+                    <span className="text-sm text-muted-foreground">
+                      {t('login_footer')}
+                    </span>
+                  </div>
+                </div>
+              </div>
+
+              {/* Right spacer column (keeps login centered) */}
+              <div className="hidden lg:block" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/professor/layout.tsx
===================================================================
--- frontend/src/app/professor/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/professor/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,38 @@
+import type { Metadata } from "next";
+import { Geist, Geist_Mono } from "next/font/google";
+import "../globals.css";
+import "@fortawesome/fontawesome-svg-core/styles.css";
+import { config } from "@fortawesome/fontawesome-svg-core";
+import Header from "@/components/header";
+import ProfessorNavbar from "@/components/professor-navbar";
+
+config.autoAddCss = false;
+
+const geistSans = Geist({
+  variable: "--font-geist-sans",
+  subsets: ["latin"],
+});
+
+const geistMono = Geist_Mono({
+  variable: "--font-geist-mono",
+  subsets: ["latin"],
+});
+
+export const metadata: Metadata = {
+  title: "IKnow - Professor Portal",
+  description: "Professor portal for managing students and grades",
+};
+
+export default function ProfessorLayout({
+  children,
+}: Readonly<{
+  children: React.ReactNode;
+}>) {
+  return (
+    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
+      <Header />
+      <ProfessorNavbar />
+      {children}
+    </div>
+  );
+}
Index: frontend/src/app/professor/page.tsx
===================================================================
--- frontend/src/app/professor/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/professor/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,5 @@
+import { redirect } from "next/navigation";
+
+export default function ProfessorHome() {
+  redirect("/professor/students");
+}
Index: frontend/src/app/professor/profile/page.tsx
===================================================================
--- frontend/src/app/professor/profile/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/professor/profile/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,287 @@
+"use client";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import {
+  faUser,
+  faIdCard,
+  faAddressCard,
+  faCalendarAlt,
+  faFlag,
+  faVenus,
+  faMars,
+  faEnvelope,
+  faPhone,
+  faMapMarkerAlt,
+  faPassport,
+} from "@fortawesome/free-solid-svg-icons";
+import { useEffect, useState } from "react";
+import { getAccessToken } from "@/lib/auth";
+import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
+import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+
+type PersonalInfo = {
+  firstName: string;
+  middleName: string;
+  lastName: string;
+  maidenName: string;
+  dateOfBirth: string;
+  gender: string;
+  nationality: string;
+  citizenship: string;
+  scholarship: string;
+  currentPlan: string;
+  registryNumber: string;
+  studyGroup: string;
+  notes?: string;
+  index: string;
+  embg: string;
+};
+
+type BirthInfo = {
+  placeOfBirth: string;
+  municipalityOfBirth: string;
+  country: string;
+};
+
+// Present in the API response, but intentionally not shown on professor profile.
+type PreviousEducation = {
+  type: string;
+  profession: string;
+  average: string | number;
+  language: string;
+  country: string;
+  previousUniversity: string;
+  previousFaculty: string;
+  previousStudyMode: string;
+};
+
+// Present in the API response, but intentionally not shown on professor profile.
+type EnrollmentInfo = {
+  enrollmentYear: string | number;
+  status: string;
+  cycle: string;
+  program: string;
+  quota: string;
+  secondaryEducationNumber: string;
+  previousEducationCredits: string | number;
+};
+
+type Contact = {
+  placeOfResidence: string;
+  municipalityOfResidence: string;
+  country: string;
+  address: string;
+  temporaryAddress: string;
+  phone: string;
+  mobilePhone: string;
+  passportNumber: string;
+  passportExpiryDate: string;
+  email: string;
+  microsoftEmail: string;
+};
+
+type StudentProfile = {
+  personalInfo: PersonalInfo;
+  birthInfo: BirthInfo;
+  previousEducation: PreviousEducation;
+  enrollmentInfo: EnrollmentInfo;
+  contact: Contact;
+};
+
+interface InfoRowProps {
+  label: string;
+  value: string | number;
+  icon?: IconDefinition;
+}
+
+const InfoRow = ({ label, value, icon }: InfoRowProps) => {
+  const { t } = useTranslation();
+  return (
+    <div className="flex justify-between items-center py-3 border-b border-border last:border-b-0">
+      <div className="flex items-center gap-2 text-muted-foreground font-medium">
+        {icon && <FontAwesomeIcon icon={icon} className="w-4 h-4" />}
+        <span>{t(label)}:</span>
+      </div>
+      <div className="text-card-foreground font-semibold text-right max-w-xs break-words">
+        {value || t('n_a')}
+      </div>
+    </div>
+  );
+};
+
+interface SectionProps {
+  title: string;
+  icon: IconDefinition;
+  children: React.ReactNode;
+}
+
+const Section = ({ title, icon, children }: SectionProps) => {
+  const { t } = useTranslation();
+  return (
+    <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+      <div className="bg-primary text-white px-6 py-4">
+        <div className="flex items-center gap-3">
+          <FontAwesomeIcon icon={icon} className="text-xl" />
+          <h2 className="text-xl font-bold">{t(title)}</h2>
+        </div>
+      </div>
+      <div className="p-6">{children}</div>
+    </div>
+  );
+};
+
+export default function ProfessorProfilePage() {
+  const [profileData, setProfileData] = useState<StudentProfile | null>(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const { t } = useTranslation();
+
+  useEffect(() => {
+    let cancelled = false;
+
+    async function load() {
+      setIsLoading(true);
+      setErrorMessage(null);
+
+      const token = getAccessToken();
+      if (!token) {
+        setErrorMessage("Not authenticated. Please login again.");
+        setIsLoading(false);
+        return;
+      }
+
+      try {
+        const response = await fetch(apiUrl("/api/user/getUser"), {
+          method: "GET",
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        });
+
+        if (!response.ok) {
+          const text = await response.text().catch(() => "");
+          throw new Error(text || `Failed to load profile (${response.status})`);
+        }
+
+        const data = (await response.json()) as StudentProfile;
+        if (!cancelled) setProfileData(data);
+      } catch (err) {
+        if (!cancelled) {
+          setErrorMessage(err instanceof Error ? err.message : "Failed to load profile.");
+        }
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    }
+
+    void load();
+
+    return () => {
+      cancelled = true;
+    };
+  }, []);
+
+  if (isLoading) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="bg-card rounded-xl shadow-sm border border-border p-6">{t('loading')}</div>
+      </div>
+    );
+  }
+
+  if (errorMessage || !profileData) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
+          {errorMessage ?? t('failed_to_load_profile')}
+        </div>
+      </div>
+    );
+  }
+
+  const { personalInfo, birthInfo, contact } = profileData;
+
+  return (
+    <div className="min-h-screen pb-8">
+      {/* Header */}
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <div className="flex items-center gap-6">
+          <div className="relative">
+            <div className="w-20 h-20 bg-white rounded-full flex items-center justify-center border-2 border-white shadow-lg">
+              <FontAwesomeIcon icon={faUser} className="text-3xl text-[#0272D1]" />
+            </div>
+            <div className="absolute -bottom-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-2 border-white"></div>
+          </div>
+          <div>
+            <h1 className="text-3xl font-bold mb-2">
+              {personalInfo.firstName} {personalInfo.middleName} {personalInfo.lastName}
+            </h1>
+            <div className="text-lg opacity-90">
+              {t('index')}: {personalInfo.index} | {t('embg')}: {personalInfo.embg}
+            </div>
+          </div>
+        </div>
+      </div>
+
+      {/* Profile Sections */}
+      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
+        {/* Personal Information */}
+        <Section title="personal_info" icon={faIdCard}>
+          <InfoRow label="first_name" value={personalInfo.firstName} />
+          <InfoRow label="middle_name" value={personalInfo.middleName} />
+          <InfoRow label="last_name" value={personalInfo.lastName} />
+          <InfoRow label="maiden_name" value={personalInfo.maidenName} />
+          <InfoRow label="date_of_birth" value={personalInfo.dateOfBirth} icon={faCalendarAlt} />
+          <InfoRow
+            label="gender"
+            value={personalInfo.gender}
+            icon={personalInfo.gender === t('male') ? faMars : faVenus}
+          />
+          <InfoRow label="nationality" value={personalInfo.nationality} icon={faFlag} />
+          <InfoRow label="citizenship" value={personalInfo.citizenship} />
+          <InfoRow label="scholarship" value={personalInfo.scholarship} />
+          <InfoRow label="current_plan" value={personalInfo.currentPlan} />
+          <InfoRow label="registry_number" value={personalInfo.registryNumber} />
+          <InfoRow label="study_group" value={personalInfo.studyGroup} />
+          {personalInfo.notes && (
+            <div className="mt-4 p-4 bg-blue-50 rounded-lg">
+              <div className="text-sm font-medium text-blue-800 mb-1">{t('note')}:</div>
+              <div className="text-sm text-blue-700">{personalInfo.notes}</div>
+            </div>
+          )}
+        </Section>
+
+        {/* Birth Information */}
+        <Section title="birth_info" icon={faMapMarkerAlt}>
+          <InfoRow label="place_of_birth" value={birthInfo.placeOfBirth} />
+          <InfoRow label="municipality_of_birth" value={birthInfo.municipalityOfBirth} />
+          <InfoRow label="country" value={birthInfo.country} />
+        </Section>
+
+        {/* Contact Information */}
+        <div className="lg:col-span-2">
+          <Section title="contact" icon={faAddressCard}>
+            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+              <div>
+                <InfoRow label="place_of_residence" value={contact.placeOfResidence} icon={faMapMarkerAlt} />
+                <InfoRow label="municipality_of_residence" value={contact.municipalityOfResidence} />
+                <InfoRow label="country" value={contact.country} />
+                <InfoRow label="address" value={contact.address} />
+                <InfoRow label="temporary_address" value={contact.temporaryAddress} />
+              </div>
+              <div>
+                <InfoRow label="phone" value={contact.phone} icon={faPhone} />
+                <InfoRow label="mobile_phone" value={contact.mobilePhone} icon={faPhone} />
+                <InfoRow label="passport_number" value={contact.passportNumber} icon={faPassport} />
+                <InfoRow label="passport_expiry_date" value={contact.passportExpiryDate} />
+                <InfoRow label="email" value={contact.email} icon={faEnvelope} />
+                <InfoRow label="microsoft_email" value={contact.microsoftEmail} icon={faEnvelope} />
+              </div>
+            </div>
+          </Section>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/professor/students/page.tsx
===================================================================
--- frontend/src/app/professor/students/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/professor/students/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,315 @@
+"use client";
+
+import { useEffect, useMemo, useState } from "react";
+import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+import { getAccessToken } from '@/lib/auth';
+
+type UsersBySubject = {
+  /** users.id - what the grading endpoints expect as StudentId. */
+  id: number;
+  name?: string;
+  /** users.index - the number shown to the professor and searched on. */
+  index?: string;
+  grade: number;
+  semester?: string;
+};
+
+type SubjectsAndUsers = {
+  name?: string;
+  id?: number;
+  code?: string;
+  users: UsersBySubject[];
+};
+
+type GradePayload = {
+  StudentId: number;
+  SubjectId: number;
+  Grade: number;
+};
+
+type FlatRow = {
+  studentIdNum: number;
+  studentIndex: string;
+  studentName: string;
+  subjectId: number;
+  subjectName: string;
+  semester: string;
+  grade: number;
+};
+
+export default function ProfessorStudentsPage() {
+  const { t } = useTranslation();
+  const [subjects, setSubjects] = useState<SubjectsAndUsers[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState<string | null>(null);
+
+  const [subjectFilter, setSubjectFilter] = useState<string>("all");
+  const [studentIdQuery, setStudentIdQuery] = useState<string>("");
+
+  const [gradeSelection, setGradeSelection] = useState<Record<string, number>>({});
+  const [actionBusyKey, setActionBusyKey] = useState<string | null>(null);
+
+  async function refresh() {
+    setLoading(true);
+    setError(null);
+    try {
+      const token = getAccessToken();
+      if (!token) {
+        throw new Error("You are not signed in.");
+      }
+
+      const res = await fetch(apiUrl("/api/prof/students"), {
+        cache: "no-store",
+        headers: { Authorization: `Bearer ${token}` },
+      });
+      if (!res.ok) {
+        throw new Error(`Failed to fetch students (${res.status})`);
+      }
+      const data = (await res.json()) as SubjectsAndUsers[];
+      setSubjects(data);
+
+      const nextSelections: Record<string, number> = {};
+      for (const subj of data) {
+        if (!subj.id) continue;
+        for (const u of subj.users) {
+          const key = `${subj.id}:${u.id}`;
+          // grade_type only declares 6..10, so an ungraded row starts at 6.
+          nextSelections[key] = u.grade >= 6 && u.grade <= 10 ? u.grade : 6;
+        }
+      }
+      setGradeSelection(nextSelections);
+    } catch (e) {
+      setError(e instanceof Error ? e.message : "Unknown error");
+    } finally {
+      setLoading(false);
+    }
+  }
+
+  useEffect(() => {
+    void refresh();
+  }, []);
+
+  const flatRows = useMemo<FlatRow[]>(() => {
+    const rows: FlatRow[] = [];
+    for (const subj of subjects) {
+      if (!subj.id) continue;
+      for (const u of subj.users) {
+        rows.push({
+          studentIdNum: u.id,
+          studentIndex: u.index ?? "",
+          studentName: u.name ?? "",
+          subjectId: subj.id,
+          subjectName: subj.name ?? "",
+          semester: u.semester ?? "",
+          grade: u.grade,
+        });
+      }
+    }
+    return rows;
+  }, [subjects]);
+
+  const filteredRows = useMemo(() => {
+    const q = studentIdQuery.trim();
+    return flatRows.filter((r) => {
+      if (subjectFilter !== "all" && String(r.subjectId) !== subjectFilter) return false;
+      if (q.length > 0 && !r.studentIndex.includes(q)) return false;
+      return true;
+    });
+  }, [flatRows, subjectFilter, studentIdQuery]);
+
+  async function postGrade(url: string, payload: GradePayload, busyKey: string) {
+    setActionBusyKey(busyKey);
+    setError(null);
+    try {
+      const token = getAccessToken();
+      if (!token) {
+        throw new Error("You are not signed in.");
+      }
+
+      const res = await fetch(apiUrl(url), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+          Authorization: `Bearer ${token}`,
+        },
+        body: JSON.stringify(payload),
+      });
+      const body = (await res.json()) as { ok: boolean; message?: string };
+      if (!res.ok || !body.ok) {
+        throw new Error(body.message || `Request failed (${res.status})`);
+      }
+      await refresh();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : "Unknown error");
+    } finally {
+      setActionBusyKey(null);
+    }
+  }
+
+  return (
+    <div className="bg-card rounded-xl shadow-sm border border-border p-6">
+      <div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
+
+        <div>
+          <h1 className="text-2xl font-semibold text-card-foreground">{t('prof_students_title')}</h1>
+          <p className="text-muted-foreground mt-1">
+            {t('prof_students_data_note')} <span className="font-mono">/api/prof/students</span>.
+          </p>
+        </div>
+
+        <div className="flex flex-col sm:flex-row gap-3">
+          <div className="flex flex-col">
+            <label className="text-sm text-muted-foreground">{t('filter_by_subject')}</label>
+            <select
+              className="border border-border rounded-lg px-3 py-2"
+              value={subjectFilter}
+              onChange={(e) => setSubjectFilter(e.target.value)}
+            >
+              <option value="all">{t('all_subjects')}</option>
+              {subjects
+                .filter((s) => typeof s.id === "number")
+                .map((s) => (
+                  <option key={String(s.id)} value={String(s.id)}>
+                    {s.name ?? `${t('subject')} ${s.id}`}
+                  </option>
+                ))}
+            </select>
+          </div>
+
+          <div className="flex flex-col">
+            <label className="text-sm text-muted-foreground">{t('find_student_by_id')}</label>
+            <input
+              className="border border-border rounded-lg px-3 py-2"
+              placeholder={t('student_id_placeholder')}
+              value={studentIdQuery}
+              onChange={(e) => setStudentIdQuery(e.target.value)}
+            />
+          </div>
+        </div>
+      </div>
+
+      {error && (
+        <div className="mt-4 rounded-lg border border-red-200 bg-red-50 text-red-800 px-4 py-3">
+          {error}
+        </div>
+      )}
+
+      <div className="mt-6 overflow-x-auto">
+        <table className="min-w-full border border-border rounded-lg overflow-hidden">
+          <thead className="bg-accent">
+            <tr>
+              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('student')}</th>
+              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('id')}</th>
+              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('subject')}</th>
+              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('grade')}</th>
+              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('actions')}</th>
+            </tr>
+          </thead>
+          <tbody>
+            {loading ? (
+              <tr>
+                <td className="px-4 py-4 text-muted-foreground" colSpan={5}>
+                  {t('loading')}
+                </td>
+              </tr>
+            ) : filteredRows.length === 0 ? (
+              <tr>
+                <td className="px-4 py-4 text-muted-foreground" colSpan={5}>
+                  {t('no_students_found')}
+                </td>
+              </tr>
+            ) : (
+              filteredRows.map((r) => {
+                const key = `${r.subjectId}:${r.studentIdNum}`;
+                const selected = gradeSelection[key] ?? 6;
+                const busy = actionBusyKey === key;
+
+                return (
+                  <tr key={key} className="hover:bg-accent">
+                    <td className="px-4 py-3 border-b text-card-foreground">{r.studentName}</td>
+                    <td className="px-4 py-3 border-b text-card-foreground">{r.studentIndex}</td>
+                    <td className="px-4 py-3 border-b text-card-foreground">
+                      {r.subjectName}
+                      {r.semester && (
+                        <span className="block text-xs text-muted-foreground">{r.semester}</span>
+                      )}
+                    </td>
+                    <td className="px-4 py-3 border-b">
+                      <div className="flex items-center gap-3">
+                        <select
+                          className="border border-border rounded-lg px-3 py-2"
+                          value={selected}
+                          onChange={(e) =>
+                            setGradeSelection((prev) => ({
+                              ...prev,
+                              [key]: Number.parseInt(e.target.value, 10),
+                            }))
+                          }
+                        >
+                          {[6, 7, 8, 9, 10].map((g) => (
+                            <option key={g} value={g}>
+                              {g}
+                            </option>
+                          ))}
+                        </select>
+                        <span className="text-sm text-muted-foreground">
+                          {t('current')}: {r.grade > 0 ? r.grade : t('none')}
+                        </span>
+                      </div>
+                    </td>
+                    <td className="px-4 py-3 border-b">
+                      <div className="flex flex-wrap gap-2">
+                        <button
+                          disabled={busy}
+                          className="px-3 py-2 rounded-lg bg-green-600 text-white text-sm font-medium disabled:opacity-50"
+                          onClick={() => {
+                            void postGrade(
+                              "/api/prof/grade/add",
+                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: selected },
+                              key,
+                            );
+                          }}
+                        >
+                          {t('add_grade')}
+                        </button>
+
+                        <button
+                          disabled={busy}
+                          className="px-3 py-2 rounded-lg bg-blue-600 text-white text-sm font-medium disabled:opacity-50"
+                          onClick={() => {
+                            void postGrade(
+                              "/api/prof/grade/edit",
+                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: selected },
+                              key,
+                            );
+                          }}
+                        >
+                          {t('edit_grade')}
+                        </button>
+
+                        <button
+                          disabled={busy}
+                          className="px-3 py-2 rounded-lg bg-gray-800 text-white text-sm font-medium disabled:opacity-50"
+                          onClick={() => {
+                            void postGrade(
+                              "/api/prof/grade/remove",
+                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: 0 },
+                              key,
+                            );
+                          }}
+                        >
+                          {t('remove_grade')}
+                        </button>
+                      </div>
+                    </td>
+                  </tr>
+                );
+              })
+            )}
+          </tbody>
+        </table>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/students/applications/page.tsx
===================================================================
--- frontend/src/app/students/applications/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/applications/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,254 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { 
+  faPenToSquare, 
+  faChevronDown,
+  faCalendarAlt,
+  faFileText,
+  faMoneyBillWave,
+  faUser,
+  faInfoCircle,
+  faCheckCircle,
+  faTimesCircle
+} from '@fortawesome/free-solid-svg-icons';
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import applicationsData from '@/data/applications.json';
+
+interface TableCellProps {
+  children: React.ReactNode;
+  className?: string;
+}
+
+const TableCell = ({ children, className = "" }: TableCellProps) => (
+  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
+    {children}
+  </td>
+);
+
+const CompletedBadge = ({ completed }: { completed: string }) => {
+  const { t } = useTranslation();
+  if (completed === 'Да') {
+    return (
+      <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full" title={t('completed')}> 
+        <FontAwesomeIcon icon={faCheckCircle} className="w-4 h-4" />
+      </span>
+    );
+  } else {
+    return (
+      <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full" title={t('not_completed')}>
+        <FontAwesomeIcon icon={faTimesCircle} className="w-4 h-4" />
+      </span>
+    );
+  }
+};
+
+const FeeBadge = ({ fee }: { fee: string }) => {
+  const feeValue = parseFloat(fee.replace(',', '.'));
+  
+  if (feeValue === 0) {
+    return (
+      <span className="inline-flex items-center gap-1 px-2 py-1 bg-green-100 text-green-800 rounded-md text-xs font-medium">
+        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
+        {fee}
+      </span>
+    );
+  } else {
+    return (
+      <span className="inline-flex items-center gap-1 px-2 py-1 bg-yellow-100 text-yellow-800 rounded-md text-xs font-medium">
+        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
+        {fee}
+      </span>
+    );
+  }
+};
+
+export default function ApplicationsPage() {
+  const { t } = useTranslation();
+  const [selectedSession, setSelectedSession] = useState(applicationsData.currentSession.id);
+  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+
+  const currentSessionData = applicationsData.examSessions.find(s => s.id === selectedSession) || applicationsData.currentSession;
+  const { applications } = applicationsData;
+
+  return (
+    <div className="min-h-screen pb-8">
+      {/* Header */}
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <div className="flex items-center gap-4">
+          <div className="bg-white rounded-full p-4">
+            <FontAwesomeIcon icon={faPenToSquare} className="text-3xl text-[#0272D1]" />
+          </div>
+          <div>
+            <h1 className="text-3xl font-bold mb-2">{t('applications_header', 'Пријави')}</h1>
+            <p className="text-lg opacity-90">
+              {t('applications_subheader', 'Електронски пријави за испити')}
+            </p>
+          </div>
+        </div>
+      </div>
+
+      {/* Session Selection */}
+      <div className="bg-card rounded-xl p-6 shadow-sm border border-border mb-8">
+        <div className="flex items-center justify-between">
+          <h2 className="text-lg font-semibold text-card-foreground flex items-center gap-2">
+            <FontAwesomeIcon icon={faCalendarAlt} className="text-primary" />
+            {t('select_exam_session', 'Избери испитна сесија:')}
+          </h2>
+
+          <div className="relative">
+            <button
+              onClick={() => setIsDropdownOpen(!isDropdownOpen)}
+              className="bg-card border border-border rounded-lg px-4 py-2 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary min-w-80"
+            >
+              <div className="flex items-center justify-between">
+                <span className="text-sm font-medium text-primary">
+                  {t(currentSessionData.id, currentSessionData.name)}
+                </span>
+                <FontAwesomeIcon
+                  icon={faChevronDown}
+                  className={`w-4 h-4 text-muted-foreground transition-transform ml-4 ${isDropdownOpen ? 'rotate-180' : ''}`}
+                />
+              </div>
+            </button>
+
+            {isDropdownOpen && (
+              <div className="absolute z-10 right-0 mt-1 w-80 bg-card border border-border rounded-lg shadow-lg">
+                {applicationsData.examSessions.map((session) => (
+                  <button
+                    key={session.id}
+                    onClick={() => {
+                      setSelectedSession(session.id);
+                      setIsDropdownOpen(false);
+                    }}
+                    className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent first:rounded-t-lg last:rounded-b-lg"
+                  >
+                    <div className="font-medium text-card-foreground">{t(session.id, session.name)}</div>
+                    <div className="text-xs text-muted-foreground">{session.year} - {t(session.semester, session.semester)} - {t(session.session, session.session)}</div>
+                  </button>
+                ))}
+              </div>
+            )}
+          </div>
+        </div>
+      </div>
+
+      {/* Applications Section */}
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">{t('registered_exams', 'Пријавени испити')}</h2>
+        </div>
+
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('serial_number', 'Сериски број')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('code', 'Код')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('subject', 'Предмет')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('completed', 'Завршена')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('fee', 'Таксени')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date', 'Датум')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('instructor', 'Наставник')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('decade', 'Декада')}</th>
+              </tr>
+            </thead>
+            <tbody className="divide-y divide-border">
+              {applications.map((application) => (
+                <tr key={application.id} className="hover:bg-accent transition-colors">
+                  <TableCell className="font-medium text-card-foreground">{application.id}</TableCell>
+                  <TableCell>
+                    <span className="font-mono text-sm text-primary font-medium hover:underline cursor-pointer">
+                      {application.serviceNumber}
+                    </span>
+                  </TableCell>
+                  <TableCell className="font-mono text-sm font-medium">{application.code}</TableCell>
+                  <TableCell className="font-medium text-card-foreground max-w-xs">
+                    <div className="flex items-center gap-2">
+                      <FontAwesomeIcon icon={faFileText} className="w-4 h-4 text-primary" />
+                      {t(application.subject, application.subject)}
+                    </div>
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <CompletedBadge completed={application.completed} />
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <FeeBadge fee={application.fee} />
+                  </TableCell>
+                  <TableCell className="text-muted-foreground font-medium">{application.date}</TableCell>
+                  <TableCell>
+                    <div className="flex items-center gap-2">
+                      <FontAwesomeIcon icon={faUser} className="w-4 h-4 text-muted-foreground" />
+                      <span className="font-medium text-card-foreground">{t(application.instructor, application.instructor)}</span>
+                    </div>
+                  </TableCell>
+                  <TableCell className="text-center font-medium text-primary">{application.decade}</TableCell>
+                </tr>
+              ))}
+            </tbody>
+          </table>
+        </div>
+
+        {/* Important Note */}
+        <div className="bg-blue-50 border-t border-blue-100 p-6">
+          <div className="flex items-start gap-3">
+            <FontAwesomeIcon icon={faInfoCircle} className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
+            <div>
+              <h3 className="font-medium text-blue-900 mb-1">{t('important_note', 'Важна забелешка')}</h3>
+              <p className="text-sm text-blue-800 leading-relaxed">
+                {t('applications_important_note_text')}
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      {/* Statistics Cards */}
+      <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-blue-100 text-blue-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faFileText} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('registered_exams', 'Пријавени испити')}</h3>
+              <p className="text-2xl font-bold text-blue-600">
+                {applications.length}
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-green-100 text-green-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('completed', 'Завршени')}</h3>
+              <p className="text-2xl font-bold text-green-600">
+                {applications.filter(app => app.completed === 'Да').length}
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-yellow-100 text-yellow-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faMoneyBillWave} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('total_fee', 'Вкупна такса')}</h3>
+              <p className="text-2xl font-bold text-yellow-600">
+                {applications.reduce((sum, app) => sum + parseFloat(app.fee.replace(',', '.')), 0).toFixed(2)}
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/students/documents/page.tsx
===================================================================
--- frontend/src/app/students/documents/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/documents/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,447 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { 
+  faFilePdf, 
+  faChevronDown,
+  faCheckCircle,
+  faClock,
+  faMoneyBillWave,
+  faFileText,
+  faChevronLeft,
+  faChevronRight,
+  faAngleDoubleLeft,
+  faAngleDoubleRight,
+  faSpinner
+} from '@fortawesome/free-solid-svg-icons';
+import { useState } from 'react';
+import documentsData from '@/data/documents.json';
+import { useTranslation } from 'react-i18next';
+import { getAccessToken } from '@/lib/auth';
+import { downloadDocumentPDF } from '@/lib/pdf-generators';
+
+interface TableCellProps {
+  children: React.ReactNode;
+  className?: string;
+}
+
+const TableCell = ({ children, className = "" }: TableCellProps) => (
+  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
+    {children}
+  </td>
+);
+
+const StatusBadge = ({ status }: { status: string }) => {
+  const { t } = useTranslation();
+  if (status === 'approved' || status === t('approved', 'Одобрено')) {
+    return (
+      <span className="inline-flex items-center justify-center w-8 h-8 bg-green-100 text-green-600 rounded-full">
+        <FontAwesomeIcon icon={faCheckCircle} className="w-5 h-5" />
+      </span>
+    );
+  }
+  if (status === 'pending') {
+    return (
+      <span className="inline-flex items-center gap-1 text-xs font-medium text-yellow-700 bg-yellow-100 px-2 py-1 rounded-full">
+        <FontAwesomeIcon icon={faClock} className="w-3 h-3" />
+        {t('pending', 'Во обработка')}
+      </span>
+    );
+  }
+  return (
+    <span className="inline-flex items-center justify-center w-8 h-8 bg-accent text-muted-foreground rounded-full">
+      <FontAwesomeIcon icon={faFileText} className="w-4 h-4" />
+    </span>
+  );
+};
+
+const PriceBadge = ({ price }: { price: number }) => {
+  const { t } = useTranslation();
+  if (price === 0) {
+    return <span className="font-medium text-green-600">{t('free', '0,00')}</span>;
+  }
+  return <span className="font-medium text-blue-600">{price.toFixed(2)}</span>;
+};
+
+interface DocumentRecord {
+  id: number;
+  archive: string;
+  date: string;
+  request: string;
+  price: number;
+  paid: string;
+  document: string;
+  payOnline: boolean;
+  status: string;
+  comment: string;
+}
+
+export default function DocumentsPage() {
+  const [selectedDocumentType, setSelectedDocumentType] = useState("select_document");
+  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+  const [comment, setComment] = useState("");
+  const [currentPage, setCurrentPage] = useState(1);
+  const [recordsPerPage, setRecordsPerPage] = useState(15);
+  const [downloadingId, setDownloadingId] = useState<number | null>(null);
+  const [documents, setDocuments] = useState<DocumentRecord[]>(documentsData.documents as DocumentRecord[]);
+  const [isSubmitting, setIsSubmitting] = useState(false);
+  const { t } = useTranslation();
+
+  const handleDownload = async (docId: number, request: string, archive: string, date: string) => {
+    const token = getAccessToken();
+    if (!token) {
+      alert(t('not_authenticated', 'Не сте најавени. Ве молиме најавете се повторно.'));
+      return;
+    }
+    setDownloadingId(docId);
+    try {
+      await downloadDocumentPDF(request, archive, date, token);
+    } catch (err) {
+      console.error('PDF generation error:', err);
+      alert(t('pdf_error', 'Грешка при генерирање на документот. Обидете се повторно.'));
+    } finally {
+      setDownloadingId(null);
+    }
+  };
+
+  const handleSubmit = () => {
+    if (selectedDocumentType === "select_document") return;
+
+    const docType = documentsData.documentTypes.find(d => d.id === selectedDocumentType);
+    if (!docType) return;
+
+    setIsSubmitting(true);
+
+    // Generate archive number (random 5-digit)
+    const archiveNumber = String(90000 + Math.floor(Math.random() * 10000));
+
+    // Current date in DD.MM.YYYY format
+    const now = new Date();
+    const dateStr = `${String(now.getDate()).padStart(2, '0')}.${String(now.getMonth() + 1).padStart(2, '0')}.${now.getFullYear()}`;
+
+    const newDoc: DocumentRecord = {
+      id: documents.length > 0 ? Math.max(...documents.map(d => d.id)) + 1 : 1,
+      archive: archiveNumber,
+      date: dateStr,
+      request: docType.name,
+      price: docType.price,
+      paid: "Не",
+      document: "Преземи",
+      payOnline: docType.price > 0,
+      status: "pending",
+      comment: comment,
+    };
+
+    setDocuments(prev => [newDoc, ...prev]);
+    setSelectedDocumentType("select_document");
+    setComment("");
+    setIsSubmitting(false);
+    alert(t('document_submitted', 'Барањето за документ е успешно поднесено!'));
+  };
+
+  const selectedDocument = documentsData.documentTypes.find(d => d.id === selectedDocumentType);
+  const { paymentInfo } = documentsData;
+
+  const totalPages = Math.ceil(documents.length / recordsPerPage);
+  const startIndex = (currentPage - 1) * recordsPerPage;
+  const endIndex = startIndex + recordsPerPage;
+  const currentDocuments = documents.slice(startIndex, endIndex);
+
+  return (
+    <div className="min-h-screen pb-8">
+      {/* Header */}
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <div className="flex items-center gap-4">
+          <div className="bg-white rounded-full p-4">
+            <FontAwesomeIcon icon={faFilePdf} className="text-3xl text-[#0272D1]" />
+          </div>
+          <div>
+            <h1 className="text-3xl font-bold mb-2">{t('documents')}</h1>
+            <p className="text-lg opacity-90">
+              {t('documents_overview', 'Преглед на вашите документи и нивниот статус.')}
+            </p>
+          </div>
+        </div>
+      </div>
+
+      {/* Document Request Form */}
+      <div className="bg-card rounded-xl p-6 shadow-sm border border-border mb-8">
+        <h2 className="text-lg font-semibold text-card-foreground mb-6 flex items-center gap-2">
+          <FontAwesomeIcon icon={faFileText} className="text-primary" />
+          {t('new_document_request', 'Ново барање за документ')}
+        </h2>
+        
+        <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
+          {/* Document Type Selection */}
+          <div>
+            <label className="block text-sm font-medium text-muted-foreground mb-2">
+              {t('select_document', 'Избери документ')}:
+            </label>
+            <div className="relative">
+              <button
+                onClick={() => setIsDropdownOpen(!isDropdownOpen)}
+                className="w-full bg-card border border-border rounded-lg px-4 py-3 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
+              >
+                <div className="flex items-center justify-between">
+                  <span className="text-sm text-card-foreground truncate">
+                    {selectedDocument ? t(selectedDocument.id) : t('select_document', 'Избери документ')}
+                  </span>
+                  <FontAwesomeIcon 
+                    icon={faChevronDown} 
+                    className={`w-4 h-4 text-muted-foreground transition-transform ml-2 flex-shrink-0 ${isDropdownOpen ? 'rotate-180' : ''}`}
+                  />
+                </div>
+              </button>
+              
+              {isDropdownOpen && (
+                <div className="absolute z-10 w-full mt-1 bg-card border border-border rounded-lg shadow-lg max-h-80 overflow-y-auto">
+                  {documentsData.documentTypes.map((docType) => (
+                    <button
+                      key={docType.id}
+                      onClick={() => {
+                        setSelectedDocumentType(docType.id);
+                        setIsDropdownOpen(false);
+                      }}
+                      className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent border-b border-border last:border-b-0"
+                    >
+                      <div className="font-medium text-card-foreground">{t(docType.id)}</div>
+                      {docType.price > 0 && (
+                        <div className="text-xs text-blue-600 mt-1">{t('price', 'Цена')}: {docType.price} мкд</div>
+                      )}
+                    </button>
+                  ))}
+                </div>
+              )}
+            </div>
+          </div>
+
+          {/* Comment Section */}
+          <div>
+            <label className="block text-sm font-medium text-muted-foreground mb-2">
+              {t('comment', 'Коментар')}:
+            </label>
+            <textarea
+              value={comment}
+              onChange={(e) => setComment(e.target.value)}
+              rows={4}
+              className="w-full border border-border rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary resize-none"
+              placeholder={t('add_comment', 'Додај коментар')}
+            />
+          </div>
+        </div>
+
+        <div className="flex justify-end mt-6">
+          <button
+            onClick={handleSubmit}
+            className="bg-primary hover:bg-blue-700 text-white font-medium py-2 px-6 rounded-lg transition-colors duration-200 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
+            disabled={selectedDocumentType === "select_document" || isSubmitting}
+          >
+            <FontAwesomeIcon icon={isSubmitting ? faSpinner : faFileText} className={`w-4 h-4 ${isSubmitting ? 'animate-spin' : ''}`} />
+            {isSubmitting ? t('submitting', 'Се поднесува...') : t('submit', 'Поднеси')}
+          </button>
+        </div>
+      </div>
+
+      {/* Documents Table */}
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">{t('my_documents', 'Мои документи')}</h2>
+        </div>
+        
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('archive', 'Архива')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date', 'Датум')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('request', 'Барање')}</th>
+                <th className="px-4 py-4 text-right text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('price', 'Цена')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('paid', 'Платено')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('document', 'Документ')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('pay_online', 'Плати онлајн')}</th>
+                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('status', 'Статус')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('comment', 'Коментар')}</th>
+              </tr>
+            </thead>
+            <tbody className="divide-y divide-border">
+              {currentDocuments.map((document) => (
+                <tr key={document.id} className="hover:bg-accent transition-colors">
+                  <TableCell className="font-medium text-card-foreground">{document.id}</TableCell>
+                  <TableCell className="font-mono text-sm text-primary font-medium">{document.archive}</TableCell>
+                  <TableCell className="text-muted-foreground">{document.date}</TableCell>
+                  <TableCell className="font-medium text-card-foreground max-w-xs">
+                    {t(document.request)}
+                  </TableCell>
+                  <TableCell className="text-right">
+                    <PriceBadge price={document.price} />
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <span className={`text-sm font-medium ${document.paid === 'ДА' ? 'text-green-600' : 'text-red-500'}`}>
+                      {document.paid}
+                    </span>
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <button 
+                      onClick={() => handleDownload(document.id, document.request, document.archive, document.date)}
+                      disabled={downloadingId === document.id}
+                      className="text-primary hover:text-blue-700 font-medium text-sm underline disabled:opacity-50 disabled:cursor-wait inline-flex items-center gap-1"
+                    >
+                      {downloadingId === document.id ? (
+                        <>
+                          <FontAwesomeIcon icon={faSpinner} className="w-3 h-3 animate-spin" />
+                          {t('generating', 'Генерира...')}
+                        </>
+                      ) : (
+                        t('download', document.document)
+                      )}
+                    </button>
+                  </TableCell>
+                  <TableCell className="text-center">
+                    {document.payOnline ? (
+                      <FontAwesomeIcon icon={faCheckCircle} className="w-5 h-5 text-green-600" />
+                    ) : (
+                      <span className="text-muted-foreground">{t('none', '—')}</span>
+                    )}
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <StatusBadge status={document.status} />
+                  </TableCell>
+                  <TableCell>
+                    {document.comment || (
+                      <span className="text-muted-foreground">{t('none', '—')}</span>
+                    )}
+                  </TableCell>
+                </tr>
+              ))}
+            </tbody>
+          </table>
+        </div>
+
+        {/* Pagination */}
+        <div className="bg-accent px-6 py-4 flex items-center justify-between border-t border-border">
+          <div className="flex items-center gap-4 text-sm text-muted-foreground">
+            <div className="flex items-center gap-2">
+              <span>{t('show_rows', 'Прикажи редови')}:</span>
+              <select
+                value={recordsPerPage}
+                onChange={(e) => setRecordsPerPage(Number(e.target.value))}
+                className="border border-border rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-primary"
+              >
+                <option value={15}>15</option>
+                <option value={25}>25</option>
+                <option value={50}>50</option>
+              </select>
+            </div>
+            <div>
+              {t('page', 'Страница')} <input
+                type="number"
+                min="1"
+                max={totalPages}
+                value={currentPage}
+                onChange={(e) => setCurrentPage(Number(e.target.value))}
+                className="w-12 border border-border rounded px-2 py-1 text-sm text-center focus:outline-none focus:ring-1 focus:ring-primary"
+              /> {t('of', 'од')} {totalPages}
+            </div>
+          </div>
+
+          <div className="flex items-center gap-2">
+            <button
+              onClick={() => setCurrentPage(1)}
+              disabled={currentPage === 1}
+              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
+            >
+              <FontAwesomeIcon icon={faAngleDoubleLeft} className="w-4 h-4" />
+            </button>
+            <button
+              onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
+              disabled={currentPage === 1}
+              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
+            >
+              <FontAwesomeIcon icon={faChevronLeft} className="w-4 h-4" />
+            </button>
+            <span className="px-4 py-2 bg-primary text-white rounded text-sm font-medium">
+              {t('first', 'Прва')}
+            </span>
+            <button
+              onClick={() => setCurrentPage(Math.min(totalPages, currentPage + 1))}
+              disabled={currentPage === totalPages}
+              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
+            >
+              <FontAwesomeIcon icon={faChevronRight} className="w-4 h-4" />
+            </button>
+            <button
+              onClick={() => setCurrentPage(totalPages)}
+              disabled={currentPage === totalPages}
+              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
+            >
+              <FontAwesomeIcon icon={faAngleDoubleRight} className="w-4 h-4" />
+            </button>
+            <span className="ml-4 text-sm text-muted-foreground">
+              {t('last', 'Последна')}
+            </span>
+          </div>
+
+          <div className="text-sm text-muted-foreground">
+            {t('total', 'Вкупно')}: {documents.length}
+          </div>
+        </div>
+
+        {/* Payment Info */}
+        <div className="bg-blue-50 border-t border-blue-100 p-4">
+          <div className="flex items-start gap-3">
+            <FontAwesomeIcon icon={faMoneyBillWave} className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
+            <p className="text-sm text-blue-800 leading-relaxed">
+              {t('documents_payment_info', paymentInfo)}
+            </p>
+          </div>
+        </div>
+      </div>
+
+      {/* Statistics Cards */}
+      <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-blue-100 text-blue-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faFileText} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('total_documents', 'Вкупно документи')}</h3>
+              <p className="text-2xl font-bold text-blue-600">
+                {documents.length}
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-green-100 text-green-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('approved', 'Одобрени')}</h3>
+              <p className="text-2xl font-bold text-green-600">
+                {documents.filter(doc => doc.status === "approved").length}
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-yellow-100 text-yellow-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faMoneyBillWave} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('total_price', 'Вкупна цена')}</h3>
+              <p className="text-2xl font-bold text-yellow-600">
+                {documents.reduce((sum, doc) => sum + doc.price, 0).toFixed(2)} {t('mkd', 'мкд')}
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/students/exams/page.tsx
===================================================================
--- frontend/src/app/students/exams/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/exams/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,7 @@
+import Exams from "@/components/exams";
+
+export default function ExamsPage() {
+  return (
+    <Exams></Exams>
+  );
+}
Index: frontend/src/app/students/layout.tsx
===================================================================
--- frontend/src/app/students/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/layout.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,40 @@
+import type { Metadata } from "next";
+import { Geist, Geist_Mono } from "next/font/google";
+import "../globals.css";
+import "@fortawesome/fontawesome-svg-core/styles.css";
+import { config } from "@fortawesome/fontawesome-svg-core";
+import Header from "@/components/header";
+import Navbar from "@/components/navbar";
+
+// Prevent FontAwesome from adding CSS automatically
+config.autoAddCss = false;
+
+const geistSans = Geist({
+  variable: "--font-geist-sans",
+  subsets: ["latin"],
+});
+
+const geistMono = Geist_Mono({
+  variable: "--font-geist-mono",
+  subsets: ["latin"],
+});
+
+export const metadata: Metadata = {
+  title: "IKnow - UKIM",
+  description:
+    "University Managment System used to provide students informations and manage their progress.",
+};
+
+export default function RootLayout({
+  children,
+}: Readonly<{
+  children: React.ReactNode;
+}>) {
+  return (
+    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
+      <Header />
+      <Navbar />
+      {children}
+    </div>
+  );
+}
Index: frontend/src/app/students/page.tsx
===================================================================
--- frontend/src/app/students/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,5 @@
+import { redirect } from "next/navigation";
+
+export default function StudentsHome() {
+  redirect("/students/profile");
+}
Index: frontend/src/app/students/profile/page.tsx
===================================================================
--- frontend/src/app/students/profile/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/profile/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,338 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { 
+  faUser, 
+  faIdCard, 
+  faGraduationCap, 
+  faAddressCard, 
+  faSchool,
+  faCalendarAlt,
+  faFlag,
+  faVenus,
+  faMars,
+  faEnvelope,
+  faPhone,
+  faMapMarkerAlt,
+  faPassport
+} from '@fortawesome/free-solid-svg-icons';
+import { useEffect, useState } from 'react';
+import { getAccessToken } from '@/lib/auth';
+import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
+import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+
+type PersonalInfo = {
+  firstName: string;
+  middleName: string;
+  lastName: string;
+  maidenName: string;
+  dateOfBirth: string;
+  gender: string;
+  nationality: string;
+  citizenship: string;
+  scholarship: string;
+  currentPlan: string;
+  registryNumber: string;
+  studyGroup: string;
+  notes?: string;
+  index: string;
+  embg: string;
+};
+
+type BirthInfo = {
+  placeOfBirth: string;
+  municipalityOfBirth: string;
+  country: string;
+};
+
+type PreviousEducation = {
+  type: string;
+  profession: string;
+  average: string | number;
+  language: string;
+  country: string;
+  previousUniversity: string;
+  previousFaculty: string;
+  previousStudyMode: string;
+};
+
+type EnrollmentInfo = {
+  enrollmentYear: string | number;
+  status: string;
+  cycle: string;
+  program: string;
+  quota: string;
+  secondaryEducationNumber: string;
+  previousEducationCredits: string | number;
+};
+
+type Contact = {
+  placeOfResidence: string;
+  municipalityOfResidence: string;
+  country: string;
+  address: string;
+  temporaryAddress: string;
+  phone: string;
+  mobilePhone: string;
+  passportNumber: string;
+  passportExpiryDate: string;
+  email: string;
+  microsoftEmail: string;
+};
+
+type StudentProfile = {
+  personalInfo: PersonalInfo;
+  birthInfo: BirthInfo;
+  previousEducation: PreviousEducation;
+  enrollmentInfo: EnrollmentInfo;
+  contact: Contact;
+};
+
+interface InfoRowProps {
+  label: string;
+  value: string | number;
+  icon?: IconDefinition;
+}
+
+const InfoRow = ({ label, value, icon }: InfoRowProps) => {
+  const { t } = useTranslation();
+  return (
+    <div className="flex justify-between items-center py-3 border-b border-border last:border-b-0">
+      <div className="flex items-center gap-2 text-muted-foreground font-medium">
+        {icon && <FontAwesomeIcon icon={icon} className="w-4 h-4" />}
+        <span>{t(label)}:</span>
+      </div>
+      <div className="text-card-foreground font-semibold text-right max-w-xs break-words">
+        {value || t('n_a')}
+      </div>
+    </div>
+  );
+};
+
+interface SectionProps {
+  title: string;
+  icon: IconDefinition;
+  children: React.ReactNode;
+}
+
+const Section = ({ title, icon, children }: SectionProps) => {
+  const { t } = useTranslation();
+  return (
+    <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+      <div className="bg-primary text-white px-6 py-4">
+        <div className="flex items-center gap-3">
+          <FontAwesomeIcon icon={icon} className="text-xl" />
+          <h2 className="text-xl font-bold">{t(title)}</h2>
+        </div>
+      </div>
+      <div className="p-6">
+        {children}
+      </div>
+    </div>
+  );
+};
+
+export default function ProfilePage() {
+  const [studentData, setStudentData] = useState<StudentProfile | null>(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const { t } = useTranslation();
+
+  useEffect(() => {
+    let cancelled = false;
+
+    async function load() {
+      setIsLoading(true);
+      setErrorMessage(null);
+
+      const token = getAccessToken();
+      if (!token) {
+        setErrorMessage('Not authenticated. Please login again.');
+        setIsLoading(false);
+        return;
+      }
+
+      try {
+        const response = await fetch(apiUrl('/api/user/getUser'), {
+          method: 'GET',
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        });
+
+        if (!response.ok) {
+          const text = await response.text().catch(() => '');
+          throw new Error(text || `Failed to load profile (${response.status})`);
+        }
+
+        const data = (await response.json()) as StudentProfile;
+        if (!cancelled) setStudentData(data);
+      } catch (err) {
+        if (!cancelled) {
+          setErrorMessage(err instanceof Error ? err.message : 'Failed to load profile.');
+        }
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    }
+
+    void load();
+
+    return () => {
+      cancelled = true;
+    };
+  }, []);
+
+  if (isLoading) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="bg-card rounded-xl shadow-sm border border-border p-6">
+          {t('loading')}
+        </div>
+      </div>
+    );
+  }
+
+  if (errorMessage || !studentData) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
+          {errorMessage ?? t('failed_to_load_profile')}
+        </div>
+      </div>
+    );
+  }
+
+  const { personalInfo, birthInfo, previousEducation, enrollmentInfo, contact } = studentData;
+
+  return (
+    <div className="min-h-screen pb-8">
+      {/* Header */}
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <div className="flex items-center gap-6">
+          <div className="relative">
+            <div className="w-20 h-20 bg-white rounded-full flex items-center justify-center border-2 border-white shadow-lg">
+              <FontAwesomeIcon icon={faUser} className="text-3xl text-[#0272D1]" />
+            </div>
+            <div className="absolute -bottom-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-2 border-white"></div>
+          </div>
+          <div>
+            <h1 className="text-3xl font-bold mb-2">
+              {personalInfo.firstName} {personalInfo.middleName} {personalInfo.lastName}
+            </h1>
+            <div className="text-lg opacity-90">
+              {t('index')}: {personalInfo.index} | {t('embg')}: {personalInfo.embg}
+            </div>
+            <div className="text-base opacity-80 mt-1">
+              {enrollmentInfo.program}
+            </div>
+          </div>
+        </div>
+      </div>
+
+      {/* Profile Sections */}
+      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
+        
+        {/* Personal Information */}
+        <Section title="personal_info" icon={faIdCard}>
+          <InfoRow label="first_name" value={personalInfo.firstName} />
+          <InfoRow label="middle_name" value={personalInfo.middleName} />
+          <InfoRow label="last_name" value={personalInfo.lastName} />
+          <InfoRow label="maiden_name" value={personalInfo.maidenName} />
+          <InfoRow 
+            label="date_of_birth" 
+            value={personalInfo.dateOfBirth} 
+            icon={faCalendarAlt} 
+          />
+          <InfoRow 
+            label="gender" 
+            value={personalInfo.gender} 
+            icon={personalInfo.gender === t('male') ? faMars : faVenus} 
+          />
+          <InfoRow 
+            label="nationality" 
+            value={personalInfo.nationality} 
+            icon={faFlag} 
+          />
+          <InfoRow label="citizenship" value={personalInfo.citizenship} />
+          <InfoRow label="scholarship" value={personalInfo.scholarship} />
+          <InfoRow label="current_plan" value={personalInfo.currentPlan} />
+          <InfoRow label="registry_number" value={personalInfo.registryNumber} />
+          <InfoRow label="study_group" value={personalInfo.studyGroup} />
+          {personalInfo.notes && (
+            <div className="mt-4 p-4 bg-blue-50 rounded-lg">
+              <div className="text-sm font-medium text-blue-800 mb-1">{t('note')}:</div>
+              <div className="text-sm text-blue-700">{personalInfo.notes}</div>
+            </div>
+          )}
+        </Section>
+
+        {/* Birth Information */}
+        <Section title="birth_info" icon={faMapMarkerAlt}>
+          <InfoRow label="place_of_birth" value={birthInfo.placeOfBirth} />
+          <InfoRow label="municipality_of_birth" value={birthInfo.municipalityOfBirth} />
+          <InfoRow label="country" value={birthInfo.country} />
+        </Section>
+
+        {/* Previous Education */}
+        <Section title="previous_education" icon={faSchool}>
+          <InfoRow label="type" value={previousEducation.type} />
+          <InfoRow label="profession" value={previousEducation.profession} />
+          <InfoRow label="average" value={previousEducation.average} />
+          <InfoRow label="language" value={previousEducation.language} />
+          <InfoRow label="country" value={previousEducation.country} />
+          <InfoRow label="previous_university" value={previousEducation.previousUniversity} />
+          <InfoRow label="previous_faculty" value={previousEducation.previousFaculty} />
+          <InfoRow label="previous_study_mode" value={previousEducation.previousStudyMode} />
+        </Section>
+
+        {/* Enrollment Information */}
+        <Section title="enrollment_info" icon={faGraduationCap}>
+          <InfoRow label="enrollment_year" value={enrollmentInfo.enrollmentYear} />
+          <InfoRow label="status" value={enrollmentInfo.status} />
+          <InfoRow label="cycle" value={enrollmentInfo.cycle} />
+          <InfoRow label="program" value={enrollmentInfo.program} />
+          <InfoRow label="quota" value={enrollmentInfo.quota} />
+          <InfoRow label="secondary_education_number" value={enrollmentInfo.secondaryEducationNumber} />
+          <InfoRow label="previous_education_credits" value={enrollmentInfo.previousEducationCredits} />
+        </Section>
+
+        {/* Contact Information */}
+        <div className="lg:col-span-2">
+          <Section title="contact" icon={faAddressCard}>
+            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+              <div>
+                <InfoRow 
+                  label="place_of_residence" 
+                  value={contact.placeOfResidence} 
+                  icon={faMapMarkerAlt} 
+                />
+                <InfoRow label="municipality_of_residence" value={contact.municipalityOfResidence} />
+                <InfoRow label="country" value={contact.country} />
+                <InfoRow label="address" value={contact.address} />
+                <InfoRow label="temporary_address" value={contact.temporaryAddress} />
+              </div>
+              <div>
+                <InfoRow label="phone" value={contact.phone} icon={faPhone} />
+                <InfoRow label="mobile_phone" value={contact.mobilePhone} icon={faPhone} />
+                <InfoRow label="passport_number" value={contact.passportNumber} icon={faPassport} />
+                <InfoRow label="passport_expiry_date" value={contact.passportExpiryDate} />
+                <InfoRow 
+                  label="email" 
+                  value={contact.email} 
+                  icon={faEnvelope} 
+                />
+                <InfoRow 
+                  label="microsoft_email" 
+                  value={contact.microsoftEmail} 
+                  icon={faEnvelope} 
+                />
+              </div>
+            </div>
+          </Section>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/app/students/semesters/page.tsx
===================================================================
--- frontend/src/app/students/semesters/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/semesters/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,397 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { 
+  faCalendarAlt, 
+  faCheck, 
+  faTimes, 
+  faFileAlt, 
+  faMoneyBillWave,
+  faSignature,
+  faCheckCircle,
+  faTimesCircle
+} from '@fortawesome/free-solid-svg-icons';
+import { useEffect, useState } from 'react';
+import { getAccessToken } from '@/lib/auth';
+import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+import EnrollSemesterDialog from '@/components/enroll-semester-dialog';
+
+type Semester = {
+  id: number | string;
+  semester: string;
+  direction: string;
+  quota: string;
+  note: string;
+  studentCom: string;
+  sum: string;
+  paid: string;
+  ukim: string;
+  createdOn: string;
+  dateChanged: string;
+  credits: string;
+  type: string;
+  doc: string;
+  doc1: string;
+  verified: string;
+  taxes: string;
+  signatures: string;
+  status: string;
+  completed: string;
+};
+
+type SemestersResponse = {
+  semesters: Semester[];
+};
+
+interface TableCellProps {
+  children: React.ReactNode;
+  className?: string;
+}
+
+const TableCell = ({ children, className = "" }: TableCellProps) => (
+  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
+    {children}
+  </td>
+);
+
+const StatusBadge = ({ status }: { status: string }) => {
+  const { t } = useTranslation();
+  const baseClasses = "px-2 py-1 rounded-full text-xs font-medium";
+  if (status === 'Валидно') {
+    return (
+      <span className={`${baseClasses} bg-green-100 text-green-800 flex items-center gap-1`}>
+        <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
+        {t('Валидно', 'Валидно')}
+      </span>
+    );
+  }
+  return (
+    <span className={`${baseClasses} bg-accent text-gray-800`}>
+      {t(status, status)}
+    </span>
+  );
+};
+
+const YesNoBadge = ({ value }: { value: string }) => {
+  const { t } = useTranslation();
+  if (value === 'Да') {
+    return (
+      <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full">
+        <FontAwesomeIcon icon={faCheck} className="w-3 h-3" />
+      </span>
+    );
+  } else if (value === 'Не') {
+    return (
+      <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full">
+        <FontAwesomeIcon icon={faTimes} className="w-3 h-3" />
+      </span>
+    );
+  }
+  return <span className="text-muted-foreground">—</span>;
+};
+
+const SignatureBadge = ({ signatures }: { signatures: string }) => {
+  const [completed, total] = signatures.split('/').map(Number);
+  const percentage = total > 0 ? (completed / total) * 100 : 0;
+  
+  let colorClass = "text-red-600 bg-red-100";
+  if (percentage === 100) {
+    colorClass = "text-green-600 bg-green-100";
+  } else if (percentage >= 50) {
+    colorClass = "text-yellow-600 bg-yellow-100";
+  }
+  
+  return (
+    <span className={`px-2 py-1 rounded-full text-xs font-medium flex items-center gap-1 ${colorClass}`}>
+      <FontAwesomeIcon icon={faSignature} className="w-3 h-3" />
+      {signatures}
+    </span>
+  );
+};
+
+export default function SemestersPage() {
+  const [semesters, setSemesters] = useState<Semester[]>([]);
+  const [isLoading, setIsLoading] = useState(true);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const [enrollOpen, setEnrollOpen] = useState(false);
+  // Bumped after a successful enrolment so the table reloads.
+  const [reloadKey, setReloadKey] = useState(0);
+  const { t } = useTranslation();
+
+  useEffect(() => {
+    let cancelled = false;
+
+    async function load() {
+      setIsLoading(true);
+      setErrorMessage(null);
+
+      const token = getAccessToken();
+      if (!token) {
+        setErrorMessage('Not authenticated. Please login again.');
+        setIsLoading(false);
+        return;
+      }
+
+      try {
+        const response = await fetch(apiUrl('/api/user/getSemesters'), {
+          method: 'GET',
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        });
+
+        if (!response.ok) {
+          const text = await response.text().catch(() => '');
+          throw new Error(text || `Failed to load semesters (${response.status})`);
+        }
+
+        const data = (await response.json()) as SemestersResponse;
+        if (!cancelled) setSemesters(Array.isArray(data?.semesters) ? data.semesters : []);
+      } catch (err) {
+        if (!cancelled) {
+          setErrorMessage(err instanceof Error ? err.message : 'Failed to load semesters.');
+        }
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    }
+
+    void load();
+
+    return () => {
+      cancelled = true;
+    };
+  }, [reloadKey]);
+
+  if (isLoading) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="bg-card rounded-xl shadow-sm border border-border p-6">
+          {t('loading')}
+        </div>
+      </div>
+    );
+  }
+
+  if (errorMessage) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
+          {errorMessage}
+        </div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      {/* Header */}
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
+          <div className="flex items-center gap-4">
+            <div className="bg-white rounded-full p-4">
+              <FontAwesomeIcon icon={faCalendarAlt} className="text-3xl text-[#0272D1]" />
+            </div>
+            <div>
+              <h1 className="text-3xl font-bold mb-2">{t('semesters')}</h1>
+              <p className="text-lg opacity-90">
+                {t('semesters_overview')}
+              </p>
+            </div>
+          </div>
+
+          <button
+            className="self-start rounded-lg bg-white px-5 py-3 font-semibold text-[#0272D1] shadow-sm hover:bg-white/90 md:self-auto"
+            onClick={() => setEnrollOpen(true)}
+          >
+            + {t('enroll_semester')}
+          </button>
+        </div>
+      </div>
+
+      {/* Table Container */}
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">{t('semesters_list')}</h2>
+        </div>
+        
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('semester')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('direction')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('quota')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('note')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('student_com')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('sum')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('paid')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('ukim')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('created_on')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date_changed')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('credits')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('type')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('doc')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('doc1')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('verified')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('taxes')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('signatures')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('status')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('completed')}</th>
+              </tr>
+            </thead>
+            <tbody className="divide-y divide-border">
+              {semesters.map((semester) => (
+                <tr key={semester.id} className="hover:bg-accent transition-colors">
+                  <TableCell className="font-medium text-card-foreground">{semester.id}</TableCell>
+                  <TableCell className="font-medium text-primary">{semester.semester}</TableCell>
+                  <TableCell>{semester.direction}</TableCell>
+                  <TableCell className="max-w-xs">
+                    <div className="truncate" title={semester.quota}>
+                      {semester.quota}
+                    </div>
+                  </TableCell>
+                  <TableCell>
+                    {semester.note ? (
+                      <span className="text-yellow-600 font-medium" title={semester.note}>
+                        {semester.note.length > 10 ? `${semester.note.substring(0, 10)}...` : semester.note}
+                      </span>
+                    ) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell>
+                    {semester.studentCom ? (
+                      <span className="text-blue-600 font-medium" title={semester.studentCom}>
+                        {semester.studentCom.length > 10 ? `${semester.studentCom.substring(0, 10)}...` : semester.studentCom}
+                      </span>
+                    ) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell className="font-medium">
+                    {semester.sum ? (
+                      <span className="text-green-600 flex items-center gap-1">
+                        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
+                        {semester.sum}
+                      </span>
+                    ) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell className="font-medium">
+                    {semester.paid ? (
+                      <span className="text-green-600 flex items-center gap-1">
+                        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
+                        {semester.paid}
+                      </span>
+                    ) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell className="font-medium">
+                    {semester.ukim ? (
+                      <span className="text-blue-600">{semester.ukim}</span>
+                    ) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell className="text-muted-foreground">{semester.createdOn}</TableCell>
+                  <TableCell className="text-muted-foreground">{semester.dateChanged}</TableCell>
+                  <TableCell className="font-medium text-primary">{semester.credits}</TableCell>
+                  <TableCell>
+                    <span className="px-2 py-1 bg-blue-100 text-blue-800 rounded-full text-xs font-medium">
+                      {semester.type}
+                    </span>
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <YesNoBadge value={semester.doc} />
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <YesNoBadge value={semester.doc1} />
+                  </TableCell>
+                  <TableCell className="text-center">
+                    <YesNoBadge value={semester.verified} />
+                  </TableCell>
+                  <TableCell className="font-medium text-green-600">{semester.taxes}</TableCell>
+                  <TableCell>
+                    <SignatureBadge signatures={semester.signatures} />
+                  </TableCell>
+                  <TableCell>
+                    <StatusBadge status={semester.status} />
+                  </TableCell>
+                  <TableCell>
+                    {semester.completed !== "Не" ? (
+                      <span className="text-green-600 font-medium flex items-center gap-1">
+                        <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
+                        {t(semester.completed, semester.completed)}
+                      </span>
+                    ) : (
+                      <span className="text-red-600 font-medium flex items-center gap-1">
+                        <FontAwesomeIcon icon={faTimesCircle} className="w-3 h-3" />
+                        {t('Не', 'Не')}
+                      </span>
+                    )}
+                  </TableCell>
+                </tr>
+              ))}
+            </tbody>
+          </table>
+        </div>
+      </div>
+
+      {/* Summary Cards */}
+      <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-green-100 text-green-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('completed_semesters')}</h3>
+              <p className="text-2xl font-bold text-green-600">
+                {semesters.filter(s => s.completed !== "Не").length}
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-blue-100 text-blue-600 rounded-full p-3">
+              <FontAwesomeIcon icon={faFileAlt} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('verified_semesters')}</h3>
+              <p className="text-2xl font-bold text-blue-600">
+                {semesters.filter(s => s.verified === "Да").length}
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+          <div className="flex items-center gap-4">
+            <div className="bg-primary text-white rounded-full p-3">
+              <FontAwesomeIcon icon={faCalendarAlt} className="text-xl" />
+            </div>
+            <div>
+              <h3 className="text-lg font-bold text-card-foreground">{t('total_semesters')}</h3>
+              <p className="text-2xl font-bold text-primary">
+                {semesters.length}
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <EnrollSemesterDialog
+        open={enrollOpen}
+        onClose={() => setEnrollOpen(false)}
+        onEnrolled={() => setReloadKey((k) => k + 1)}
+      />
+    </div>
+  );
+}
Index: frontend/src/app/students/subjects/page.tsx
===================================================================
--- frontend/src/app/students/subjects/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/app/students/subjects/page.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,529 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { 
+  faBook, 
+  faChevronDown,
+  faFileInvoice
+} from '@fortawesome/free-solid-svg-icons';
+import { useEffect, useState } from 'react';
+import { getAccessToken } from '@/lib/auth';
+import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+
+interface Subject {
+  id: number;
+  code: string;
+  hours: string;
+  kojPat: number;
+  name: string;
+  semester: number;
+  status: string;
+  signature: string;
+  group: string;
+  professor: string;
+}
+
+type SemesterInfo = {
+  id: number;
+  name: string;
+  status: string;
+  serviceNumber: string | number;
+};
+
+type FinancialInfo = {
+  sum: string | number;
+  paid: string;
+  due: string;
+  materialCosts: string;
+  credits: string;
+  MKSA: string;
+  electronicRegistration: string;
+  eUKIM: string;
+  bankProvision: string;
+  total: string;
+};
+
+type CurrentSemester = {
+  id: string;
+  name: string;
+  status: string;
+  serviceNumber: string | number;
+  ticketNumber: string;
+  debt: string;
+  financialInfo: FinancialInfo;
+};
+
+type SubjectsResponse = {
+  currentSemester: CurrentSemester;
+  semesters: SemesterInfo[];
+  subjectsBySemester: Record<string, Subject[]>;
+  semesterKeyById: Record<number, string>;
+};
+
+type ApiCurrentSemester = {
+  id: string;
+  name: string;
+  status: string;
+  serviceNumber: string | number;
+  ticketNumber: string;
+  debt: string;
+  financialInfo: {
+    sum: string | number;
+    paid: string;
+    due: string;
+    materialCosts: string;
+    credits: string;
+    totalCredits?: string;
+    mksa?: string;
+    MKSA?: string;
+    electronicRegistration: string;
+    eUKIM: string;
+    bankProvision: string;
+    total: string;
+  };
+};
+
+type ApiSubjectsResponse = {
+  semesters: SemesterInfo[];
+  currentSemester?: ApiCurrentSemester;
+  currentSemestar?: ApiCurrentSemester;
+  subjectsBySemester: Record<string, Subject[]>;
+};
+
+function normalizeKey(input: string) {
+  return input.toLowerCase().replace(/\s|\(|\)|\.|,/g, '');
+}
+
+function detectSeasonFromName(name: string): 'summer' | 'winter' | null {
+  const n = name.toLowerCase();
+  if (n.includes('летен')) return 'summer';
+  if (n.includes('зимски')) return 'winter';
+  return null;
+}
+
+function buildSemesterKeyById(semesters: SemesterInfo[], keys: string[]) {
+  const keyBySeason: Partial<Record<'summer' | 'winter', string>> = {};
+  for (const key of keys) {
+    const k = key.toLowerCase();
+    if (k.includes('summer')) keyBySeason.summer = key;
+    if (k.includes('winter')) keyBySeason.winter = key;
+  }
+
+  const mapping: Record<number, string> = {};
+  for (const s of semesters) {
+    const season = detectSeasonFromName(s.name);
+    const mapped = season ? keyBySeason[season] : undefined;
+    if (mapped) mapping[s.id] = mapped;
+  }
+
+  // Fallback: if we couldn't infer seasons, try matching by normalized names.
+  if (Object.keys(mapping).length === 0) {
+    for (const s of semesters) {
+      const ns = normalizeKey(s.name);
+      const match = keys.find((k) => normalizeKey(k).includes(ns) || ns.includes(normalizeKey(k)));
+      if (match) mapping[s.id] = match;
+    }
+  }
+
+  // Last resort: map in order.
+  if (Object.keys(mapping).length === 0) {
+    semesters.forEach((s, idx) => {
+      if (keys[idx]) mapping[s.id] = keys[idx];
+    });
+  }
+
+  return mapping;
+}
+
+interface TableCellProps {
+  children: React.ReactNode;
+  className?: string;
+}
+
+const TableCell = ({ children, className = "" }: TableCellProps) => (
+  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
+    {children}
+  </td>
+);
+
+const StatusBadge = ({ status }: { status: string }) => {
+  const { t } = useTranslation();
+  const baseClasses = "px-3 py-1 rounded-md text-xs font-medium";
+  if (status === t('mandatory_short')) {
+    return (
+      <span className={`${baseClasses} bg-blue-100 text-blue-800`}>
+        {t('mandatory_short')}
+      </span>
+    );
+  } else if (status === t('elective_short')) {
+    return (
+      <span className={`${baseClasses} bg-green-100 text-green-800`}>
+        {t('elective_short')}
+      </span>
+    );
+  }
+  return (
+    <span className={`${baseClasses} bg-accent text-gray-800`}>
+      {t(status) || status}
+    </span>
+  );
+};
+
+export default function SubjectsPage() {
+  const [subjectsData, setSubjectsData] = useState<SubjectsResponse | null>(null);
+  const [selectedSemester, setSelectedSemester] = useState<number | null>(null);
+  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+  const [isLoading, setIsLoading] = useState(true);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const { t } = useTranslation();
+
+  useEffect(() => {
+    let cancelled = false;
+
+    async function load() {
+      setIsLoading(true);
+      setErrorMessage(null);
+
+      const token = getAccessToken();
+      if (!token) {
+        setErrorMessage('Not authenticated. Please login again.');
+        setIsLoading(false);
+        return;
+      }
+
+      try {
+        const response = await fetch(apiUrl('/api/user/getSubjects'), {
+          method: 'GET',
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        });
+
+        if (!response.ok) {
+          const text = await response.text().catch(() => '');
+          throw new Error(text || `Failed to load subjects (${response.status})`);
+        }
+
+        const apiData = (await response.json()) as ApiSubjectsResponse;
+        if (cancelled) return;
+
+        const current = apiData.currentSemester ?? apiData.currentSemestar;
+        if (!current) {
+          throw new Error('Response missing currentSemestar/currentSemester');
+        }
+
+        const keys = Object.keys(apiData.subjectsBySemester ?? {});
+        const semesterKeyById = buildSemesterKeyById(apiData.semesters ?? [], keys);
+
+        const normalized: SubjectsResponse = {
+          semesters: apiData.semesters ?? [],
+          subjectsBySemester: apiData.subjectsBySemester ?? {},
+          semesterKeyById,
+          currentSemester: {
+            id: current.id,
+            name: current.name,
+            status: current.status,
+            serviceNumber: current.serviceNumber,
+            ticketNumber: current.ticketNumber,
+            debt: current.debt,
+            financialInfo: {
+              sum: current.financialInfo.sum,
+              paid: current.financialInfo.paid,
+              due: current.financialInfo.due,
+              materialCosts: current.financialInfo.materialCosts,
+              credits: current.financialInfo.credits,
+              MKSA: current.financialInfo.MKSA ?? current.financialInfo.mksa ?? '',
+              electronicRegistration: current.financialInfo.electronicRegistration,
+              eUKIM: current.financialInfo.eUKIM,
+              bankProvision: current.financialInfo.bankProvision,
+              total: current.financialInfo.total,
+            },
+          },
+        };
+
+        setSubjectsData(normalized);
+
+        setSelectedSemester((prev) => {
+          if (prev !== null) return prev;
+          const season = detectSeasonFromName(current.name);
+          if (season) {
+            const key = keys.find((k) => k.toLowerCase().includes(season));
+            if (key) {
+              const matchId = normalized.semesters.find((s) => normalized.semesterKeyById[s.id] === key)?.id;
+              if (typeof matchId === 'number') return matchId;
+            }
+          }
+          return normalized.semesters[0]?.id ?? null;
+        });
+      } catch (err) {
+        if (!cancelled) {
+          setErrorMessage(err instanceof Error ? err.message : 'Failed to load subjects.');
+        }
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    }
+
+    void load();
+
+    return () => {
+      cancelled = true;
+    };
+  }, []);
+
+  if (isLoading) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="bg-card rounded-xl shadow-sm border border-border p-6">
+          {t('loading')}
+        </div>
+      </div>
+    );
+  }
+
+  if (errorMessage || !subjectsData || selectedSemester === null) {
+    return (
+      <div className="min-h-screen pb-8">
+        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
+          {errorMessage ?? t('failed_to_load_subjects')}
+        </div>
+      </div>
+    );
+  }
+  
+  const currentSemesterData =
+    subjectsData.semesters.find((s) => s.id === selectedSemester) ?? subjectsData.semesters[0];
+  const semesterKey =
+    subjectsData.semesterKeyById[selectedSemester] ??
+    Object.keys(subjectsData.subjectsBySemester)[0];
+  const currentSubjects: Subject[] = semesterKey ? subjectsData.subjectsBySemester[semesterKey] || [] : [];
+  const { currentSemester } = subjectsData;
+
+  return (
+    <div className="min-h-screen pb-8">
+      {/* Header */}
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <div className="flex items-center gap-4">
+          <div className="bg-white rounded-full p-4">
+            <FontAwesomeIcon icon={faBook} className="text-3xl text-[#0272D1]" />
+          </div>
+          <div>
+            <h1 className="text-3xl font-bold mb-2">{t('subjects')}</h1>
+            <p className="text-lg opacity-90">
+              {t('subjects_overview')}
+            </p>
+          </div>
+        </div>
+      </div>
+
+      {/* Status and Selection Section */}
+      <div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
+        
+        {/* Left Column - Status and Dropdown */}
+        <div className="lg:col-span-1 space-y-6">
+          
+          {/* Status Card */}
+          <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+            <div className="text-sm text-muted-foreground mb-2">
+              {t('status')}: <span className="text-primary font-semibold">{t('enrolled_by_student')}</span>
+            </div>
+            <div className="text-sm text-muted-foreground">
+              {t('ticket_number')}: <span className="font-semibold">{currentSemester.ticketNumber}</span>
+            </div>
+          </div>
+
+          {/* Semester Selection */}
+          <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+            <div className="text-sm text-muted-foreground mb-2">
+              {t('debt_from_documents')}: <span className="font-semibold">{currentSemester.debt}</span>
+            </div>
+            
+            <div className="relative mt-4">
+              <label className="block text-sm font-medium text-muted-foreground mb-2">
+                {t('select_semester')}:
+              </label>
+              <div className="relative">
+                <button
+                  onClick={() => setIsDropdownOpen(!isDropdownOpen)}
+                  className="w-full bg-card border border-border rounded-lg px-4 py-3 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
+                >
+                  <div className="flex items-center justify-between">
+                    <span className="text-sm font-medium text-primary">
+                      {currentSemesterData.name}
+                    </span>
+                    <FontAwesomeIcon 
+                      icon={faChevronDown} 
+                      className={`w-4 h-4 text-muted-foreground transition-transform ${isDropdownOpen ? 'rotate-180' : ''}`}
+                    />
+                  </div>
+                </button>
+                
+                {isDropdownOpen && (
+                  <div className="absolute z-10 w-full mt-1 bg-card border border-border rounded-lg shadow-lg">
+                    {subjectsData.semesters.map((semester) => (
+                      <button
+                        key={semester.id}
+                        onClick={() => {
+                          setSelectedSemester(semester.id);
+                          setIsDropdownOpen(false);
+                        }}
+                        className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent first:rounded-t-lg last:rounded-b-lg"
+                      >
+                        <div className="font-medium text-card-foreground">{semester.name}</div>
+                        <div className="text-xs text-muted-foreground">{t('status')}: {semester.status}</div>
+                      </button>
+                    ))}
+                  </div>
+                )}
+              </div>
+            </div>
+
+            <div className="mt-4 text-sm">
+              <div className="text-primary font-medium">
+                {t('serial_number')}: {currentSemesterData.serviceNumber}
+              </div>
+            </div>
+          </div>
+
+          {/* Enrolled Subjects */}
+          <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
+            <h3 className="font-semibold text-card-foreground mb-3 flex items-center gap-2">
+              <FontAwesomeIcon icon={faBook} className="w-4 h-4 text-primary" />
+              {t('enrolled_subjects')}
+            </h3>
+            <div className="text-3xl font-bold text-primary">
+              {currentSubjects.length}
+            </div>
+          </div>
+        </div>
+
+        {/* Right Column - Financial Information */}
+        <div className="lg:col-span-2">
+          <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+            <div className="bg-primary text-white px-6 py-4">
+              <h2 className="text-xl font-bold flex items-center gap-2">
+                <FontAwesomeIcon icon={faFileInvoice} />
+                {t('financial_info')}
+              </h2>
+            </div>
+            
+            <div className="p-6">
+              <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+                
+                {/* Left Financial Column */}
+                <div className="space-y-4">
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('sum')}:</span>
+                    <span className="font-semibold text-primary">{currentSemester.financialInfo.sum}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('paid')}:</span>
+                    <span className="font-semibold text-green-600">{currentSemester.financialInfo.paid}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('due')}:</span>
+                    <span className="font-semibold text-red-600">{currentSemester.financialInfo.due}</span>
+                  </div>
+                  <div className="mt-4 p-4 bg-blue-50 rounded-lg">
+                    <div className="text-sm font-medium text-blue-800 mb-1">{t('material_costs')}:</div>
+                    <div className="text-sm text-blue-700">{t('material_costs_info')}</div>
+                  </div>
+                </div>
+
+                {/* Right Financial Column */}
+                <div className="space-y-4">
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('credits')}:</span>
+                    <span className="font-semibold text-primary">{currentSemester.financialInfo.credits}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('mksa')}:</span>
+                    <span className="font-semibold">{currentSemester.financialInfo.MKSA}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('electronic_registration')}:</span>
+                    <span className="font-semibold">{currentSemester.financialInfo.electronicRegistration}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('eukim')}:</span>
+                    <span className="font-semibold">{currentSemester.financialInfo.eUKIM}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-2 border-b border-border">
+                    <span className="text-muted-foreground">{t('bank_provision')}:</span>
+                    <span className="font-semibold">{currentSemester.financialInfo.bankProvision}</span>
+                  </div>
+                  <div className="flex justify-between items-center py-3 border-t-2 border-primary bg-primary bg-opacity-5 rounded-lg px-4">
+                    <span className="font-bold text-white">{t('total')}:</span>
+                    <span className="font-bold text-xl text-white">{currentSemester.financialInfo.total}</span>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      {/* Subjects Table */}
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">{t('subjects_list')}</h2>
+        </div>
+        
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('code')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('hours')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('which_time')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('subject')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('semester')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('status')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('signature')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('group')}</th>
+                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('professor')}</th>
+              </tr>
+            </thead>
+            <tbody className="divide-y divide-border">
+              {currentSubjects.map((subject: Subject) => (
+                <tr key={subject.id} className="hover:bg-accent transition-colors">
+                  <TableCell className="font-medium text-card-foreground">{subject.id}</TableCell>
+                  <TableCell className="font-mono text-sm text-primary font-medium">{subject.code}</TableCell>
+                  <TableCell className="font-medium">{subject.hours}</TableCell>
+                  <TableCell className="text-center font-medium">{subject.kojPat}</TableCell>
+                  <TableCell className="font-medium text-card-foreground max-w-xs">
+                    <div className="flex items-center gap-2">
+                      <FontAwesomeIcon icon={faBook} className="w-4 h-4 text-primary" />
+                      {t(subject.name, subject.name)}
+                    </div>
+                  </TableCell>
+                  <TableCell className="text-center font-medium text-primary">{t(subject.semester.toString(), subject.semester.toString())}</TableCell>
+                  <TableCell>
+                    <StatusBadge status={subject.status} />
+                  </TableCell>
+                  <TableCell className="text-center">
+                    {subject.signature ? t(subject.signature, subject.signature) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell className="text-center">
+                    {subject.group ? t(subject.group, subject.group) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                  <TableCell>
+                    {subject.professor ? t(subject.professor, subject.professor) : (
+                      <span className="text-muted-foreground">—</span>
+                    )}
+                  </TableCell>
+                </tr>
+              ))}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/components/LanguageSwitcher.tsx
===================================================================
--- frontend/src/components/LanguageSwitcher.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/LanguageSwitcher.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,29 @@
+"use client";
+import { useTranslation } from 'react-i18next';
+
+export default function LanguageSwitcher() {
+  const { i18n } = useTranslation();
+
+  const changeLanguage = (lng: string) => {
+    i18n.changeLanguage(lng);
+  };
+
+  return (
+    <div className="flex gap-2 items-center">
+      <button
+        onClick={() => changeLanguage('mk')}
+        className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'mk' ? 'border-primary text-primary bg-accent' : 'border-border text-muted-foreground bg-card hover:border-primary hover:text-primary'}`}
+        aria-label="Macedonian"
+      >
+        MK
+      </button>
+      <button
+        onClick={() => changeLanguage('en')}
+        className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'en' ? 'border-primary text-primary bg-accent' : 'border-border text-muted-foreground bg-card hover:border-primary hover:text-primary'}`}
+        aria-label="English"
+      >
+        EN
+      </button>
+    </div>
+  );
+}
Index: frontend/src/components/admin-navbar.tsx
===================================================================
--- frontend/src/components/admin-navbar.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/admin-navbar.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,67 @@
+"use client";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faBook, faCalendarPlus, faChalkboardUser, faBars, faTimes, faUserGear } from "@fortawesome/free-solid-svg-icons";
+import Link from "next/link";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+const AdminNavbar = () => {
+  const [isMenuOpen, setIsMenuOpen] = useState(false);
+  const toggleMenu = () => setIsMenuOpen((v) => !v);
+
+  const { t } = useTranslation();
+  const menuItems = [
+    { icon: faBook, label: t("admin_subjects"), href: "/admin/subjects" },
+    { icon: faCalendarPlus, label: t("admin_semesters"), href: "/admin/semesters" },
+    { icon: faChalkboardUser, label: t("admin_schedule"), href: "/admin/schedule" },
+  ];
+
+  return (
+    <>
+      {/* Desktop Navbar */}
+      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
+        {menuItems.map((item) => (
+          <Link key={item.href} href={item.href}>
+            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
+              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+              <span>{item.label}</span>
+            </div>
+          </Link>
+        ))}
+      </nav>
+
+      {/* Mobile Navbar */}
+      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
+        <div className="flex justify-between items-center p-4">
+          <div className="flex items-center gap-2 text-xl font-bold">
+            <FontAwesomeIcon icon={faUserGear} className="text-xl" />
+            {t("admin_portal")}
+          </div>
+          <button
+            onClick={toggleMenu}
+            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
+            aria-label="Toggle menu"
+          >
+            <FontAwesomeIcon icon={isMenuOpen ? faTimes : faBars} className="text-xl transition-transform duration-300" />
+          </button>
+        </div>
+
+        <div className={`overflow-hidden transition-all duration-300 ease-in-out ${isMenuOpen ? "max-h-64 opacity-100" : "max-h-0 opacity-0"}`}>
+          <div className="px-4 pb-4 space-y-2">
+            {menuItems.map((item) => (
+              <Link key={item.href} href={item.href}>
+                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
+                  <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+                  <span className="text-lg">{item.label}</span>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+      </nav>
+    </>
+  );
+};
+
+export default AdminNavbar;
Index: frontend/src/components/contact-bubble.tsx
===================================================================
--- frontend/src/components/contact-bubble.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/contact-bubble.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,176 @@
+"use client"
+
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faEnvelope, faTimes, faPaperPlane, faSpinner } from '@fortawesome/free-solid-svg-icons';
+
+export default function ContactBubble() {
+  const { t } = useTranslation();
+  const [isOpen, setIsOpen] = useState(false);
+  const [isSending, setIsSending] = useState(false);
+  const [sent, setSent] = useState(false);
+  const [form, setForm] = useState({ name: '', email: '', subject: '', message: '' });
+
+  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
+    setForm((prev) => ({ ...prev, [e.target.name]: e.target.value }));
+  };
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    setIsSending(true);
+    // Simulate sending
+    await new Promise((r) => setTimeout(r, 1200));
+    setIsSending(false);
+    setSent(true);
+    setTimeout(() => {
+      setSent(false);
+      setIsOpen(false);
+      setForm({ name: '', email: '', subject: '', message: '' });
+    }, 2500);
+  };
+
+  return (
+    <>
+      {/* Floating bubble */}
+      <button
+        onClick={() => setIsOpen(true)}
+        className={`fixed bottom-6 right-6 z-50 flex items-center gap-2 bg-primary hover:bg-blue-700 text-white px-5 py-3 rounded-full shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl ${isOpen ? 'scale-0 opacity-0' : 'scale-100 opacity-100'}`}
+        aria-label={t('contact_us', 'Контактирај нè')}
+      >
+        <FontAwesomeIcon icon={faEnvelope} className="w-5 h-5" />
+        <span className="font-medium text-sm">{t('contact_us', 'Контактирај нè')}</span>
+      </button>
+
+      {/* Backdrop */}
+      {isOpen && (
+        <div
+          className="fixed inset-0 z-50 bg-black/40 backdrop-blur-sm transition-opacity duration-300"
+          onClick={() => setIsOpen(false)}
+        />
+      )}
+
+      {/* Modal */}
+      <div
+        className={`fixed z-50 bottom-6 right-6 w-[380px] max-w-[calc(100vw-2rem)] bg-card border border-border rounded-2xl shadow-2xl transition-all duration-300 origin-bottom-right ${isOpen ? 'scale-100 opacity-100' : 'scale-0 opacity-0 pointer-events-none'}`}
+      >
+        {/* Modal header */}
+        <div className="bg-primary text-white rounded-t-2xl px-6 py-4 flex items-center justify-between">
+          <div className="flex items-center gap-3">
+            <FontAwesomeIcon icon={faEnvelope} className="w-5 h-5" />
+            <h2 className="text-lg font-bold">{t('contact_us', 'Контактирај нè')}</h2>
+          </div>
+          <button
+            onClick={() => setIsOpen(false)}
+            className="text-white/80 hover:text-white transition-colors p-1"
+            aria-label={t('close', 'Затвори')}
+          >
+            <FontAwesomeIcon icon={faTimes} className="w-5 h-5" />
+          </button>
+        </div>
+
+        {/* Modal body */}
+        <div className="p-6">
+          {sent ? (
+            <div className="text-center py-8">
+              <div className="w-16 h-16 bg-green-100 text-green-600 rounded-full flex items-center justify-center mx-auto mb-4">
+                <FontAwesomeIcon icon={faPaperPlane} className="w-7 h-7" />
+              </div>
+              <h3 className="text-lg font-bold text-card-foreground mb-1">
+                {t('contact_sent_title', 'Пораката е испратена!')}
+              </h3>
+              <p className="text-sm text-muted-foreground">
+                {t('contact_sent_desc', 'Ќе ви одговориме наскоро.')}
+              </p>
+            </div>
+          ) : (
+            <form onSubmit={handleSubmit} className="space-y-4">
+              {/* Name */}
+              <div>
+                <label className="block text-sm font-medium text-muted-foreground mb-1">
+                  {t('contact_name', 'Име и презиме')}
+                </label>
+                <input
+                  type="text"
+                  name="name"
+                  required
+                  value={form.name}
+                  onChange={handleChange}
+                  placeholder={t('contact_name_placeholder', 'Вашето име')}
+                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
+                />
+              </div>
+
+              {/* Email */}
+              <div>
+                <label className="block text-sm font-medium text-muted-foreground mb-1">
+                  {t('contact_email', 'Е-пошта')}
+                </label>
+                <input
+                  type="email"
+                  name="email"
+                  required
+                  value={form.email}
+                  onChange={handleChange}
+                  placeholder={t('contact_email_placeholder', 'example@email.com')}
+                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
+                />
+              </div>
+
+              {/* Subject */}
+              <div>
+                <label className="block text-sm font-medium text-muted-foreground mb-1">
+                  {t('contact_subject', 'Наслов')}
+                </label>
+                <input
+                  type="text"
+                  name="subject"
+                  required
+                  value={form.subject}
+                  onChange={handleChange}
+                  placeholder={t('contact_subject_placeholder', 'Тема на пораката')}
+                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
+                />
+              </div>
+
+              {/* Message */}
+              <div>
+                <label className="block text-sm font-medium text-muted-foreground mb-1">
+                  {t('contact_message', 'Порака')}
+                </label>
+                <textarea
+                  name="message"
+                  required
+                  rows={3}
+                  value={form.message}
+                  onChange={handleChange}
+                  placeholder={t('contact_message_placeholder', 'Напишете ја вашата порака...')}
+                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary resize-none"
+                />
+              </div>
+
+              {/* Submit */}
+              <button
+                type="submit"
+                disabled={isSending}
+                className="w-full bg-primary hover:bg-blue-700 text-white font-medium py-2.5 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2 disabled:opacity-60 disabled:cursor-not-allowed"
+              >
+                {isSending ? (
+                  <>
+                    <FontAwesomeIcon icon={faSpinner} className="w-4 h-4 animate-spin" />
+                    {t('contact_sending', 'Испраќа...')}
+                  </>
+                ) : (
+                  <>
+                    <FontAwesomeIcon icon={faPaperPlane} className="w-4 h-4" />
+                    {t('contact_send', 'Испрати')}
+                  </>
+                )}
+              </button>
+            </form>
+          )}
+        </div>
+      </div>
+    </>
+  );
+}
Index: frontend/src/components/enroll-semester-dialog.tsx
===================================================================
--- frontend/src/components/enroll-semester-dialog.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/enroll-semester-dialog.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,287 @@
+"use client";
+
+import { useEffect, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { apiUrl } from "@/lib/api";
+import { getAccessToken } from "@/lib/auth";
+
+type SubjectOption = {
+  id: number;
+  name?: string;
+  code?: string;
+  credits: number;
+  mandatorySemester: number;
+  alreadyPassed: boolean;
+};
+
+type MajorOption = {
+  id: number;
+  name?: string;
+  subjects: SubjectOption[];
+};
+
+type SemesterOption = {
+  id: number;
+  name?: string;
+  year: number;
+  type?: string;
+};
+
+type EnrollmentOptions = {
+  requiredSubjects: number;
+  semesters: SemesterOption[];
+  majors: MajorOption[];
+  defaultMajorId: number | null;
+};
+
+export default function EnrollSemesterDialog({
+  open,
+  onClose,
+  onEnrolled,
+}: {
+  open: boolean;
+  onClose: () => void;
+  onEnrolled: () => void;
+}) {
+  const { t } = useTranslation();
+
+  const [options, setOptions] = useState<EnrollmentOptions | null>(null);
+  const [loading, setLoading] = useState(false);
+  const [submitting, setSubmitting] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+
+  const [semesterId, setSemesterId] = useState<number | null>(null);
+  const [majorId, setMajorId] = useState<number | null>(null);
+  const [picked, setPicked] = useState<number[]>([]);
+
+  useEffect(() => {
+    if (!open) return;
+
+    let cancelled = false;
+
+    async function load() {
+      setLoading(true);
+      setError(null);
+      try {
+        const token = getAccessToken();
+        if (!token) throw new Error(t("enroll_not_signed_in"));
+
+        const res = await fetch(apiUrl("/api/enrollment/options"), {
+          cache: "no-store",
+          headers: { Authorization: `Bearer ${token}` },
+        });
+        if (!res.ok) throw new Error(`${t("enroll_options_failed")} (${res.status})`);
+
+        const data = (await res.json()) as EnrollmentOptions;
+        if (cancelled) return;
+
+        setOptions(data);
+        setSemesterId(data.semesters[0]?.id ?? null);
+        setMajorId(data.defaultMajorId ?? data.majors[0]?.id ?? null);
+        setPicked([]);
+      } catch (e) {
+        if (!cancelled) setError(e instanceof Error ? e.message : String(e));
+      } finally {
+        if (!cancelled) setLoading(false);
+      }
+    }
+
+    void load();
+    return () => {
+      cancelled = true;
+    };
+  }, [open, t]);
+
+  const required = options?.requiredSubjects ?? 5;
+
+  const subjects = useMemo(
+    () => options?.majors.find((m) => m.id === majorId)?.subjects ?? [],
+    [options, majorId],
+  );
+
+  function toggle(subjectId: number) {
+    setPicked((prev) => {
+      if (prev.includes(subjectId)) return prev.filter((id) => id !== subjectId);
+      if (prev.length >= required) return prev; // the cap is the point of the form
+      return [...prev, subjectId];
+    });
+  }
+
+  async function submit() {
+    setSubmitting(true);
+    setError(null);
+    try {
+      const token = getAccessToken();
+      if (!token) throw new Error(t("enroll_not_signed_in"));
+
+      const res = await fetch(apiUrl("/api/enrollment"), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+          Authorization: `Bearer ${token}`,
+        },
+        body: JSON.stringify({
+          SemesterId: semesterId,
+          MajorId: majorId,
+          SubjectIds: picked,
+        }),
+      });
+
+      const body = (await res.json()) as { ok: boolean; message?: string };
+      if (!res.ok || !body.ok) {
+        throw new Error(body.message || `${t("enroll_failed")} (${res.status})`);
+      }
+
+      onEnrolled();
+      onClose();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setSubmitting(false);
+    }
+  }
+
+  if (!open) return null;
+
+  const noSemestersLeft = !loading && options !== null && options.semesters.length === 0;
+  const canSubmit =
+    !submitting && semesterId !== null && majorId !== null && picked.length === required;
+
+  return (
+    <div
+      className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-black/50 p-4 sm:items-center"
+      role="dialog"
+      aria-modal="true"
+      onClick={onClose}
+    >
+      <div
+        className="w-full max-w-3xl rounded-xl border border-border bg-card shadow-lg"
+        onClick={(e) => e.stopPropagation()}
+      >
+        <div className="flex items-center justify-between rounded-t-xl bg-primary px-6 py-4 text-white">
+          <h2 className="text-xl font-bold">{t("enroll_semester")}</h2>
+          <button
+            className="rounded-lg px-3 py-1 text-sm hover:bg-white/20"
+            onClick={onClose}
+            aria-label={t("close")}
+          >
+            ✕
+          </button>
+        </div>
+
+        <div className="p-6">
+          {loading ? (
+            <p className="text-muted-foreground">{t("loading")}</p>
+          ) : noSemestersLeft ? (
+            <p className="text-muted-foreground">{t("enroll_no_semesters")}</p>
+          ) : (
+            <>
+              <div className="grid gap-4 sm:grid-cols-2">
+                <div className="flex flex-col">
+                  <label className="text-sm text-muted-foreground">{t("semester")}</label>
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2"
+                    value={semesterId ?? ""}
+                    onChange={(e) => setSemesterId(Number.parseInt(e.target.value, 10))}
+                  >
+                    {options?.semesters.map((s) => (
+                      <option key={s.id} value={s.id}>
+                        {s.name}
+                      </option>
+                    ))}
+                  </select>
+                </div>
+
+                <div className="flex flex-col">
+                  <label className="text-sm text-muted-foreground">{t("direction")}</label>
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2"
+                    value={majorId ?? ""}
+                    onChange={(e) => {
+                      setMajorId(Number.parseInt(e.target.value, 10));
+                      setPicked([]); // subjects differ per programme
+                    }}
+                  >
+                    {options?.majors.map((m) => (
+                      <option key={m.id} value={m.id}>
+                        {m.name}
+                      </option>
+                    ))}
+                  </select>
+                </div>
+              </div>
+
+              <div className="mt-6 flex items-center justify-between">
+                <h3 className="font-semibold text-card-foreground">{t("subjects")}</h3>
+                <span
+                  className={`text-sm font-medium ${
+                    picked.length === required ? "text-green-700" : "text-muted-foreground"
+                  }`}
+                >
+                  {picked.length} / {required}
+                </span>
+              </div>
+
+              <div className="mt-2 max-h-80 overflow-y-auto rounded-lg border border-border">
+                {subjects.map((s) => {
+                  const checked = picked.includes(s.id);
+                  const atLimit = !checked && picked.length >= required;
+                  return (
+                    <label
+                      key={s.id}
+                      className={`flex items-center gap-3 border-b border-border px-4 py-3 last:border-b-0 ${
+                        atLimit ? "opacity-50" : "cursor-pointer hover:bg-accent"
+                      }`}
+                    >
+                      <input
+                        type="checkbox"
+                        checked={checked}
+                        disabled={atLimit}
+                        onChange={() => toggle(s.id)}
+                      />
+                      <span className="flex-1">
+                        <span className="text-card-foreground">{s.name}</span>
+                        <span className="ml-2 font-mono text-xs text-muted-foreground">{s.code}</span>
+                        {s.alreadyPassed && (
+                          <span className="ml-2 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-800">
+                            {t("enroll_already_passed")}
+                          </span>
+                        )}
+                      </span>
+                      <span className="text-xs text-muted-foreground">
+                        {t("enroll_semester_short")} {s.mandatorySemester} · {s.credits} {t("enroll_credits")}
+                      </span>
+                    </label>
+                  );
+                })}
+              </div>
+            </>
+          )}
+
+          {error && (
+            <div className="mt-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
+              {error}
+            </div>
+          )}
+
+          <div className="mt-6 flex justify-end gap-3">
+            <button
+              className="rounded-lg border border-border px-4 py-2 text-sm font-medium"
+              onClick={onClose}
+              disabled={submitting}
+            >
+              {t("cancel")}
+            </button>
+            <button
+              className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+              onClick={() => void submit()}
+              disabled={!canSubmit}
+            >
+              {submitting ? t("loading") : t("enroll_confirm")}
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: frontend/src/components/exams.tsx
===================================================================
--- frontend/src/components/exams.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/exams.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,312 @@
+"use client"
+import { useEffect, useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faSort, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons';
+import { getAccessToken } from '@/lib/auth';
+import { apiUrl } from '@/lib/api';
+
+type PassedSubject = {
+  id: number;
+  subjectId: number;
+  code: string;
+  subject: string;
+  credits: number;
+  grade: number;
+  gradeText: string;
+  date: string; // DD.MM.YYYY
+  semester: string;
+  professor: string;
+};
+
+type PassedSubjectsResponse = {
+  passedSubjects: PassedSubject[];
+};
+
+type ExamRow = {
+  id: number;
+  code: string;
+  subject: string;
+  date: string;
+  semester: string;
+  credits: number;
+  grade: number;
+};
+
+const Exams = () => {
+  const { t } = useTranslation();
+  const [sortField, setSortField] = useState<'grade' | 'date' | null>(null);
+  const [sortOrder, setSortOrder] = useState<'asc' | 'desc' | null>(null);
+  const [exams, setExams] = useState<ExamRow[]>([]);
+  const [isLoading, setIsLoading] = useState(true);
+  const [errorMessage, setErrorMessage] = useState<string | null>(null);
+
+  useEffect(() => {
+    let cancelled = false;
+
+    async function load() {
+      setIsLoading(true);
+      setErrorMessage(null);
+
+      const token = getAccessToken();
+      if (!token) {
+        setErrorMessage('Not authenticated. Please login again.');
+        setIsLoading(false);
+        return;
+      }
+
+      try {
+        const response = await fetch(apiUrl('/api/user/getPassedSubjects'), {
+          method: 'GET',
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        });
+
+        if (!response.ok) {
+          const text = await response.text().catch(() => '');
+          throw new Error(text || `Failed to load passed subjects (${response.status})`);
+        }
+
+        const data = (await response.json()) as PassedSubjectsResponse;
+        const rows: ExamRow[] = (data?.passedSubjects ?? []).map((s) => ({
+          id: s.id,
+          code: s.code,
+          subject: s.subject,
+          date: s.date,
+          semester: s.semester,
+          credits: s.credits,
+          grade: s.grade,
+        }));
+
+        if (!cancelled) setExams(rows);
+      } catch (err) {
+        if (!cancelled) {
+          setErrorMessage(err instanceof Error ? err.message : 'Failed to load passed subjects.');
+        }
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    }
+
+    void load();
+
+    return () => {
+      cancelled = true;
+    };
+  }, []);
+
+  const stats = useMemo(() => {
+    const passed = exams.length;
+    const creditsCurrent = exams.reduce((sum, s) => sum + (typeof s.credits === 'number' ? s.credits : 0), 0);
+    const numericGrades = exams.map((e) => (typeof e.grade === 'number' ? e.grade : null)).filter((g): g is number => g !== null);
+    const average =
+      numericGrades.length > 0
+        ? numericGrades.reduce((sum, g) => sum + g, 0) / numericGrades.length
+        : 0;
+
+    const totalCredits = 240;
+    const totalExams = 40;
+    return {
+      average: Number.isFinite(average) ? Number(average.toFixed(2)) : 0,
+      credits: { current: creditsCurrent, total: totalCredits },
+      passed,
+      remaining: Math.max(0, totalExams - passed),
+    };
+  }, [exams]);
+
+  const getGradeColor = (grade: number) => {
+    if (grade >= 9) return "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20";
+    if (grade >= 8) return "bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 border-yellow-500/20";
+    if (grade >= 6) return "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20";
+    return "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20";
+  };
+
+  const handleSortByGrade = () => {
+    if (sortField === 'grade') {
+      if (sortOrder === 'desc') {
+        setSortOrder('asc');
+      } else if (sortOrder === 'asc') {
+        setSortField(null);
+        setSortOrder(null);
+      } else {
+        setSortOrder('desc');
+      }
+    } else {
+      setSortField('grade');
+      setSortOrder('desc');
+    }
+  };
+
+  const handleSortByDate = () => {
+    if (sortField === 'date') {
+      if (sortOrder === 'desc') {
+        setSortOrder('asc');
+      } else if (sortOrder === 'asc') {
+        setSortField(null);
+        setSortOrder(null);
+      } else {
+        setSortOrder('desc');
+      }
+    } else {
+      setSortField('date');
+      setSortOrder('desc');
+    }
+  };
+
+  const getSortedExams = () => {
+    if (!sortField || !sortOrder) return exams;
+    
+    return [...exams].sort((a, b) => {
+      if (sortField === 'grade') {
+        return sortOrder === 'asc' ? a.grade - b.grade : b.grade - a.grade;
+      }
+      
+      if (sortField === 'date') {
+        // Convert date strings to Date objects for proper sorting
+        const dateA = new Date(a.date.split('.').reverse().join('-')); // Convert DD.MM.YYYY to YYYY-MM-DD
+        const dateB = new Date(b.date.split('.').reverse().join('-'));
+        
+        return sortOrder === 'asc' ? dateA.getTime() - dateB.getTime() : dateB.getTime() - dateA.getTime();
+      }
+      
+      return 0;
+    });
+  };
+
+  const getSortIcon = (field: 'grade' | 'date') => {
+    if (sortField === field) {
+      if (sortOrder === 'asc') return faSortUp;
+      if (sortOrder === 'desc') return faSortDown;
+    }
+    return faSort;
+  };
+
+  const creditsPercentage = stats.credits.total > 0 ? (stats.credits.current / stats.credits.total) * 100 : 0;
+
+  if (isLoading) {
+    return (
+      <div className="bg-card rounded-lg shadow-sm p-6">
+        {t('loading', 'Loading...')}
+      </div>
+    );
+  }
+
+  if (errorMessage) {
+    return (
+      <div className="bg-card rounded-lg shadow-sm p-6">
+        <div className="rounded-lg border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-400">
+          {t('failed_to_load_exams', errorMessage)}
+        </div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="bg-card rounded-lg shadow-sm p-6 space-y-6">
+      {/* Statistics Section */}
+      <div className="space-y-4">
+        <div className="grid grid-cols-2 md:grid-cols-4 gap-6">
+          {/* Average Grade */}
+          <div className="text-center">
+            <div className="text-3xl font-bold text-card-foreground">{stats.average}</div>
+            <div className="text-sm text-muted-foreground mt-1">{t('average', 'Просек')}</div>
+          </div>
+
+          {/* Credits */}
+          <div className="text-center">
+            <div className="text-3xl font-bold text-card-foreground">
+              {stats.credits.current}
+              <span className="text-lg text-muted-foreground">/{stats.credits.total}</span>
+            </div>
+            <div className="text-sm text-muted-foreground mt-1">{t('credits', 'Кредити')}</div>
+          </div>
+
+          {/* Passed Exams */}
+          <div className="text-center">
+            <div className="text-3xl font-bold text-card-foreground">{stats.passed}</div>
+            <div className="text-sm text-muted-foreground mt-1">{t('passed', 'Положени')}</div>
+          </div>
+
+          {/* Remaining Exams */}
+          <div className="text-center">
+            <div className="text-3xl font-bold text-card-foreground">{stats.remaining}</div>
+            <div className="text-sm text-muted-foreground mt-1">{t('remaining', 'Останато')}</div>
+          </div>
+        </div>
+
+        {/* Progress Bar spanning entire statistics section */}
+        <div className="w-full bg-secondary rounded-full h-2">
+          <div
+            className="bg-primary h-2 rounded-full transition-all duration-300"
+            style={{ width: `${creditsPercentage}%` }}
+          ></div>
+        </div>
+      </div>
+
+      {/* Exams Table */}
+      <div>
+        <h3 className="text-xl font-semibold text-card-foreground mb-4">{t('exams', 'Испити')}</h3>
+
+        <div className="overflow-x-auto">
+          <table className="min-w-full">
+            <thead>
+              <tr className="border-b border-border">
+                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">#</th>
+                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('subject', 'Предмет')}</th>
+                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('semester', 'Семестар')}</th>
+                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('credits', 'Кредити')}</th>
+                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">
+                  <button
+                    onClick={handleSortByDate}
+                    className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-accent hover:text-accent-foreground transition-all duration-200 transform hover:scale-105"
+                  >
+                    {t('date', 'Датум')}
+                    <FontAwesomeIcon
+                      icon={getSortIcon('date')}
+                      className={`text-xs transition-colors duration-200 ${
+                        sortField === 'date' ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground'
+                      }`}
+                    />
+                  </button>
+                </th>
+                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">
+                  <button
+                    onClick={handleSortByGrade}
+                    className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-accent hover:text-accent-foreground transition-all duration-200 transform hover:scale-105"
+                  >
+                    {t('grade', 'Оценка')}
+                    <FontAwesomeIcon
+                      icon={getSortIcon('grade')}
+                      className={`text-xs transition-colors duration-200 ${
+                        sortField === 'grade' ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground'
+                      }`}
+                    />
+                  </button>
+                </th>
+              </tr>
+            </thead>
+            <tbody className="divide-y divide-border">
+              {getSortedExams().map((exam) => (
+                <tr key={exam.id} className="hover:bg-accent/50 transition-colors duration-150">
+                  <td className="py-4 px-4 text-sm text-card-foreground">{exam.id}</td>
+                  <td className="py-4 px-4 text-sm text-card-foreground font-medium">{t(exam.subject, exam.subject)}</td>
+                  <td className="py-4 px-4 text-sm text-muted-foreground">{t(exam.semester, exam.semester)}</td>
+                  <td className="py-4 px-4 text-sm text-muted-foreground">{exam.credits}</td>
+                  <td className="py-4 px-4 text-sm text-muted-foreground">{exam.date}</td>
+                  <td className="py-4 px-4">
+                    <span className={`inline-flex items-center px-2.5 py-1 rounded-md text-sm font-medium border ${getGradeColor(exam.grade)}`}>
+                      {exam.grade}
+                    </span>
+                  </td>
+                </tr>
+              ))}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default Exams;
Index: frontend/src/components/header.tsx
===================================================================
--- frontend/src/components/header.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/header.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,114 @@
+"use client"
+
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faUser } from '@fortawesome/free-solid-svg-icons';
+import Image from 'next/image';
+
+import { useEffect, useState } from 'react';
+import { getAccessToken, clearAuthTokens } from '@/lib/auth';
+import { useTranslation } from 'react-i18next';
+import LanguageSwitcher from './LanguageSwitcher';
+import { apiUrl } from '@/lib/api';
+
+const Header = () => {
+
+  const [userName, setUserName] = useState<string>('');
+  const { t } = useTranslation();
+
+  useEffect(() => {
+    async function fetchUser() {
+      const token = getAccessToken();
+      if (!token) return;
+      try {
+        const response = await fetch(apiUrl('/api/user/getUser'), {
+          method: 'GET',
+          headers: { Authorization: `Bearer ${token}` },
+        });
+        if (!response.ok) return;
+        const data = await response.json();
+        // Try both student and professor shape
+        if (data?.personalInfo) {
+          const p = data.personalInfo;
+          setUserName([p.firstName, p.middleName, p.lastName].filter(Boolean).join(' '));
+        }
+      } catch {}
+    }
+    fetchUser();
+    return () => {};
+  }, []);
+
+  const handleLogout = () => {
+    clearAuthTokens();
+    if (typeof window !== 'undefined') {
+      window.location.href = '/';
+    }
+  };
+
+  return (
+    <header className="bg-card shadow-sm border-b border-border">
+      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
+        <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center py-4 gap-4 sm:gap-0">
+          {/* Left side - Logos and University Info */}
+          <div className="flex items-center gap-2 justify-center sm:justify-start">
+            {/* UKIM Logo */}
+            <div className="flex-shrink-0">
+              <Image
+                src="/ukim-logo.png"
+                alt="UKIM Logo"
+                width={40}
+                height={40}
+                className="h-10 w-auto"
+              />
+            </div>
+            {/* FINKI Logo */}
+            <div className="flex-shrink-0">
+              <Image
+                src="/finki-logo.png"
+                alt="FINKI Logo"
+                width={40}
+                height={40}
+                className="h-10 w-auto"
+              />
+            </div>
+            {/* University Text */}
+            <div className="hidden sm:block">
+              <div className="text-card-foreground font-medium text-sm">
+                {t('university')}
+              </div>
+              <div className="text-muted-foreground text-sm">
+                {t('faculty')}
+              </div>
+            </div>
+          </div>
+          {/* Right side - User Profile */}
+          <div className="flex flex-col sm:flex-row items-center gap-2 sm:gap-4 w-full sm:w-auto justify-center sm:justify-end">
+            {/* Language Switcher - now left of user info */}
+            <div className="sm:mr-2 w-full sm:w-auto flex justify-center sm:justify-end">
+              <LanguageSwitcher />
+            </div>
+            <div className="flex items-center gap-2 sm:gap-3 w-full sm:w-auto justify-center sm:justify-end">
+              {/* User Avatar */}
+              <div className="hidden sm:flex items-center justify-center w-10 h-10 bg-primary text-primary-foreground rounded-full">
+                <FontAwesomeIcon icon={faUser} className="text-sm" />
+              </div>
+              {/* User Name */}
+              <div className="hidden sm:block text-card-foreground font-medium">
+                {userName || '...'}
+              </div>
+              {/* Logout Button - more stylish and full width on mobile */}
+              <button
+                className="w-full sm:w-auto ml-0 sm:ml-2 px-4 py-2 border-2 border-primary text-primary bg-card rounded-lg font-semibold flex items-center justify-center gap-2 hover:bg-accent transition-all duration-200 shadow-sm"
+                onClick={handleLogout}
+              >
+                <svg xmlns='http://www.w3.org/2000/svg' className='h-4 w-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'><path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a2 2 0 01-2 2H7a2 2 0 01-2-2V7a2 2 0 012-2h4a2 2 0 012 2v1' /></svg>
+                {t('logout')}
+              </button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </header>
+  );
+};
+
+export default Header;
Index: frontend/src/components/navbar.tsx
===================================================================
--- frontend/src/components/navbar.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/navbar.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,86 @@
+"use client"
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faUser } from '@fortawesome/free-solid-svg-icons';
+import { faBookmark } from '@fortawesome/free-solid-svg-icons';
+import { faBook } from '@fortawesome/free-solid-svg-icons';
+import { faPenToSquare } from '@fortawesome/free-solid-svg-icons';
+import { faListCheck } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf } from '@fortawesome/free-solid-svg-icons';
+import { faBars, faTimes, faGraduationCap } from '@fortawesome/free-solid-svg-icons';
+import { useState } from 'react';
+import Link from 'next/link';
+import { useTranslation } from 'react-i18next';
+
+const Navbar = () => {
+  const [isMenuOpen, setIsMenuOpen] = useState(false);
+
+  const toggleMenu = () => {
+    setIsMenuOpen(!isMenuOpen);
+  };
+
+  const { t } = useTranslation();
+  const menuItems = [
+    { icon: faUser, label: t('profile'), href: '/students/profile' },
+    { icon: faBookmark, label: t('semesters'), href: '/students/semesters' },
+    { icon: faBook, label: t('subjects'), href: '/students/subjects' },
+    { icon: faPenToSquare, label: t('applications'), href: '/students/applications' },
+    { icon: faListCheck, label: t('exams'), href: '/students/exams' },
+    { icon: faFilePdf, label: t('documents'), href: '/students/documents' }
+  ];
+
+  return (
+    <>
+      {/* Desktop Navbar */}
+      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
+        {menuItems.map((item, index) => (
+          <Link key={index} href={item.href}>
+            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
+              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+              <span>{item.label}</span>
+            </div>
+          </Link>
+        ))}
+      </nav>
+
+      {/* Mobile Navbar */}
+      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
+        <div className="flex justify-between items-center p-4">
+          {/* IKnow Logo/Text */}
+          <div className="flex items-center gap-2 text-xl font-bold">
+            <FontAwesomeIcon icon={faGraduationCap} className="text-xl" />
+            IKnow
+          </div>
+          
+          {/* Hamburger Menu Button */}
+          <button
+            onClick={toggleMenu}
+            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
+          >
+            <FontAwesomeIcon 
+              icon={isMenuOpen ? faTimes : faBars} 
+              className="text-xl transition-transform duration-300"
+            />
+          </button>
+        </div>
+
+        {/* Mobile Menu Items */}
+        <div className={`overflow-hidden transition-all duration-300 ease-in-out ${
+          isMenuOpen ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
+        }`}>
+          <div className="px-4 pb-4 space-y-2">
+            {menuItems.map((item, index) => (
+              <Link key={index} href={item.href}>
+                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
+                  <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+                  <span className="text-lg">{item.label}</span>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+      </nav>
+    </>
+  );
+};
+
+export default Navbar;
Index: frontend/src/components/professor-navbar.tsx
===================================================================
--- frontend/src/components/professor-navbar.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/professor-navbar.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,80 @@
+"use client";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faUser, faUsers, faBars, faTimes, faChalkboardUser } from "@fortawesome/free-solid-svg-icons";
+import Link from "next/link";
+import { useState } from "react";
+import { useTranslation } from 'react-i18next';
+
+const ProfessorNavbar = () => {
+  const [isMenuOpen, setIsMenuOpen] = useState(false);
+
+  const toggleMenu = () => {
+    setIsMenuOpen((v) => !v);
+  };
+
+  const { t } = useTranslation();
+  const menuItems = [
+    { icon: faUser, label: t('profile'), href: "/professor/profile" },
+    { icon: faUsers, label: t('students') || 'Студенти', href: "/professor/students" },
+  ];
+
+  return (
+    <>
+      {/* Desktop Navbar */}
+      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
+        {menuItems.map((item) => (
+          <Link key={item.href} href={item.href}>
+            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
+              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+              <span>{item.label}</span>
+            </div>
+          </Link>
+        ))}
+      </nav>
+
+      {/* Mobile Navbar */}
+      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
+        <div className="flex justify-between items-center p-4">
+          <div className="flex items-center gap-2 text-xl font-bold">
+            <FontAwesomeIcon icon={faChalkboardUser} className="text-xl" />
+            Professor
+          </div>
+
+          <button
+            onClick={toggleMenu}
+            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
+            aria-label="Toggle menu"
+          >
+            <FontAwesomeIcon
+              icon={isMenuOpen ? faTimes : faBars}
+              className="text-xl transition-transform duration-300"
+            />
+          </button>
+        </div>
+
+        <div
+          className={`overflow-hidden transition-all duration-300 ease-in-out ${
+            isMenuOpen ? "max-h-64 opacity-100" : "max-h-0 opacity-0"
+          }`}
+        >
+          <div className="px-4 pb-4 space-y-2">
+            {menuItems.map((item) => (
+              <Link key={item.href} href={item.href}>
+                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
+                  <FontAwesomeIcon
+                    icon={item.icon}
+                    className="transition-transform duration-300 group-hover:rotate-12"
+                  />
+                  <span className="text-lg">{item.label}</span>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+      </nav>
+    </>
+  );
+};
+
+export default ProfessorNavbar;
Index: frontend/src/components/theme-provider.tsx
===================================================================
--- frontend/src/components/theme-provider.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/theme-provider.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,8 @@
+"use client";
+
+import { ThemeProvider as NextThemesProvider } from "next-themes";
+import { type ThemeProviderProps } from "next-themes";
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+  return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
+}
Index: frontend/src/components/theme-toggle.tsx
===================================================================
--- frontend/src/components/theme-toggle.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/components/theme-toggle.tsx	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,37 @@
+"use client";
+
+import { Moon, Sun } from "lucide-react";
+import { useTheme } from "next-themes";
+import { useEffect, useState } from "react";
+
+export function ThemeToggle() {
+  const [mounted, setMounted] = useState(false);
+  const { theme, setTheme } = useTheme();
+
+  // Avoid hydration mismatch
+  useEffect(() => {
+    setMounted(true);
+  }, []);
+
+  if (!mounted) {
+    return (
+      <button className="p-2 rounded-md hover:bg-accent">
+        <Sun className="h-5 w-5" />
+      </button>
+    );
+  }
+
+  return (
+    <button
+      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
+      className="p-2 rounded-md hover:bg-accent transition-colors"
+      aria-label="Toggle theme"
+    >
+      {theme === "dark" ? (
+        <Sun className="h-5 w-5" />
+      ) : (
+        <Moon className="h-5 w-5" />
+      )}
+    </button>
+  );
+}
Index: frontend/src/data/applications.json
===================================================================
--- frontend/src/data/applications.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/data/applications.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,144 @@
+{
+  "examSessions": [
+    {
+      "id": "2025_summer_session2",
+      "name": "2025 (Летна) Втора испитна сесија",
+      "year": "2025",
+      "semester": "Летна",
+      "session": "Втора испитна сесија"
+    },
+    {
+      "id": "2025_summer_session1",
+      "name": "2025 (Летна) Прва испитна сесија",
+      "year": "2025",
+      "semester": "Летна",
+      "session": "Прва испитна сесија"
+    },
+    {
+      "id": "2025_winter_session2",
+      "name": "2025 (Зимска) Втора испитна сесија",
+      "year": "2025",
+      "semester": "Зимска",
+      "session": "Втора испитна сесија"
+    },
+    {
+      "id": "2025_winter_session1",
+      "name": "2025 (Зимска) Прва испитна сесија",
+      "year": "2025",
+      "semester": "Зимска",
+      "session": "Прва испитна сесија"
+    },
+    {
+      "id": "2024_summer_session2",
+      "name": "2024 (Летна) Втора испитна сесија",
+      "year": "2024",
+      "semester": "Летна",
+      "session": "Втора испитна сесија"
+    },
+    {
+      "id": "2024_summer_session1",
+      "name": "2024 (Летна) Прва испитна сесија",
+      "year": "2024",
+      "semester": "Летна",
+      "session": "Прва испитна сесија"
+    },
+    {
+      "id": "2024_winter_session2",
+      "name": "2024 (Зимска) Втора испитна сесија",
+      "year": "2024",
+      "semester": "Зимска",
+      "session": "Втора испитна сесија"
+    },
+    {
+      "id": "2024_winter_session1",
+      "name": "2024 (Зимска) Прва испитна сесија",
+      "year": "2024",
+      "semester": "Зимска",
+      "session": "Прва испитна сесија"
+    }
+  ],
+  "currentSession": {
+    "id": "2025_summer_session2",
+    "name": "2025 (Летна) Втора испитна сесија"
+  },
+  "applications": [
+    {
+      "id": 1,
+      "serviceNumber": "4684532",
+      "code": "F23L2W014",
+      "subject": "Компјутерски мрежи и безбедност",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Сашо Граматиков",
+      "decade": 1
+    },
+    {
+      "id": 2,
+      "serviceNumber": "4684531",
+      "code": "F23L2W167",
+      "subject": "Шаблони за дизајн на кориснички интерфејси",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Сузана Лошковска",
+      "decade": 1
+    },
+    {
+      "id": 3,
+      "serviceNumber": "4684530",
+      "code": "F23L3S100",
+      "subject": "Деловна пракса",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Александар Стојменски",
+      "decade": 1
+    },
+    {
+      "id": 4,
+      "serviceNumber": "4684529",
+      "code": "F23L2S026",
+      "subject": "Маркетинг",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Билјана Стојкоска",
+      "decade": 1
+    },
+    {
+      "id": 5,
+      "serviceNumber": "4684528",
+      "code": "F23L2S017",
+      "subject": "Оперативни системи",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Невена Ацковска",
+      "decade": 1
+    },
+    {
+      "id": 6,
+      "serviceNumber": "4684527",
+      "code": "F23L2S029",
+      "subject": "Софтверско инженерство",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Ѓорѓи Маџаров",
+      "decade": 1
+    },
+    {
+      "id": 7,
+      "serviceNumber": "4684526",
+      "code": "F23L2S030",
+      "subject": "Вештачка интелигенција",
+      "completed": "Не",
+      "fee": "0,00",
+      "date": "21.05.2025",
+      "instructor": "Соња Гиевска",
+      "decade": 1
+    }
+  ],
+  "note": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички."
+}
Index: frontend/src/data/documents.json
===================================================================
--- frontend/src/data/documents.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/data/documents.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,185 @@
+{
+  "documentTypes": [
+    {
+      "id": "select_document",
+      "name": "Изберете документ",
+      "price": 0
+    },
+    {
+      "id": "administrative_regulation",
+      "name": "Барање за административно регулирање на ретроактивен семестар (од 2024г) ( 1000)",
+      "price": 1000
+    },
+    {
+      "id": "exam_application_satisfaction",
+      "name": "Барање за задочно пријавување на испит (од 2024г) ( 1000)",
+      "price": 1000
+    },
+    {
+      "id": "semester_enrollment_after_deadline",
+      "name": "Барање за запишување на семестар по истек на рок (од 2024г) ( 1500)",
+      "price": 1500
+    },
+    {
+      "id": "certificate_issuance_various",
+      "name": "Барање за издавање потврди по разни основи (од 2024г) ( 1500)",
+      "price": 1500
+    },
+    {
+      "id": "student_status_verification",
+      "name": "Барање за мирување на студиите (од 2024г) ( 2000)",
+      "price": 2000
+    },
+    {
+      "id": "diploma_thesis_postponement",
+      "name": "Барање за откажување на пријавена тема за дипломска работа (од 2024г) ( 1000)",
+      "price": 1000
+    },
+    {
+      "id": "diploma_package",
+      "name": "Барање за пакет за дипломирање (од 2024г) (6200)",
+      "price": 6200
+    },
+    {
+      "id": "exam_postponement",
+      "name": "Барање за поништување на испит (од 2024г) ( 2000)",
+      "price": 2000
+    },
+    {
+      "id": "regular_student_certificate",
+      "name": "Барање за потврда за редовен студент (хартиена) ( 100)",
+      "price": 100
+    },
+    {
+      "id": "study_continuation_verification",
+      "name": "Барање за продолжување на студии во мирување (од 2024г) ( 2000)",
+      "price": 2000
+    },
+    {
+      "id": "failed_subject_grade_change",
+      "name": "Барање за промена на изборен предмет (од 2024г) ( 1500)",
+      "price": 1500
+    },
+    {
+      "id": "passed_subject_grade_change",
+      "name": "Барање за промена на положен предмет (од 2024г) ( 0)",
+      "price": 0
+    },
+    {
+      "id": "study_program_change_same_accreditation",
+      "name": "Барање за промена на студиска програма од иста акредитација (од 2024г) ( 2000)",
+      "price": 2000
+    },
+    {
+      "id": "study_program_change_new_accreditation",
+      "name": "Барање за промена на студиска програма од понова акредитација (од 2024г) ( 3000)",
+      "price": 3000
+    },
+    {
+      "id": "diploma_supplement",
+      "name": "Додаток на диплома ( 0)",
+      "price": 0
+    },
+    {
+      "id": "diploma_supplement_second_cycle",
+      "name": "Додаток на диплома (втор циклус) ( 0)",
+      "price": 0
+    },
+    {
+      "id": "mksa",
+      "name": "МКСА ( 750)",
+      "price": 750
+    },
+    {
+      "id": "exam_recognition",
+      "name": "Признавање на положени испити ( 0)",
+      "price": 0
+    },
+    {
+      "id": "student_card_old",
+      "name": "Студентски картон (Старо) ( 0)",
+      "price": 0
+    }
+  ],
+  "documents": [
+    {
+      "id": 1,
+      "archive": "91008",
+      "date": "05.11.2024",
+      "request": "Уверение за положени испити ФИНКИ",
+      "price": 100.00,
+      "paid": "ДА",
+      "document": "Преземи",
+      "payOnline": true,
+      "status": "approved",
+      "comment": ""
+    },
+    {
+      "id": 2,
+      "archive": "91007",
+      "date": "05.11.2024",
+      "request": "УППИ образец",
+      "price": 0.00,
+      "paid": "ДА",
+      "document": "Преземи",
+      "payOnline": false,
+      "status": "approved",
+      "comment": ""
+    },
+    {
+      "id": 3,
+      "archive": "90494",
+      "date": "31.10.2024",
+      "request": "Уверение за редовен студент - ФИНКИ",
+      "price": 0.00,
+      "paid": "ДА",
+      "document": "Преземи",
+      "payOnline": false,
+      "status": "approved",
+      "comment": ""
+    },
+    {
+      "id": 4,
+      "archive": "84239",
+      "date": "10.03.2024",
+      "request": "Уверение за редовен студент - ФИНКИ",
+      "price": 0.00,
+      "paid": "ДА",
+      "document": "Преземи",
+      "payOnline": false,
+      "status": "approved",
+      "comment": ""
+    },
+    {
+      "id": 5,
+      "archive": "84238",
+      "date": "10.03.2024",
+      "request": "Уверение за положени испити ФИНКИ",
+      "price": 100.00,
+      "paid": "ДА",
+      "document": "Преземи",
+      "payOnline": true,
+      "status": "approved",
+      "comment": ""
+    },
+    {
+      "id": 6,
+      "archive": "81891",
+      "date": "12.01.2024",
+      "request": "Уверение за редовен студент - ФИНКИ",
+      "price": 0.00,
+      "paid": "ДА",
+      "document": "Преземи",
+      "payOnline": false,
+      "status": "approved",
+      "comment": ""
+    }
+  ],
+  "pagination": {
+    "currentPage": 1,
+    "totalPages": 1,
+    "totalRecords": 6,
+    "recordsPerPage": 15
+  },
+  "paymentInfo": "Онлајн плаќањата имаат банкарска провизија за безготовинско плаќање од 1,14% од оригиналната сума (минималната провизија 3,00, максималната 300,00 мкд)"
+}
Index: frontend/src/i18n.ts
===================================================================
--- frontend/src/i18n.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/i18n.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,23 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+
+import translationEN from './locales/en/translation.json';
+import translationMK from './locales/mk/translation.json';
+
+const resources = {
+  en: { translation: translationEN },
+  mk: { translation: translationMK },
+};
+
+i18n
+  .use(initReactI18next)
+  .init({
+    resources,
+    lng: 'mk',
+    fallbackLng: 'mk',
+    interpolation: {
+      escapeValue: false,
+    },
+  });
+
+export default i18n;
Index: frontend/src/lib/admin-api.ts
===================================================================
--- frontend/src/lib/admin-api.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/lib/admin-api.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,90 @@
+import { apiUrl } from "@/lib/api";
+import { getAccessToken } from "@/lib/auth";
+
+export type AdminResult = { ok: boolean; message?: string; id?: number | null };
+
+export type SubjectRef = { id: number; name?: string; code?: string | null };
+
+export type SubjectMajor = {
+  majorId: number;
+  majorName?: string;
+  mandatorySemester: number;
+};
+
+export type AdminSubject = {
+  id: number;
+  name?: string;
+  code?: string;
+  awardedCredits: number;
+  dependencyCredit?: number | null;
+  majors: SubjectMajor[];
+  prerequisites: SubjectRef[];
+  enrolledCount: number;
+};
+
+export type AdminSemester = {
+  id: number;
+  year: number;
+  type?: string;
+  name?: string;
+  enrolmentCount: number;
+  uncoveredSubjects: SubjectRef[];
+};
+
+export type ScheduleRow = {
+  subjectId: number;
+  subjectName?: string;
+  subjectCode?: string;
+  professorId: number;
+  professorName?: string;
+};
+
+export type ProfessorLoad = {
+  professorId: number;
+  professorName?: string;
+  subjects: number;
+};
+
+export type Schedule = {
+  semesterId: number;
+  semesterName?: string;
+  assignments: ScheduleRow[];
+  load: ProfessorLoad[];
+  uncoveredSubjects: SubjectRef[];
+  allSubjects: SubjectRef[];
+  professors: { id: number; name?: string }[];
+};
+
+function authHeaders(): Record<string, string> {
+  const token = getAccessToken();
+  if (!token) throw new Error("You are not signed in.");
+  return { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
+}
+
+/** GET that throws with the server message rather than a bare status code. */
+export async function adminGet<T>(path: string): Promise<T> {
+  const res = await fetch(apiUrl(path), { cache: "no-store", headers: authHeaders() });
+  if (!res.ok) {
+    const body = await res.json().catch(() => null);
+    throw new Error(body?.message || `Request failed (${res.status})`);
+  }
+  return (await res.json()) as T;
+}
+
+/** POST/PUT/DELETE returning the standard {ok, message} envelope. */
+export async function adminSend(
+  path: string,
+  method: "POST" | "PUT" | "DELETE",
+  body?: unknown,
+): Promise<AdminResult> {
+  const res = await fetch(apiUrl(path), {
+    method,
+    headers: authHeaders(),
+    body: body === undefined ? undefined : JSON.stringify(body),
+  });
+  const result = (await res.json().catch(() => null)) as AdminResult | null;
+  if (!res.ok || !result?.ok) {
+    throw new Error(result?.message || `Request failed (${res.status})`);
+  }
+  return result;
+}
Index: frontend/src/lib/api.ts
===================================================================
--- frontend/src/lib/api.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/lib/api.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,15 @@
+/**
+ * Base URL of the iknow-api backend.
+ *
+ * Set NEXT_PUBLIC_API_BASE_URL in .env.local to point at a local API run
+ * (see .env.example). The faculty database is only reachable through the SSH
+ * tunnel on the developer machine, so the deployed backend cannot read it -
+ * working against real data means running iknow-api locally.
+ */
+export const API_BASE_URL =
+  process.env.NEXT_PUBLIC_API_BASE_URL ?? 'https://iknow-api.onrender.com';
+
+/** Builds an absolute API URL from a path such as `/api/user/getUser`. */
+export function apiUrl(path: string): string {
+  return `${API_BASE_URL}${path}`;
+}
Index: frontend/src/lib/auth.ts
===================================================================
--- frontend/src/lib/auth.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/lib/auth.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,142 @@
+import { API_BASE_URL } from './api';
+export type AuthTokens = {
+  accessToken: string;
+  refreshToken: string;
+};
+
+export type UserRole = 'Professor' | 'Student' | 'Admin' | string;
+
+export type AuthSession = AuthTokens & {
+  role: UserRole;
+};
+
+type StoredToken = {
+  value: string;
+  expiresAt: number; // epoch ms
+};
+
+const STORAGE_KEYS = {
+  access: 'iknow.auth.access',
+  refresh: 'iknow.auth.refresh',
+  role: 'iknow.auth.role',
+} as const;
+
+const ACCESS_TOKEN_TTL_MS = 60 * 60 * 1000; // 1 hour
+const REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 60 * 1000; // ~1 month (30 days)
+
+function isBrowser() {
+  return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
+}
+
+function readStoredToken(key: string): StoredToken | null {
+  if (!isBrowser()) return null;
+  const raw = window.localStorage.getItem(key);
+  if (!raw) return null;
+
+  try {
+    const parsed = JSON.parse(raw) as StoredToken;
+    if (!parsed?.value || typeof parsed.expiresAt !== 'number') {
+      window.localStorage.removeItem(key);
+      return null;
+    }
+
+    if (Date.now() >= parsed.expiresAt) {
+      window.localStorage.removeItem(key);
+      return null;
+    }
+
+    return parsed;
+  } catch {
+    window.localStorage.removeItem(key);
+    return null;
+  }
+}
+
+function writeStoredToken(key: string, value: string, ttlMs: number) {
+  if (!isBrowser()) return;
+  const payload: StoredToken = {
+    value,
+    expiresAt: Date.now() + ttlMs,
+  };
+  window.localStorage.setItem(key, JSON.stringify(payload));
+}
+
+export function setAuthTokens(tokens: AuthTokens) {
+  writeStoredToken(STORAGE_KEYS.access, tokens.accessToken, ACCESS_TOKEN_TTL_MS);
+  writeStoredToken(STORAGE_KEYS.refresh, tokens.refreshToken, REFRESH_TOKEN_TTL_MS);
+}
+
+export function setUserRole(role: UserRole) {
+  // Keep role TTL aligned with access token TTL.
+  writeStoredToken(STORAGE_KEYS.role, role, ACCESS_TOKEN_TTL_MS);
+}
+
+export function getAccessToken(): string | null {
+  return readStoredToken(STORAGE_KEYS.access)?.value ?? null;
+}
+
+export function getRefreshToken(): string | null {
+  return readStoredToken(STORAGE_KEYS.refresh)?.value ?? null;
+}
+
+export function getUserRole(): UserRole | null {
+  return readStoredToken(STORAGE_KEYS.role)?.value ?? null;
+}
+
+export function clearAuthTokens() {
+  if (!isBrowser()) return;
+  window.localStorage.removeItem(STORAGE_KEYS.access);
+  window.localStorage.removeItem(STORAGE_KEYS.refresh);
+  window.localStorage.removeItem(STORAGE_KEYS.role);
+}
+
+export async function login(params: { email: string; password: string }): Promise<AuthSession> {
+  const baseUrl = API_BASE_URL;
+
+  const response = await fetch(`${baseUrl}/api/auth/login`, {
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/json',
+    },
+    body: JSON.stringify({
+      email: params.email,
+      password: params.password,
+      GenerateRefreshToken: true,
+    }),
+  });
+
+  if (!response.ok) {
+    let message = `Login failed (${response.status})`;
+    try {
+      const text = await response.text();
+      if (text) message = text;
+    } catch {
+      // ignore
+    }
+    throw new Error(message);
+  }
+
+  const data = (await response.json()) as {
+    token?: string;
+    refreshToken?: string;
+    role?: string;
+  };
+
+  const accessToken = data?.token;
+  const refreshToken = data?.refreshToken;
+  const role = data?.role;
+
+  if (!accessToken || !refreshToken) {
+    throw new Error('Login response did not contain tokens.');
+  }
+
+  const session: AuthSession = {
+    accessToken,
+    refreshToken,
+    role: role ?? 'Student',
+  };
+
+  setAuthTokens(session);
+  setUserRole(session.role);
+  return session;
+}
Index: frontend/src/lib/pdf-fonts.ts
===================================================================
--- frontend/src/lib/pdf-fonts.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/lib/pdf-fonts.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,32 @@
+import { jsPDF } from 'jspdf';
+
+let fontsLoaded = false;
+let regularFontBase64: string | null = null;
+let boldFontBase64: string | null = null;
+
+async function fetchFontAsBase64(url: string): Promise<string> {
+  const response = await fetch(url);
+  const buffer = await response.arrayBuffer();
+  const bytes = new Uint8Array(buffer);
+  let binary = '';
+  for (let i = 0; i < bytes.length; i++) {
+    binary += String.fromCharCode(bytes[i]);
+  }
+  return btoa(binary);
+}
+
+export async function loadCyrillicFonts(doc: jsPDF): Promise<void> {
+  if (!fontsLoaded) {
+    regularFontBase64 = await fetchFontAsBase64('/fonts/Roboto-Regular.ttf');
+    boldFontBase64 = await fetchFontAsBase64('/fonts/Roboto-Bold.ttf');
+    fontsLoaded = true;
+  }
+
+  doc.addFileToVFS('Roboto-Regular.ttf', regularFontBase64!);
+  doc.addFont('Roboto-Regular.ttf', 'Roboto', 'normal');
+
+  doc.addFileToVFS('Roboto-Bold.ttf', boldFontBase64!);
+  doc.addFont('Roboto-Bold.ttf', 'Roboto', 'bold');
+
+  doc.setFont('Roboto', 'normal');
+}
Index: frontend/src/lib/pdf-generators.ts
===================================================================
--- frontend/src/lib/pdf-generators.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/lib/pdf-generators.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,1207 @@
+import { jsPDF } from 'jspdf';
+import autoTable from 'jspdf-autotable';
+import { loadCyrillicFonts } from './pdf-fonts';
+import { apiUrl } from './api';
+
+/* ---------- shared types ---------- */
+
+export type StudentInfo = {
+  firstName: string;
+  middleName: string;
+  lastName: string;
+  index: string;
+  embg: string;
+  dateOfBirth: string;
+  gender: string;
+  nationality: string;
+  citizenship: string;
+  currentPlan: string;
+  registryNumber: string;
+  studyGroup: string;
+  scholarship: string;
+};
+
+export type EnrollmentInfo = {
+  enrollmentYear: string | number;
+  status: string;
+  cycle: string;
+  program: string;
+  quota: string;
+};
+
+export type BirthInfo = {
+  placeOfBirth: string;
+  municipalityOfBirth: string;
+  country: string;
+};
+
+export type ContactInfo = {
+  placeOfResidence: string;
+  municipalityOfResidence: string;
+  address: string;
+  phone: string;
+  mobilePhone: string;
+  email: string;
+};
+
+export type PassedExam = {
+  id: number;
+  code: string;
+  subject: string;
+  credits: number;
+  grade: number;
+  date: string;
+  semester: string;
+  professor: string;
+};
+
+export type PreviousEducation = {
+  type: string;
+  profession: string;
+  average: string | number;
+  language: string;
+  country: string;
+  previousUniversity: string;
+  previousFaculty: string;
+};
+
+/* ---------- helpers ---------- */
+
+const PAGE_WIDTH = 210; // A4 mm
+const MARGIN = 20;
+const CONTENT_WIDTH = PAGE_WIDTH - 2 * MARGIN;
+
+function drawUniversityHeader(doc: jsPDF, y: number): number {
+  doc.setFont('Roboto', 'bold');
+
+  doc.setFontSize(11);
+  doc.text('УНИВЕРЗИТЕТ „СВ. КИРИЛ И МЕТОДИЈ" - СКОПЈЕ', PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 6;
+
+  doc.setFontSize(10);
+  doc.text('ФАКУЛТЕТ ЗА ИНФОРМАТИЧКИ НАУКИ И', PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 5;
+  doc.text('КОМПЈУТЕРСКО ИНЖЕНЕРСТВО', PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 5;
+
+  // Horizontal line under header
+  doc.setDrawColor(0, 114, 209); // primary blue
+  doc.setLineWidth(0.5);
+  doc.line(MARGIN, y, PAGE_WIDTH - MARGIN, y);
+  y += 8;
+
+  return y;
+}
+
+function drawDocumentTitle(doc: jsPDF, title: string, y: number): number {
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(14);
+  doc.text(title, PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 10;
+  return y;
+}
+
+function drawInfoRow(doc: jsPDF, label: string, value: string, x: number, y: number, labelWidth = 50): number {
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.text(`${label}:`, x, y);
+  doc.setFont('Roboto', 'normal');
+  doc.text(String(value || '—'), x + labelWidth, y);
+  return y + 5.5;
+}
+
+function drawFooter(doc: jsPDF, archiveNumber: string, date: string): void {
+  const pageHeight = doc.internal.pageSize.getHeight();
+  let y = pageHeight - 40;
+
+  doc.setDrawColor(0, 114, 209);
+  doc.setLineWidth(0.3);
+  doc.line(MARGIN, y, PAGE_WIDTH - MARGIN, y);
+  y += 8;
+
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(9);
+
+  doc.text(`Бр.: ${archiveNumber}`, MARGIN, y);
+  doc.text(`Датум: ${date}`, PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 12;
+
+  // Signature placeholders
+  doc.text('Потпис на студентот:', MARGIN, y);
+  doc.text('М.П.', PAGE_WIDTH / 2, y, { align: 'center' });
+  doc.text('Одговорно лице:', PAGE_WIDTH - MARGIN - 35, y);
+  y += 8;
+
+  doc.setDrawColor(150, 150, 150);
+  doc.setLineWidth(0.2);
+  doc.line(MARGIN, y, MARGIN + 45, y);
+  doc.line(PAGE_WIDTH / 2 - 15, y, PAGE_WIDTH / 2 + 15, y);
+  doc.line(PAGE_WIDTH - MARGIN - 45, y, PAGE_WIDTH - MARGIN, y);
+}
+
+/* ==================================================================
+   PDF 1 — Уверение за положени испити (Certificate of Passed Exams)
+   ================================================================== */
+
+export async function generatePassedExamsCertificate(
+  student: StudentInfo,
+  enrollment: EnrollmentInfo,
+  passedExams: PassedExam[],
+  archiveNumber: string,
+  date: string,
+): Promise<void> {
+  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
+  await loadCyrillicFonts(doc);
+
+  let y = 20;
+
+  // --- Header ---
+  y = drawUniversityHeader(doc, y);
+
+  // --- Title ---
+  y = drawDocumentTitle(doc, 'УВЕРЕНИЕ ЗА ПОЛОЖЕНИ ИСПИТИ', y);
+
+  // --- Student Info Block ---
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(9);
+
+  y = drawInfoRow(doc, 'Студент', `${student.firstName} ${student.middleName} ${student.lastName}`, MARGIN, y);
+  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y);
+  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y);
+  y = drawInfoRow(doc, 'Циклус на студии', enrollment.cycle, MARGIN, y);
+  y = drawInfoRow(doc, 'Статус', enrollment.status, MARGIN, y);
+  y += 4;
+
+  // --- Passed Exams Table ---
+  const tableBody = passedExams.map((exam, idx) => [
+    String(idx + 1),
+    exam.code,
+    exam.subject,
+    String(exam.credits),
+    String(exam.grade),
+    exam.date,
+    exam.semester,
+    exam.professor || '—',
+  ]);
+
+  autoTable(doc, {
+    startY: y,
+    head: [['Р.Б.', 'Шифра', 'Предмет', 'Кредити', 'Оцена', 'Датум', 'Семестар', 'Професор']],
+    body: tableBody,
+    theme: 'grid',
+    styles: {
+      font: 'Roboto',
+      fontSize: 7.5,
+      cellPadding: 2,
+      textColor: [30, 30, 30],
+      lineColor: [200, 200, 200],
+      lineWidth: 0.2,
+    },
+    headStyles: {
+      fillColor: [0, 114, 209],
+      textColor: [255, 255, 255],
+      fontStyle: 'bold',
+      fontSize: 7.5,
+      halign: 'center',
+    },
+    columnStyles: {
+      0: { halign: 'center', cellWidth: 10 },
+      1: { halign: 'center', cellWidth: 16 },
+      2: { cellWidth: 50 },
+      3: { halign: 'center', cellWidth: 14 },
+      4: { halign: 'center', cellWidth: 12 },
+      5: { halign: 'center', cellWidth: 20 },
+      6: { cellWidth: 22 },
+      7: { cellWidth: 26 },
+    },
+    margin: { left: MARGIN, right: MARGIN },
+    didParseCell: (data) => {
+      if (data.section === 'body' && data.row.index % 2 === 0) {
+        data.cell.styles.fillColor = [245, 247, 250];
+      }
+    },
+  });
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  y = (doc as any).lastAutoTable.finalY + 8;
+
+  // --- Summary ---
+  const totalCredits = passedExams.reduce((sum, e) => sum + e.credits, 0);
+  const grades = passedExams.map((e) => e.grade).filter((g) => g > 0);
+  const average = grades.length > 0 ? (grades.reduce((s, g) => s + g, 0) / grades.length).toFixed(2) : '0.00';
+
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(10);
+  doc.text(`Вкупно положени предмети: ${passedExams.length}`, MARGIN, y);
+  y += 6;
+  doc.text(`Вкупно кредити: ${totalCredits}`, MARGIN, y);
+  y += 6;
+  doc.text(`Просечна оцена: ${average}`, MARGIN, y);
+
+  // --- Footer ---
+  drawFooter(doc, archiveNumber, date);
+
+  doc.save(`Уверение_положени_испити_${student.index}.pdf`);
+}
+
+/* ==================================================================
+   PDF 2 — УППИ образец (UPPI Form / Student Record)
+   ================================================================== */
+
+export async function generateUPPIForm(
+  student: StudentInfo,
+  enrollment: EnrollmentInfo,
+  birth: BirthInfo,
+  contact: ContactInfo,
+  previousEdu: PreviousEducation,
+  passedExams: PassedExam[],
+  archiveNumber: string,
+  date: string,
+): Promise<void> {
+  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
+  await loadCyrillicFonts(doc);
+
+  let y = 20;
+
+  // --- Header ---
+  y = drawUniversityHeader(doc, y);
+
+  // --- Title ---
+  y = drawDocumentTitle(doc, 'УППИ ОБРАЗЕЦ', y);
+
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.text('УНИВЕРЗАЛНА ПРИЈАВА ЗА ПРАКТИЧНА ИНДИВИДУАЛНА РАБОТА', PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 10;
+
+  // --- Section: Personal Information ---
+  doc.setFillColor(0, 114, 209);
+  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.setTextColor(255, 255, 255);
+  doc.text('ЛИЧНИ ПОДАТОЦИ', MARGIN + 3, y + 0.5);
+  doc.setTextColor(30, 30, 30);
+  y += 10;
+
+  const col2X = MARGIN + CONTENT_WIDTH / 2;
+
+  y = drawInfoRow(doc, 'Име', student.firstName, MARGIN, y, 35);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'Презиме', student.lastName, col2X, y, 35);
+  y = drawInfoRow(doc, 'Татково име', student.middleName, MARGIN, y, 35);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'ЕМБГ', student.embg, col2X, y, 35);
+  y = drawInfoRow(doc, 'Датум на раѓање', student.dateOfBirth, MARGIN, y, 35);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'Пол', student.gender, col2X, y, 35);
+  y = drawInfoRow(doc, 'Националност', student.nationality, MARGIN, y, 35);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'Државјанство', student.citizenship, col2X, y, 35);
+  y += 3;
+
+  // --- Section: Birth Info ---
+  doc.setFillColor(0, 114, 209);
+  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.setTextColor(255, 255, 255);
+  doc.text('ПОДАТОЦИ ЗА РАЃАЊЕ', MARGIN + 3, y + 0.5);
+  doc.setTextColor(30, 30, 30);
+  y += 10;
+
+  y = drawInfoRow(doc, 'Место на раѓање', birth.placeOfBirth, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Општина', birth.municipalityOfBirth, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Држава', birth.country, MARGIN, y, 40);
+  y += 3;
+
+  // --- Section: Contact ---
+  doc.setFillColor(0, 114, 209);
+  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.setTextColor(255, 255, 255);
+  doc.text('КОНТАКТ ИНФОРМАЦИИ', MARGIN + 3, y + 0.5);
+  doc.setTextColor(30, 30, 30);
+  y += 10;
+
+  y = drawInfoRow(doc, 'Место на живеење', contact.placeOfResidence, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Адреса', contact.address, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Телефон', contact.phone || contact.mobilePhone, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Е-пошта', contact.email, MARGIN, y, 40);
+  y += 3;
+
+  // --- Section: Enrollment ---
+  doc.setFillColor(0, 114, 209);
+  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.setTextColor(255, 255, 255);
+  doc.text('СТУДИСКИ ИНФОРМАЦИИ', MARGIN + 3, y + 0.5);
+  doc.setTextColor(30, 30, 30);
+  y += 10;
+
+  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y, 40);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'Мат. број', student.registryNumber, col2X, y, 35);
+  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Циклус', enrollment.cycle, MARGIN, y, 40);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'Статус', enrollment.status, col2X, y, 35);
+  y = drawInfoRow(doc, 'Год. на запишување', String(enrollment.enrollmentYear), MARGIN, y, 40);
+  y -= 5.5;
+  y = drawInfoRow(doc, 'Квота', enrollment.quota, col2X, y, 35);
+  y += 3;
+
+  // --- Section: Previous Education ---
+  doc.setFillColor(0, 114, 209);
+  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.setTextColor(255, 255, 255);
+  doc.text('ПРЕТХОДНО ОБРАЗОВАНИЕ', MARGIN + 3, y + 0.5);
+  doc.setTextColor(30, 30, 30);
+  y += 10;
+
+  y = drawInfoRow(doc, 'Вид', previousEdu.type, MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Просек', String(previousEdu.average), MARGIN, y, 40);
+  y = drawInfoRow(doc, 'Јазик', previousEdu.language, MARGIN, y, 40);
+  y += 3;
+
+  // --- Section: Passed Exams mini-table ---
+  doc.setFillColor(0, 114, 209);
+  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.setTextColor(255, 255, 255);
+  doc.text('ПОЛОЖЕНИ ИСПИТИ', MARGIN + 3, y + 0.5);
+  doc.setTextColor(30, 30, 30);
+  y += 8;
+
+  const examTableBody = passedExams.map((exam, idx) => [
+    String(idx + 1),
+    exam.code,
+    exam.subject,
+    String(exam.credits),
+    String(exam.grade),
+    exam.date,
+  ]);
+
+  autoTable(doc, {
+    startY: y,
+    head: [['#', 'Шифра', 'Предмет', 'Кредити', 'Оцена', 'Датум']],
+    body: examTableBody,
+    theme: 'grid',
+    styles: {
+      font: 'Roboto',
+      fontSize: 7,
+      cellPadding: 1.5,
+      textColor: [30, 30, 30],
+      lineColor: [200, 200, 200],
+      lineWidth: 0.2,
+    },
+    headStyles: {
+      fillColor: [0, 114, 209],
+      textColor: [255, 255, 255],
+      fontStyle: 'bold',
+      fontSize: 7,
+      halign: 'center',
+    },
+    columnStyles: {
+      0: { halign: 'center', cellWidth: 8 },
+      1: { halign: 'center', cellWidth: 18 },
+      2: { cellWidth: 70 },
+      3: { halign: 'center', cellWidth: 16 },
+      4: { halign: 'center', cellWidth: 14 },
+      5: { halign: 'center', cellWidth: 22 },
+    },
+    margin: { left: MARGIN, right: MARGIN },
+    didParseCell: (data) => {
+      if (data.section === 'body' && data.row.index % 2 === 0) {
+        data.cell.styles.fillColor = [245, 247, 250];
+      }
+    },
+  });
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  y = (doc as any).lastAutoTable.finalY + 8;
+
+  // Summary
+  const totalCredits = passedExams.reduce((sum, e) => sum + e.credits, 0);
+  const grades = passedExams.map((e) => e.grade).filter((g) => g > 0);
+  const average = grades.length > 0 ? (grades.reduce((s, g) => s + g, 0) / grades.length).toFixed(2) : '0.00';
+
+  doc.setFont('Roboto', 'bold');
+  doc.setFontSize(9);
+  doc.text(`Вкупно кредити: ${totalCredits}    |    Просечна оцена: ${average}`, MARGIN, y);
+
+  // Footer
+  drawFooter(doc, archiveNumber, date);
+
+  doc.save(`УППИ_образец_${student.index}.pdf`);
+}
+
+/* ==================================================================
+   PDF 3 — Уверение за редовен студент (Regular Student Certificate)
+   ================================================================== */
+
+export async function generateRegularStudentCertificate(
+  student: StudentInfo,
+  enrollment: EnrollmentInfo,
+  passedExams: PassedExam[],
+  archiveNumber: string,
+  date: string,
+): Promise<void> {
+  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
+  await loadCyrillicFonts(doc);
+
+  let y = 20;
+
+  // --- Header ---
+  y = drawUniversityHeader(doc, y);
+
+  // --- Title ---
+  y = drawDocumentTitle(doc, 'УВЕРЕНИЕ', y);
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(10);
+  doc.text('за редовен студент', PAGE_WIDTH / 2, y, { align: 'center' });
+  y += 12;
+
+  // --- Body text ---
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(10);
+
+  const totalCredits = passedExams.reduce((sum, e) => sum + e.credits, 0);
+  const grades = passedExams.map((e) => e.grade).filter((g) => g > 0);
+  const average = grades.length > 0 ? (grades.reduce((s, g) => s + g, 0) / grades.length).toFixed(2) : '0.00';
+
+  const bodyText = [
+    `Со ова се потврдува дека студентот/студентката`,
+    ``,
+    `${student.firstName} ${student.middleName} ${student.lastName}`,
+    ``,
+    `со индекс број ${student.index}, ЕМБГ ${student.embg},`,
+    `е редовен студент на Факултетот за информатички науки и компјутерско`,
+    `инженерство при Универзитетот „Св. Кирил и Методиј" - Скопје.`,
+    ``,
+    `Студиска програма: ${enrollment.program}`,
+    `Циклус на студии: ${enrollment.cycle}`,
+    `Статус: ${enrollment.status}`,
+    `Година на запишување: ${enrollment.enrollmentYear}`,
+    ``,
+    `Студентот/студентката до сега има положено ${passedExams.length} испити,`,
+    `со вкупно ${totalCredits} кредити и просечна оцена ${average}.`,
+    ``,
+    `Ова уверение се издава за потребите на студентот/студентката`,
+    `и може да послужи за секоја законска употреба.`,
+  ];
+
+  for (const line of bodyText) {
+    if (line === '') {
+      y += 4;
+    } else {
+      if (line.startsWith(`${student.firstName}`)) {
+        doc.setFont('Roboto', 'bold');
+        doc.setFontSize(12);
+        doc.text(line, PAGE_WIDTH / 2, y, { align: 'center' });
+        doc.setFont('Roboto', 'normal');
+        doc.setFontSize(10);
+      } else {
+        doc.text(line, MARGIN, y);
+      }
+      y += 6;
+    }
+  }
+
+  // Footer
+  drawFooter(doc, archiveNumber, date);
+
+  doc.save(`Уверение_редовен_студент_${student.index}.pdf`);
+}
+
+/* ==================================================================
+   Generic document — fallback for other document types
+   ================================================================== */
+
+export async function generateGenericDocument(
+  student: StudentInfo,
+  enrollment: EnrollmentInfo,
+  documentTitle: string,
+  archiveNumber: string,
+  date: string,
+): Promise<void> {
+  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
+  await loadCyrillicFonts(doc);
+
+  let y = 20;
+
+  y = drawUniversityHeader(doc, y);
+  y = drawDocumentTitle(doc, documentTitle.toUpperCase(), y);
+
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(10);
+
+  y = drawInfoRow(doc, 'Студент', `${student.firstName} ${student.middleName} ${student.lastName}`, MARGIN, y);
+  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y);
+  y = drawInfoRow(doc, 'ЕМБГ', student.embg, MARGIN, y);
+  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y);
+  y = drawInfoRow(doc, 'Циклус', enrollment.cycle, MARGIN, y);
+  y = drawInfoRow(doc, 'Статус', enrollment.status, MARGIN, y);
+  y += 8;
+
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(10);
+  doc.text('Документот е издаден по барање на студентот.', MARGIN, y);
+
+  drawFooter(doc, archiveNumber, date);
+
+  doc.save(`${documentTitle.replace(/\s+/g, '_')}_${student.index}.pdf`);
+}
+
+/* ==================================================================
+   Themed request generators — one for each document type
+   ================================================================== */
+
+async function generateRequestDocument(
+  student: StudentInfo,
+  enrollment: EnrollmentInfo,
+  title: string,
+  bodyLines: string[],
+  archiveNumber: string,
+  date: string,
+  filename: string,
+): Promise<void> {
+  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
+  await loadCyrillicFonts(doc);
+
+  let y = 20;
+
+  y = drawUniversityHeader(doc, y);
+  y = drawDocumentTitle(doc, title, y);
+
+  // Student info block
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(9);
+  y = drawInfoRow(doc, 'Студент', `${student.firstName} ${student.middleName} ${student.lastName}`, MARGIN, y);
+  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y);
+  y = drawInfoRow(doc, 'ЕМБГ', student.embg, MARGIN, y);
+  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y);
+  y = drawInfoRow(doc, 'Циклус', enrollment.cycle, MARGIN, y);
+  y = drawInfoRow(doc, 'Статус', enrollment.status, MARGIN, y);
+  y = drawInfoRow(doc, 'Година на упис', String(enrollment.enrollmentYear), MARGIN, y);
+  y += 8;
+
+  // Separator
+  doc.setDrawColor(200, 200, 200);
+  doc.setLineWidth(0.3);
+  doc.line(MARGIN, y, PAGE_WIDTH - MARGIN, y);
+  y += 8;
+
+  // Body text
+  doc.setFont('Roboto', 'normal');
+  doc.setFontSize(10);
+  for (const line of bodyLines) {
+    if (line === '') {
+      y += 5;
+    } else {
+      const wrapped = doc.splitTextToSize(line, CONTENT_WIDTH);
+      for (const wl of wrapped) {
+        doc.text(wl, MARGIN, y);
+        y += 5.5;
+      }
+    }
+  }
+
+  drawFooter(doc, archiveNumber, date);
+  doc.save(`${filename}_${student.index}.pdf`);
+}
+
+// --- Administrative Regulation ---
+export async function generateAdministrativeRegulation(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА АДМИНИСТРАТИВНО РЕГУЛИРАЊЕ НА РЕТРОАКТИВЕН СЕМЕСТАР',
+    [
+      `До: Деканат на Факултетот за информатички науки и компјутерско инженерство`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `запишан/а на студиската програма ${enrollment.program}, ${enrollment.cycle} циклус студии,`,
+      `со ова барање побарувам административно регулирање на ретроактивен семестар.`,
+      '',
+      `Молам да ми се одобри административна регулација на семестар кој не е запишан во предвидениот рок,`,
+      `согласно одлуката на Факултетот и важечката регулатива.`,
+      '',
+      `Прилози: Уплатница за административна такса од 1000 ден.`,
+    ],
+    archiveNumber, date, 'Административно_регулирање');
+}
+
+// --- Late Exam Registration ---
+export async function generateExamApplicationSatisfaction(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ЗАДОЧНО ПРИЈАВУВАЊЕ НА ИСПИТ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `запишан/а на студиската програма ${enrollment.program},`,
+      `побарувам задочно пријавување на испит кој не е пријавен во предвидениот рок.`,
+      '',
+      `Причина за задоцнување: ___________________________________`,
+      '',
+      `Молам за одобрување на ова барање.`,
+      '',
+      `Прилози: Уплатница за административна такса од 1000 ден.`,
+    ],
+    archiveNumber, date, 'Задочно_пријавување_испит');
+}
+
+// --- Semester Enrollment After Deadline ---
+export async function generateSemesterEnrollmentAfterDeadline(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ЗАПИШУВАЊЕ НА СЕМЕСТАР ПО ИСТЕК НА РОК',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам да ми се одобри запишување на нареден семестар по истекот на официјалниот рок.`,
+      '',
+      `Причина за задоцнето запишување: ___________________________________`,
+      '',
+      `Молам за одобрување.`,
+      '',
+      `Прилози: Уплатница за административна такса од 1500 ден.`,
+    ],
+    archiveNumber, date, 'Запишување_семестар_по_рок');
+}
+
+// --- Certificate Issuance ---
+export async function generateCertificateIssuanceVarious(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ИЗДАВАЊЕ НА ПОТВРДИ ПО РАЗНИ ОСНОВИ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам издавање на потврда за следната намена:`,
+      '',
+      `Намена: ___________________________________`,
+      '',
+      `Молам да ми биде издадена бараната потврда.`,
+      '',
+      `Прилози: Уплатница за административна такса од 1500 ден.`,
+    ],
+    archiveNumber, date, 'Издавање_потврди');
+}
+
+// --- Study Suspension ---
+export async function generateStudySuspension(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА МИРУВАЊЕ НА СТУДИИТЕ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `запишан/а на студиската програма ${enrollment.program},`,
+      `побарувам мирување на студиите за период од ______ семестри.`,
+      '',
+      `Причина за мирување: ___________________________________`,
+      '',
+      `Изјавувам дека сум запознаен/а со правилата за продолжување на студиите`,
+      `по истекот на периодот на мирување.`,
+      '',
+      `Прилози: Уплатница за административна такса од 2000 ден.`,
+    ],
+    archiveNumber, date, 'Мирување_студии');
+}
+
+// --- Diploma Thesis Cancellation ---
+export async function generateDiplomaThesisCancellation(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ОТКАЖУВАЊЕ НА ПРИЈАВЕНА ТЕМА ЗА ДИПЛОМСКА РАБОТА',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам откажување на претходно пријавената тема за дипломска работа.`,
+      '',
+      `Назив на темата: ___________________________________`,
+      `Ментор: ___________________________________`,
+      '',
+      `Причина за откажување: ___________________________________`,
+      '',
+      `Прилози: Уплатница за административна такса од 1000 ден.`,
+    ],
+    archiveNumber, date, 'Откажување_дипломска');
+}
+
+// --- Graduation Package ---
+export async function generateDiplomaPackage(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПАКЕТ ЗА ДИПЛОМИРАЊЕ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `запишан/а на студиската програма ${enrollment.program}, ${enrollment.cycle} циклус,`,
+      `побарувам издавање на пакет за дипломирање.`,
+      '',
+      `Со ова потврдувам дека ги имам исполнето сите услови за дипломирање`,
+      `согласно студиската програма и правилникот на Факултетот.`,
+      '',
+      `Пакетот за дипломирање ги вклучува: диплома, додаток на диплома и свечена промоција.`,
+      '',
+      `Прилози: Уплатница за административна такса од 6200 ден.`,
+    ],
+    archiveNumber, date, 'Пакет_дипломирање');
+}
+
+// --- Exam Cancellation ---
+export async function generateExamCancellation(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПОНИШТУВАЊЕ НА ИСПИТ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам поништување на испит по предметот:`,
+      '',
+      `Предмет: ___________________________________`,
+      `Датум на полагање: ___________________________________`,
+      '',
+      `Причина за поништување: ___________________________________`,
+      '',
+      `Прилози: Уплатница за административна такса од 2000 ден.`,
+    ],
+    archiveNumber, date, 'Поништување_испит');
+}
+
+// --- Study Continuation ---
+export async function generateStudyContinuation(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПРОДОЛЖУВАЊЕ НА СТУДИИ ВО МИРУВАЊЕ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам продолжување на студиите по периодот на мирување.`,
+      '',
+      `Период на мирување: од ____________ до ____________`,
+      '',
+      `Молам да ми се одобри продолжување на студиите согласно тековната`,
+      `студиска програма и важечкиот правилник.`,
+      '',
+      `Прилози: Уплатница за административна такса од 2000 ден.`,
+    ],
+    archiveNumber, date, 'Продолжување_студии');
+}
+
+// --- Elective Subject Change ---
+export async function generateElectiveSubjectChange(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПРОМЕНА НА ИЗБОРЕН ПРЕДМЕТ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам промена на изборен предмет.`,
+      '',
+      `Предмет што се менува: ___________________________________`,
+      `Нов изборен предмет: ___________________________________`,
+      '',
+      `Причина за промена: ___________________________________`,
+      '',
+      `Прилози: Уплатница за административна такса од 1500 ден.`,
+    ],
+    archiveNumber, date, 'Промена_изборен_предмет');
+}
+
+// --- Passed Subject Change ---
+export async function generatePassedSubjectChange(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПРОМЕНА НА ПОЛОЖЕН ПРЕДМЕТ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам промена / корекција на запис за положен предмет.`,
+      '',
+      `Предмет: ___________________________________`,
+      `Датум на полагање: ___________________________________`,
+      `Оцена: ___________________________________`,
+      '',
+      `Детали за промена: ___________________________________`,
+    ],
+    archiveNumber, date, 'Промена_положен_предмет');
+}
+
+// --- Study Program Change (Same Accreditation) ---
+export async function generateProgramChangeSameAccreditation(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПРОМЕНА НА СТУДИСКА ПРОГРАМА ОД ИСТА АКРЕДИТАЦИЈА',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `тековно запишан/а на програмата ${enrollment.program},`,
+      `побарувам промена на студиска програма во рамки на истата акредитација.`,
+      '',
+      `Нова студиска програма: ___________________________________`,
+      '',
+      `Причина за промена: ___________________________________`,
+      '',
+      `Прилози: Уплатница за административна такса од 2000 ден.`,
+    ],
+    archiveNumber, date, 'Промена_програма_иста_акредитација');
+}
+
+// --- Study Program Change (New Accreditation) ---
+export async function generateProgramChangeNewAccreditation(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'БАРАЊЕ ЗА ПРОМЕНА НА СТУДИСКА ПРОГРАМА ОД ПОНОВА АКРЕДИТАЦИЈА',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `тековно запишан/а на програмата ${enrollment.program},`,
+      `побарувам промена на студиска програма во рамки на нова акредитација.`,
+      '',
+      `Нова студиска програма: ___________________________________`,
+      `Нова акредитација: ___________________________________`,
+      '',
+      `Причина за промена: ___________________________________`,
+      '',
+      `Прилози: Уплатница за административна такса од 3000 ден.`,
+    ],
+    archiveNumber, date, 'Промена_програма_нова_акредитација');
+}
+
+// --- Diploma Supplement ---
+export async function generateDiplomaSupplement(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'ДОДАТОК НА ДИПЛОМА',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `запишан/а на студиската програма ${enrollment.program}, ${enrollment.cycle} циклус,`,
+      `побарувам издавање на додаток на диплома.`,
+      '',
+      `Додатокот на дипломата се издава како придружен документ`,
+      `кон дипломата за завршените студии.`,
+    ],
+    archiveNumber, date, 'Додаток_диплома');
+}
+
+// --- Diploma Supplement Second Cycle ---
+export async function generateDiplomaSupplementSecondCycle(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'ДОДАТОК НА ДИПЛОМА (ВТОР ЦИКЛУС)',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `запишан/а на студиската програма ${enrollment.program}, втор циклус на студии,`,
+      `побарувам издавање на додаток на диплома за вториот циклус студии.`,
+      '',
+      `Додатокот на дипломата се издава како придружен документ`,
+      `кон магистерската диплома.`,
+    ],
+    archiveNumber, date, 'Додаток_диплома_втор_циклус');
+}
+
+// --- MKSA ---
+export async function generateMKSA(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'МКСА - МАКЕДОНСКА КВАЛИФИКАЦИСКА РАМКА',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам издавање на МКСА (Македонска Квалификациска Рамка) документ.`,
+      '',
+      `Студиска програма: ${enrollment.program}`,
+      `Циклус: ${enrollment.cycle}`,
+      '',
+      `Документот е потребен за целите на: ___________________________________`,
+      '',
+      `Прилози: Уплатница за административна такса од 750 ден.`,
+    ],
+    archiveNumber, date, 'МКСА');
+}
+
+// --- Exam Recognition ---
+export async function generateExamRecognition(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'ПРИЗНАВАЊЕ НА ПОЛОЖЕНИ ИСПИТИ',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам признавање на положени испити од претходна институција / програма.`,
+      '',
+      `Претходна институција: ___________________________________`,
+      `Претходна програма: ___________________________________`,
+      '',
+      `Листа на предмети за признавање:`,
+      `1. ___________________________________`,
+      `2. ___________________________________`,
+      `3. ___________________________________`,
+      '',
+      `Прилози: Уверение за положени испити од претходна институција.`,
+    ],
+    archiveNumber, date, 'Признавање_испити');
+}
+
+// --- Student Card (Old) ---
+export async function generateStudentCardOld(
+  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
+): Promise<void> {
+  await generateRequestDocument(student, enrollment,
+    'СТУДЕНТСКИ КАРТОН (СТАРО)',
+    [
+      `До: Деканат на ФИНКИ`,
+      '',
+      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
+      `побарувам издавање на студентски картон (стар формат).`,
+      '',
+      `Студиска програма: ${enrollment.program}`,
+      `Година на упис: ${enrollment.enrollmentYear}`,
+      '',
+      `Молам да ми биде издаден студентски картон.`,
+    ],
+    archiveNumber, date, 'Студентски_картон');
+}
+
+/* ==================================================================
+   Main dispatcher — called from the Documents page
+   ================================================================== */
+
+// Map document type IDs → generator function names
+const DOCUMENT_TYPE_MAP: Record<string, string> = {
+  'административно регулирање': 'administrative_regulation',
+  'задочно пријавување': 'exam_application_satisfaction',
+  'запишување на семестар по истек': 'semester_enrollment_after_deadline',
+  'издавање потврди': 'certificate_issuance_various',
+  'мирување на студиите': 'student_status_verification',
+  'откажување на пријавена тема': 'diploma_thesis_postponement',
+  'пакет за дипломирање': 'diploma_package',
+  'поништување на испит': 'exam_postponement',
+  'потврда за редовен студент': 'regular_student_certificate',
+  'продолжување на студии во мирување': 'study_continuation_verification',
+  'промена на изборен предмет': 'failed_subject_grade_change',
+  'промена на положен предмет': 'passed_subject_grade_change',
+  'промена на студиска програма од иста': 'study_program_change_same_accreditation',
+  'промена на студиска програма од понова': 'study_program_change_new_accreditation',
+  'додаток на диплома (втор циклус)': 'diploma_supplement_second_cycle',
+  'додаток на диплома': 'diploma_supplement',
+  'мкса': 'mksa',
+  'признавање на положени испити': 'exam_recognition',
+  'студентски картон': 'student_card_old',
+};
+
+function identifyDocumentType(request: string): string | null {
+  const lower = request.toLowerCase();
+
+  // Exact-match patterns (check longer patterns first)
+  if (lower.includes('положени испити')) return 'passed_exams_certificate';
+  if (lower.includes('уппи')) return 'uppi_form';
+  if (lower.includes('редовен студент')) return 'regular_student_certificate';
+
+  // Match by document type keywords
+  for (const [keyword, docType] of Object.entries(DOCUMENT_TYPE_MAP)) {
+    if (lower.includes(keyword)) return docType;
+  }
+
+  return null;
+}
+
+export async function downloadDocumentPDF(
+  documentRequest: string,
+  archiveNumber: string,
+  documentDate: string,
+  accessToken: string,
+): Promise<void> {
+  // Fetch student profile
+  const profileRes = await fetch(apiUrl('/api/user/getUser'), {
+    headers: { Authorization: `Bearer ${accessToken}` },
+  });
+  if (!profileRes.ok) throw new Error('Не може да се вчита профилот на студентот');
+
+  const profile = await profileRes.json();
+  const { personalInfo, enrollmentInfo, birthInfo, contact, previousEducation } = profile;
+
+  const student: StudentInfo = {
+    firstName: personalInfo.firstName,
+    middleName: personalInfo.middleName,
+    lastName: personalInfo.lastName,
+    index: personalInfo.index,
+    embg: personalInfo.embg,
+    dateOfBirth: personalInfo.dateOfBirth,
+    gender: personalInfo.gender,
+    nationality: personalInfo.nationality,
+    citizenship: personalInfo.citizenship,
+    currentPlan: personalInfo.currentPlan,
+    registryNumber: personalInfo.registryNumber,
+    studyGroup: personalInfo.studyGroup,
+    scholarship: personalInfo.scholarship,
+  };
+
+  const enrollment: EnrollmentInfo = {
+    enrollmentYear: enrollmentInfo.enrollmentYear,
+    status: enrollmentInfo.status,
+    cycle: enrollmentInfo.cycle,
+    program: enrollmentInfo.program,
+    quota: enrollmentInfo.quota,
+  };
+
+  const docType = identifyDocumentType(documentRequest);
+
+  // Types that need passed exams data
+  const needsExams = docType === 'passed_exams_certificate' || docType === 'uppi_form' || docType === 'regular_student_certificate';
+
+  let passedExams: PassedExam[] = [];
+  if (needsExams) {
+    const examsRes = await fetch(apiUrl('/api/user/getPassedSubjects'), {
+      headers: { Authorization: `Bearer ${accessToken}` },
+    });
+    if (examsRes.ok) {
+      const examsData = await examsRes.json();
+      passedExams = (examsData?.passedSubjects ?? []).map((s: Record<string, unknown>) => ({
+        id: s.id as number,
+        code: s.code as string,
+        subject: s.subject as string,
+        credits: s.credits as number,
+        grade: s.grade as number,
+        date: s.date as string,
+        semester: s.semester as string,
+        professor: (s.professor as string) || '—',
+      }));
+    }
+  }
+
+  switch (docType) {
+    case 'passed_exams_certificate':
+      await generatePassedExamsCertificate(student, enrollment, passedExams, archiveNumber, documentDate);
+      break;
+    case 'uppi_form': {
+      const birth: BirthInfo = {
+        placeOfBirth: birthInfo.placeOfBirth,
+        municipalityOfBirth: birthInfo.municipalityOfBirth,
+        country: birthInfo.country,
+      };
+      const contactInfo: ContactInfo = {
+        placeOfResidence: contact.placeOfResidence,
+        municipalityOfResidence: contact.municipalityOfResidence,
+        address: contact.address,
+        phone: contact.phone,
+        mobilePhone: contact.mobilePhone,
+        email: contact.email,
+      };
+      const prevEdu: PreviousEducation = {
+        type: previousEducation.type,
+        profession: previousEducation.profession,
+        average: previousEducation.average,
+        language: previousEducation.language,
+        country: previousEducation.country,
+        previousUniversity: previousEducation.previousUniversity,
+        previousFaculty: previousEducation.previousFaculty,
+      };
+      await generateUPPIForm(student, enrollment, birth, contactInfo, prevEdu, passedExams, archiveNumber, documentDate);
+      break;
+    }
+    case 'regular_student_certificate':
+      await generateRegularStudentCertificate(student, enrollment, passedExams, archiveNumber, documentDate);
+      break;
+    case 'administrative_regulation':
+      await generateAdministrativeRegulation(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'exam_application_satisfaction':
+      await generateExamApplicationSatisfaction(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'semester_enrollment_after_deadline':
+      await generateSemesterEnrollmentAfterDeadline(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'certificate_issuance_various':
+      await generateCertificateIssuanceVarious(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'student_status_verification':
+      await generateStudySuspension(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'diploma_thesis_postponement':
+      await generateDiplomaThesisCancellation(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'diploma_package':
+      await generateDiplomaPackage(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'exam_postponement':
+      await generateExamCancellation(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'study_continuation_verification':
+      await generateStudyContinuation(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'failed_subject_grade_change':
+      await generateElectiveSubjectChange(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'passed_subject_grade_change':
+      await generatePassedSubjectChange(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'study_program_change_same_accreditation':
+      await generateProgramChangeSameAccreditation(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'study_program_change_new_accreditation':
+      await generateProgramChangeNewAccreditation(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'diploma_supplement':
+      await generateDiplomaSupplement(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'diploma_supplement_second_cycle':
+      await generateDiplomaSupplementSecondCycle(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'mksa':
+      await generateMKSA(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'exam_recognition':
+      await generateExamRecognition(student, enrollment, archiveNumber, documentDate);
+      break;
+    case 'student_card_old':
+      await generateStudentCardOld(student, enrollment, archiveNumber, documentDate);
+      break;
+    default:
+      await generateGenericDocument(student, enrollment, documentRequest, archiveNumber, documentDate);
+      break;
+  }
+}
Index: frontend/src/lib/utils.ts
===================================================================
--- frontend/src/lib/utils.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/lib/utils.ts	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+  return twMerge(clsx(inputs))
+}
Index: frontend/src/locales/en/translation.json
===================================================================
--- frontend/src/locales/en/translation.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/locales/en/translation.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,321 @@
+{
+  "prof_students_title": "Professor • Students",
+  "prof_students_data_note": "Data comes from",
+  "filter_by_subject": "Filter by subject",
+  "all_subjects": "All subjects",
+  "find_student_by_id": "Find student by index / ID",
+  "student_id_placeholder": "e.g. 20001",
+  "no_students_found": "No students found.",
+  "taxes": "Taxes",
+  "signatures": "Signatures",
+  "valid": "Valid",
+  "completed_semester": "Completed semesters",
+  "verified_semesters": "Verified semesters",
+  "total_semesters": "Total semesters",
+  "completed_semesters": "Completed semesters",
+  "documents_overview": "Overview of your documents and their status.",
+  "new_document_request": "New Document Request",
+  "select_document": "Select Document",
+  "price": "Price",
+  "comment": "Comment",
+  "add_comment": "Add comment",
+  "submit": "Submit",
+  "submitting": "Submitting...",
+  "document_submitted": "Document request submitted successfully!",
+  "document_submit_error": "Error submitting document request.",
+  "not_authenticated": "You are not logged in. Please log in again.",
+  "pdf_error": "Error generating document. Please try again.",
+  "generating": "Generating...",
+  "pending": "Pending",
+  "my_documents": "My Documents",
+  "archive": "Archive",
+  "request": "Request",
+  "document": "Document",
+  "pay_online": "Pay Online",
+  "none": "—",
+  "show_rows": "Show rows",
+  "page": "Page",
+  "of": "of",
+  "first": "First",
+  "last": "Last",
+  "total": "Total",
+  "documents_payment_info": "For more information about document payments, contact the administration.",
+  "total_documents": "Total Documents",
+  "approved": "Approved",
+  "total_price": "Total Price",
+  "mkd": "MKD",
+  "free": "0.00",
+  "download": "Download",
+  "university": "University ‘St. Cyril and Methodius’ - Skopje",
+  "faculty": "Faculty of Computer Science and Engineering",
+  "logout": "Logout",
+  "profile": "Profile",
+  "semesters": "Semesters",
+  "applications": "Applications",
+  "documents": "Documents",
+  "exams": "Exams",
+  "subjects": "Subjects",
+  "students": "Students",
+  "loading": "Loading...",
+  "failed_to_load_profile": "Failed to load profile.",
+  "n_a": "N/A",
+  "index": "Index",
+  "embg": "EMBG",
+  "personal_info": "Personal Information",
+  "first_name": "First Name",
+  "middle_name": "Middle Name",
+  "last_name": "Last Name",
+  "maiden_name": "Maiden Name",
+  "date_of_birth": "Date of Birth",
+  "gender": "Gender",
+  "male": "Male",
+  "female": "Female",
+  "nationality": "Nationality",
+  "citizenship": "Citizenship",
+  "scholarship": "Scholarship",
+  "current_plan": "Current Plan",
+  "registry_number": "Registry Number",
+  "study_group": "Study Group",
+  "note": "Note",
+  "birth_info": "Birth Information",
+  "place_of_birth": "Place of Birth",
+  "municipality_of_birth": "Municipality of Birth",
+  "country": "Country",
+  "previous_education": "Previous Education",
+  "type": "Type",
+  "profession": "Profession",
+  "average": "Average",
+  "language": "Language",
+  "previous_university": "Previous University",
+  "previous_faculty": "Previous Faculty",
+  "previous_study_mode": "Previous Study Mode",
+  "enrollment_info": "Enrollment Information",
+  "enrollment_year": "Enrollment Year",
+  "status": "Status",
+  "cycle": "Cycle",
+  "program": "Program",
+  "quota": "Quota",
+  "secondary_education_number": "Secondary Education Number",
+  "previous_education_credits": "Previous Education Credits",
+  "contact": "Contact",
+  "place_of_residence": "Place of Residence",
+  "municipality_of_residence": "Municipality of Residence",
+  "address": "Address",
+  "temporary_address": "Temporary Address",
+  "phone": "Phone",
+  "mobile_phone": "Mobile Phone",
+  "passport_number": "Passport Number",
+  "passport_expiry_date": "Passport Expiry Date",
+  "email": "Email",
+  "microsoft_email": "Microsoft Email",
+  "applications_header": "Applications",
+  "applications_subheader": "Electronic exam applications",
+  "select_exam_session": "Select exam session:",
+  "registered_exams": "Registered Exams",
+  "serial_number": "Serial Number",
+  "code": "Code",
+  "subject": "Subject",
+  "completed": "Completed",
+  "not_completed": "Not Completed",
+  "fee": "Fee",
+  "date": "Date",
+  "instructor": "Instructor",
+  "decade": "Decade",
+  "important_note": "Important Note",
+  "applications_important_note": "Important note regarding exam applications",
+  "yes": "Yes",
+  "no": "No",
+  "total_fee": "Total Fee",
+  "failed_to_load_exams": "Failed to load exams.",
+  "credits": "Credits",
+  "passed": "Passed",
+  "remaining": "Remaining",
+  "semester": "Semester",
+  "grade": "Grade",
+  "semesters_overview": "Overview of your enrolled semesters and their statuses.",
+  "semesters_list": "Semesters List",
+  "direction": "Direction",
+  "student_com": "Student Commission",
+  "sum": "Sum",
+  "paid": "Paid",
+  "ukim": "UKIM",
+  "created_on": "Created On",
+  "date_changed": "Date Changed",
+  "doc": "Document",
+  "doc1": "Document 1",
+  "verified": "Verified",
+  "debt": "Debt",
+  "debt_from_documents": "Debt from documents",
+  "ticket_number": "Ticket number",
+  "select_semester": "Select semester",
+  "enrolled_subjects": "Enrolled subjects",
+  "financial_info": "Financial information",
+  "material_costs": "Material costs",
+  "material_costs_info": "Material costs include all required fees for materials and resources for the subjects.",
+  "electronic_registration": "Electronic registration",
+  "eukim": "eUKIM",
+  "bank_provision": "Bank provision",
+  "which_time": "Which time",
+  "signature": "Signature",
+  "group": "Group",
+  "professor": "Professor",
+  "subjects_list": "Subjects list",
+  "subjects_overview": "Overview of your enrolled subjects and their status.",
+  "mandatory_short": "Mand.",
+  "elective_short": "Elect.",
+  "enrolled_by_student": "Enrolled by student",
+  "due": "Debt",
+  "failed_to_load_subjects": "Failed to load subjects.",
+  "hours": "Hours",
+  "administrative_regulation": "Request for administrative regulation of retroactive semester (from 2024) (1000)",
+  "exam_application_satisfaction": "Request for late exam registration (from 2024) (1000)",
+  "semester_enrollment_after_deadline": "Request for semester enrollment after deadline (from 2024) (1500)",
+  "certificate_issuance_various": "Request for issuance of certificates for various reasons (from 2024) (1500)",
+  "student_status_verification": "Request for suspension of studies (from 2024) (2000)",
+  "diploma_thesis_postponement": "Request for cancellation of registered diploma thesis topic (from 2024) (1000)",
+  "diploma_package": "Request for graduation package (from 2024) (6200)",
+  "exam_postponement": "Request for exam cancellation (from 2024) (2000)",
+  "regular_student_certificate": "Request for regular student certificate (paper) (100)",
+  "study_continuation_verification": "Request for continuation of studies in suspension (from 2024) (2000)",
+  "failed_subject_grade_change": "Request for elective subject change (from 2024) (1500)",
+  "passed_subject_grade_change": "Request for passed subject change (from 2024) (0)",
+  "study_program_change_same_accreditation": "Request for study program change from same accreditation (from 2024) (2000)",
+  "study_program_change_new_accreditation": "Request for study program change from newer accreditation (from 2024) (3000)",
+  "diploma_supplement": "Diploma supplement (0)",
+  "diploma_supplement_second_cycle": "Diploma supplement (second cycle) (0)",
+  "mksa": "MKSA (750)",
+  "exam_recognition": "Recognition of passed exams (0)",
+  "student_card_old": "Student card (Old) (0)",
+  "Уверение за положени испити ФИНКИ": "Certificate of passed exams FINKI",
+  "УППИ образец": "UPPI form",
+  "Уверение за редовен студент - ФИНКИ": "Regular student certificate - FINKI",
+  "2025_summer_session2": "2025 (Summer) Second exam session",
+  "2025_summer_session1": "2025 (Summer) First exam session",
+  "2025_winter_session2": "2025 (Winter) Second exam session",
+  "2025_winter_session1": "2025 (Winter) First exam session",
+  "2024_summer_session2": "2024 (Summer) Second exam session",
+  "2024_summer_session1": "2024 (Summer) First exam session",
+  "2024_winter_session2": "2024 (Winter) Second exam session",
+  "2024_winter_session1": "2024 (Winter) First exam session",
+  "applications_important_note_text": "The serial number of the electronic application must be entered on the paper application that the student will submit physically.",
+  "login_student_title": "Login for Student",
+  "login_student_example": "Email: stefan.saveski@students.finki.ukim.mk\nPassword: Test12345!",
+  "login_professor_title": "Login for Professor",
+  "login_professor_example": "Email: vangel.ajanovski@finki.ukim.mk\nPassword: Test12345!",
+  "login_admin_title": "Login for Administrator",
+  "login_admin_example": "Email: igor.adminovski@finki.ukim.mk\nPassword: Test12345!",
+  "login_welcome": "Welcome",
+  "login_subtitle": "Sign in to your IKnow account",
+  "login_email_label": "Enter email",
+  "login_email_placeholder": "Enter email",
+  "login_password_label": "Password",
+  "login_password_placeholder": "Enter password",
+  "login_remember_me": "Remember me",
+  "login_forgot_password": "Forgot password?",
+  "login_button": "Sign in",
+  "login_button_loading": "Signing in...",
+  "login_no_account": "Don't have an account?",
+  "login_contact_admin": "Contact administration",
+  "login_footer": "Student Information System",
+  "contact_us": "Contact Us",
+  "close": "Close",
+  "contact_name": "Full Name",
+  "contact_name_placeholder": "Your name",
+  "contact_email": "Email",
+  "contact_email_placeholder": "example@email.com",
+  "contact_subject": "Subject",
+  "contact_subject_placeholder": "Message topic",
+  "contact_message": "Message",
+  "contact_message_placeholder": "Write your message...",
+  "contact_send": "Send",
+  "contact_sending": "Sending...",
+  "contact_sent_title": "Message sent!",
+  "contact_sent_desc": "We will get back to you soon.",
+  "Компјутерски мрежи и безбедност": "Computer Networks and Security",
+  "Шаблони за дизајн на кориснички интерфејси": "User Interface Design Patterns",
+  "Деловна пракса": "Business Practice",
+  "Маркетинг": "Marketing",
+  "Оперативни системи": "Operating Systems",
+  "Софтверско инженерство": "Software Engineering",
+  "Вештачка интелигенција": "Artificial Intelligence",
+  "Сашо Граматиков": "Sasho Gramatikov",
+  "Сузана Лошковска": "Suzana Loshkovska",
+  "Александар Стојменски": "Aleksandar Stojmenski",
+  "Билјана Стојкоска": "Biljana Stojkoska",
+  "Невена Ацковска": "Nevena Ackovska",
+  "Ѓорѓи Маџаров": "Gjorgji Madjarov",
+  "Соња Гиевска": "Sonja Gievska",
+  "Летна": "Summer",
+  "Зимска": "Winter",
+  "Прва испитна сесија": "First exam session",
+  "Втора испитна сесија": "Second exam session",
+  "Валидно": "Valid",
+  "Да": "Yes",
+  "Не": "No",
+  "exams_overview": "Overview of your passed exams and grades.",
+  "failed_to_load_semesters": "Failed to load semesters.",
+  "add_grade": "Add Grade",
+  "edit_grade": "Edit Grade",
+  "remove_grade": "Remove Grade",
+  "current": "Current",
+  "login_demo_note": "Use these credentials to explore the system.",
+  "enroll_semester": "Enroll semester",
+  "enroll_confirm": "Enroll",
+  "enroll_no_semesters": "You are already enrolled in every available semester.",
+  "enroll_already_passed": "passed",
+  "enroll_credits": "credits",
+  "enroll_semester_short": "sem.",
+  "enroll_not_signed_in": "You are not signed in.",
+  "enroll_options_failed": "Could not load enrollment options",
+  "enroll_failed": "Enrollment failed",
+  "cancel": "Cancel",
+  "admin_portal": "Admin",
+  "admin_subjects": "Subjects",
+  "admin_semesters": "Semesters",
+  "admin_schedule": "Teaching schedule",
+  "admin_subjects_intro": "Add subjects, map them to study programmes and set prerequisites.",
+  "admin_semesters_intro": "Open an active semester so students can enroll in it.",
+  "admin_schedule_intro": "Decide which professor teaches which subject in which semester.",
+  "admin_new_subject": "New subject",
+  "admin_edit_subject": "Edit subject",
+  "admin_subject_name": "Name",
+  "admin_subject_code": "Code",
+  "admin_credits": "Credits",
+  "admin_dependency_credit": "Required credits",
+  "admin_create": "Create",
+  "admin_save": "Save",
+  "admin_delete": "Delete",
+  "admin_remove": "Remove",
+  "admin_add": "Add",
+  "admin_manage": "Manage",
+  "admin_close": "Close",
+  "admin_majors": "Study programmes",
+  "admin_prerequisites": "Prerequisites",
+  "admin_pick_major": "Pick a study programme",
+  "admin_pick_prerequisite": "Pick a prerequisite",
+  "admin_pick_subject": "Pick a subject",
+  "admin_pick_professor": "Pick a professor",
+  "admin_search_subject": "Search by name or code",
+  "admin_no_subjects": "No subjects found.",
+  "admin_delete_blocked": "Cannot delete: {{count}} enrolment(s) already contain this subject.",
+  "admin_new_semester": "Open a new semester",
+  "admin_year": "Year",
+  "admin_type": "Type",
+  "admin_winter": "Winter",
+  "admin_summer": "Summer",
+  "admin_open_semester": "Open semester",
+  "admin_open_semesters": "Open semesters",
+  "admin_no_semesters": "No semesters yet.",
+  "admin_enrolments": "Enrolments",
+  "admin_coverage": "Coverage",
+  "admin_fully_covered": "all subjects covered",
+  "admin_uncovered_count": "{{count}} subject(s) without a professor",
+  "admin_uncovered_hint": "Students cannot enroll in a subject nobody teaches that semester.",
+  "admin_show_uncovered": "Show",
+  "admin_professor": "Professor",
+  "admin_assign": "Assign",
+  "admin_assignments": "Assignments",
+  "admin_load": "Teaching load",
+  "admin_no_assignments": "Nothing assigned yet.",
+  "admin_no_professors": "No professors."
+}
Index: frontend/src/locales/mk/translation.json
===================================================================
--- frontend/src/locales/mk/translation.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/src/locales/mk/translation.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,325 @@
+{
+  "prof_students_title": "Професор • Студенти",
+  "prof_students_data_note": "Податоците се од",
+  "filter_by_subject": "Филтрирај по предмет",
+  "all_subjects": "Сите предмети",
+  "find_student_by_id": "Најди студент по индекс / ID",
+  "student_id_placeholder": "пр. 20001",
+  "no_students_found": "Не се пронајдени студенти.",
+  "student": "Студент",
+  "id": "ID",
+  "actions": "Акции",
+  "current": "Тековна",
+  "add_grade": "Додади оценка",
+  "edit_grade": "Измени оценка",
+  "remove_grade": "Избриши оценка",
+  "taxes": "Такси",
+  "signatures": "Потписи",
+  "valid": "Валидно",
+  "completed_semester": "Завршени семестри",
+  "verified_semesters": "Потврдени семестри",
+  "total_semesters": "Вкупно семестри",
+  "completed_semesters": "Завршени семестри",
+  "documents_overview": "Преглед на вашите документи и нивниот статус.",
+  "new_document_request": "Ново барање за документ",
+  "select_document": "Изберете документ",
+  "price": "Цена",
+  "comment": "Коментар",
+  "add_comment": "Додај коментар",
+  "submit": "Поднеси",
+  "submitting": "Се поднесува...",
+  "document_submitted": "Барањето за документ е успешно поднесено!",
+  "document_submit_error": "Грешка при поднесување на барањето.",
+  "not_authenticated": "Не сте најавени. Ве молиме најавете се повторно.",
+  "pdf_error": "Грешка при генерирање на документот. Обидете се повторно.",
+  "generating": "Генерира...",
+  "pending": "Во обработка",
+  "my_documents": "Мои документи",
+  "archive": "Архива",
+  "request": "Барање",
+  "document": "Документ",
+  "pay_online": "Плати онлајн",
+  "none": "—",
+  "show_rows": "Прикажи редови",
+  "page": "Страница",
+  "of": "од",
+  "first": "Прва",
+  "last": "Последна",
+  "total": "Вкупно",
+  "documents_payment_info": "За повеќе информации за плаќање документи, обратете се во администрација.",
+  "total_documents": "Вкупно документи",
+  "approved": "Одобрено",
+  "total_price": "Вкупна цена",
+  "mkd": "мкд",
+  "free": "0,00",
+  "download": "Преземи",
+  "choose_document": "Избери документ",
+  "university": "Универзитет „Св. КИРИЛ И МЕТОДИЈ“ - Скопје",
+  "faculty": "Факултет за информатички науки и компјутерско инженерство",
+  "logout": "Одјави се",
+  "profile": "Профил",
+  "semesters": "Семестри",
+  "applications": "Апликации",
+  "documents": "Документи",
+  "exams": "Испити",
+  "subjects": "Предмети",
+  "students": "Студенти",
+  "loading": "Се вчитува...",
+  "failed_to_load_profile": "Не успеавме да го вчитаме профилот.",
+  "n_a": "Н/П",
+  "index": "Индекс",
+  "embg": "ЕМБГ",
+  "personal_info": "Лични податоци",
+  "first_name": "Име",
+  "middle_name": "Средно име",
+  "last_name": "Презиме",
+  "maiden_name": "Моминско презиме",
+  "date_of_birth": "Датум на раѓање",
+  "gender": "Пол",
+  "male": "машки",
+  "female": "женски",
+  "nationality": "Националност",
+  "citizenship": "Државјанство",
+  "scholarship": "Стипендија",
+  "current_plan": "Тековен план",
+  "registry_number": "Бр. во матична книга",
+  "study_group": "Група на студирање",
+  "note": "Забелешка",
+  "birth_info": "Податоци за раѓање",
+  "place_of_birth": "Место на раѓање",
+  "municipality_of_birth": "Општина на раѓање",
+  "country": "Земја",
+  "previous_education": "Претходно образование",
+  "type": "Тип",
+  "profession": "Професија",
+  "average": "Просек",
+  "language": "Јазик",
+  "previous_university": "Претходен универзитет",
+  "previous_faculty": "Претходен факултет",
+  "previous_study_mode": "Режим на претходни студии",
+  "enrollment_info": "Податоци за упис",
+  "enrollment_year": "Година на упис",
+  "status": "Статус",
+  "cycle": "Циклус",
+  "program": "Запишана програма",
+  "quota": "Квота на прв упис",
+  "secondary_education_number": "Бр. дипл. ср. образование",
+  "previous_education_credits": "Кред. пр. образование",
+  "contact": "Контакт",
+  "place_of_residence": "Место на живеење",
+  "municipality_of_residence": "Општина на живеење",
+  "address": "Адреса",
+  "temporary_address": "Адреса на престој",
+  "phone": "Телефон",
+  "mobile_phone": "Моб. телефон",
+  "passport_number": "Број на пасош",
+  "passport_expiry_date": "Датум на истекување на пасошот",
+  "email": "Е-пошта",
+  "microsoft_email": "Microsoft email",
+  "applications_header": "Пријави",
+  "applications_subheader": "Електронски пријави за испити",
+  "select_exam_session": "Избери испитна сесија:",
+  "registered_exams": "Пријавени испити",
+  "serial_number": "Сериски број",
+  "code": "Код",
+  "subject": "Предмет",
+  "completed": "Завршени",
+  "not_completed": "Незавршени",
+  "fee": "Таксени",
+  "date": "Датум",
+  "instructor": "Наставник",
+  "decade": "Декада",
+  "important_note": "Важна забелешка",
+  "applications_important_note": "Важна забелешка за испитните пријави",
+  "yes": "Да",
+  "no": "Не",
+  "total_fee": "Вкупна такса",
+  "failed_to_load_exams": "Не успеавме да ги вчитаме испитите.",
+  "credits": "Кредити",
+  "passed": "Положени",
+  "remaining": "Останато",
+  "semester": "Семестар",
+  "grade": "Оценка",
+  "semesters_overview": "Преглед на вашите запишани семестри и нивниот статус.",
+  "semesters_list": "Листа на семестри",
+  "direction": "Насока",
+  "student_com": "Студентска комисија",
+  "sum": "Сума",
+  "paid": "Платено",
+  "ukim": "УКИМ",
+  "created_on": "Креирано на",
+  "date_changed": "Датум на промена",
+  "doc": "Документ",
+  "doc1": "Документ 1",
+  "verified": "Потврдено",
+  "debt": "Долг",
+  "debt_from_documents": "Долг од документи",
+  "ticket_number": "Број на тикет",
+  "select_semester": "Избери семестар",
+  "enrolled_subjects": "Запишани предмети",
+  "financial_info": "Финансиски информации",
+  "material_costs": "Материјални трошоци",
+  "material_costs_info": "Материјалните трошоци ги вклучуваат сите задолжителни надоместоци за материјали и ресурси за предметите.",
+  "electronic_registration": "Електронска регистрација",
+  "eukim": "еУКИМ",
+  "bank_provision": "Банкарска провизија",
+  "which_time": "Кој пат",
+  "signature": "Потпис",
+  "group": "Група",
+  "professor": "Професор",
+  "subjects_list": "Листа на предмети",
+  "subjects_overview": "Преглед на вашите запишани предмети и нивниот статус.",
+  "mandatory_short": "Зад.",
+  "elective_short": "Изб.",
+  "enrolled_by_student": "Запишан од студентот",
+  "due": "Долг",
+  "failed_to_load_subjects": "Не успеавме да ги вчитаме предметите.",
+  "hours": "Часови",
+  "administrative_regulation": "Барање за административно регулирање на ретроактивен семестар (од 2024г) ( 1000)",
+  "exam_application_satisfaction": "Барање за задочно пријавување на испит (од 2024г) ( 1000)",
+  "semester_enrollment_after_deadline": "Барање за запишување на семестар по истек на рок (од 2024г) ( 1500)",
+  "certificate_issuance_various": "Барање за издавање потврди по разни основи (од 2024г) ( 1500)",
+  "student_status_verification": "Барање за мирување на студиите (од 2024г) ( 2000)",
+  "diploma_thesis_postponement": "Барање за откажување на пријавена тема за дипломска работа (од 2024г) ( 1000)",
+  "diploma_package": "Барање за пакет за дипломирање (од 2024г) (6200)",
+  "exam_postponement": "Барање за поништување на испит (од 2024г) ( 2000)",
+  "regular_student_certificate": "Барање за потврда за редовен студент (хартиена) ( 100)",
+  "study_continuation_verification": "Барање за продолжување на студии во мирување (од 2024г) ( 2000)",
+  "failed_subject_grade_change": "Барање за промена на изборен предмет (од 2024г) ( 1500)",
+  "passed_subject_grade_change": "Барање за промена на положен предмет (од 2024г) ( 0)",
+  "study_program_change_same_accreditation": "Барање за промена на студиска програма од иста акредитација (од 2024г) ( 2000)",
+  "study_program_change_new_accreditation": "Барање за промена на студиска програма од понова акредитација (од 2024г) ( 3000)",
+  "diploma_supplement": "Додаток на диплома ( 0)",
+  "diploma_supplement_second_cycle": "Додаток на диплома (втор циклус) ( 0)",
+  "mksa": "МКСА ( 750)",
+  "exam_recognition": "Признавање на положени испити ( 0)",
+  "student_card_old": "Студентски картон (Старо) ( 0)",
+  "Уверение за положени испити ФИНКИ": "Уверение за положени испити ФИНКИ",
+  "УППИ образец": "УППИ образец",
+  "Уверение за редовен студент - ФИНКИ": "Уверение за редовен студент - ФИНКИ",
+  "Компјутерски мрежи и безбедност": "Компјутерски мрежи и безбедност",
+  "Шаблони за дизајн на кориснички интерфејси": "Шаблони за дизајн на кориснички интерфејси",
+  "Деловна пракса": "Деловна пракса",
+  "Маркетинг": "Маркетинг",
+  "Оперативни системи": "Оперативни системи",
+  "Софтверско инженерство": "Софтверско инженерство",
+  "Вештачка интелигенција": "Вештачка интелигенција",
+  "Сашо Граматиков": "Сашо Граматиков",
+  "Сузана Лошковска": "Сузана Лошковска",
+  "Александар Стојменски": "Александар Стојменски",
+  "Билјана Стојкоска": "Билјана Стојкоска",
+  "Невена Ацковска": "Невена Ацковска",
+  "Ѓорѓи Маџаров": "Ѓорѓи Маџаров",
+  "Соња Гиевска": "Соња Гиевска",
+  "exams_overview": "Преглед на вашите положени испити и оценки.",
+  "failed_to_load_semesters": "Не успеавме да ги вчитаме семестрите.",
+  "Летна": "Летна",
+  "Зимска": "Зимска",
+  "Прва испитна сесија": "Прва испитна сесија",
+  "Втора испитна сесија": "Втора испитна сесија",
+  "Валидно": "Валидно",
+  "Да": "Да",
+  "Не": "Не",
+  "2025_summer_session2": "2025 (Летна) Втора испитна сесија",
+  "2025_summer_session1": "2025 (Летна) Прва испитна сесија",
+  "2025_winter_session2": "2025 (Зимска) Втора испитна сесија",
+  "2025_winter_session1": "2025 (Зимска) Прва испитна сесија",
+  "2024_summer_session2": "2024 (Летна) Втора испитна сесија",
+  "2024_summer_session1": "2024 (Летна) Прва испитна сесија",
+  "2024_winter_session2": "2024 (Зимска) Втора испитна сесија",
+  "2024_winter_session1": "2024 (Зимска) Прва испитна сесија",
+  "applications_important_note_text": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички.",
+  "login_student_title": "Најава за студент",
+  "login_student_example": "Е-пошта: stefan.saveski@students.finki.ukim.mk\nЛозинка: Test12345!",
+  "login_professor_title": "Најава за професор",
+  "login_professor_example": "Е-пошта: vangel.ajanovski@finki.ukim.mk\nЛозинка: Test12345!",
+  "login_admin_title": "Најава за администратор",
+  "login_admin_example": "Е-пошта: igor.adminovski@finki.ukim.mk\nЛозинка: Test12345!",
+  "login_welcome": "Добредојде",
+  "login_subtitle": "Најавете се во вашиот IKnow акаунт",
+  "login_email_label": "Внесете е-пошта",
+  "login_email_placeholder": "Внесете е-пошта",
+  "login_password_label": "Лозинка",
+  "login_password_placeholder": "Внесете лозинка",
+  "login_remember_me": "Запомни ме",
+  "login_forgot_password": "Заборавена лозинка?",
+  "login_button": "Најави се",
+  "login_button_loading": "Најавување...",
+  "login_no_account": "Немате акаунт?",
+  "login_contact_admin": "Контактирајте ја администрацијата",
+  "login_footer": "Студентски информационен систем",
+  "contact_us": "Контактирај нè",
+  "close": "Затвори",
+  "contact_name": "Име и презиме",
+  "contact_name_placeholder": "Вашето име",
+  "contact_email": "Е-пошта",
+  "contact_email_placeholder": "example@email.com",
+  "contact_subject": "Наслов",
+  "contact_subject_placeholder": "Тема на пораката",
+  "contact_message": "Порака",
+  "contact_message_placeholder": "Напишете ја вашата порака...",
+  "contact_send": "Испрати",
+  "contact_sending": "Испраќа...",
+  "contact_sent_title": "Пораката е испратена!",
+  "contact_sent_desc": "Ќе ви одговориме наскоро.",
+  "login_demo_note": "Користете ги овие податоци за да го истражите системот.",
+  "enroll_semester": "Запиши семестар",
+  "enroll_confirm": "Запиши",
+  "enroll_no_semesters": "Веќе сте запишани во сите достапни семестри.",
+  "enroll_already_passed": "положен",
+  "enroll_credits": "кредити",
+  "enroll_semester_short": "сем.",
+  "enroll_not_signed_in": "Не сте најавени.",
+  "enroll_options_failed": "Не може да се вчитаат опциите за запишување",
+  "enroll_failed": "Запишувањето не успеа",
+  "cancel": "Откажи",
+  "admin_portal": "Админ",
+  "admin_subjects": "Предмети",
+  "admin_semesters": "Семестри",
+  "admin_schedule": "Распоред",
+  "admin_subjects_intro": "Додавање предмети, поврзување со студиски програми и предуслови.",
+  "admin_semesters_intro": "Отворање активен семестар во кој студентите можат да се запишат.",
+  "admin_schedule_intro": "Определување кој професор кој предмет го предава.",
+  "admin_new_subject": "Нов предмет",
+  "admin_edit_subject": "Измена на предмет",
+  "admin_subject_name": "Назив",
+  "admin_subject_code": "Шифра",
+  "admin_credits": "Кредити",
+  "admin_dependency_credit": "Потребни кредити",
+  "admin_create": "Креирај",
+  "admin_save": "Зачувај",
+  "admin_delete": "Избриши",
+  "admin_remove": "Отстрани",
+  "admin_add": "Додади",
+  "admin_manage": "Уреди",
+  "admin_close": "Затвори",
+  "admin_majors": "Студиски програми",
+  "admin_prerequisites": "Предуслови",
+  "admin_pick_major": "Избери студиска програма",
+  "admin_pick_prerequisite": "Избери предуслов",
+  "admin_pick_subject": "Избери предмет",
+  "admin_pick_professor": "Избери професор",
+  "admin_search_subject": "Пребарај по назив или шифра",
+  "admin_no_subjects": "Нема предмети.",
+  "admin_delete_blocked": "Не може да се избрише: {{count}} запишувања го содржат предметот.",
+  "admin_new_semester": "Отвори нов семестар",
+  "admin_year": "Година",
+  "admin_type": "Тип",
+  "admin_winter": "Зимски",
+  "admin_summer": "Летен",
+  "admin_open_semester": "Отвори семестар",
+  "admin_open_semesters": "Отворени семестри",
+  "admin_no_semesters": "Нема семестри.",
+  "admin_enrolments": "Запишувања",
+  "admin_coverage": "Покриеност",
+  "admin_fully_covered": "сите предмети се покриени",
+  "admin_uncovered_count": "{{count}} предмети без професор",
+  "admin_uncovered_hint": "Студентите не можат да запишат предмет кој никој не го предава.",
+  "admin_show_uncovered": "Прикажи",
+  "admin_professor": "Професор",
+  "admin_assign": "Распореди",
+  "admin_assignments": "Распоред",
+  "admin_load": "Оптовареност",
+  "admin_no_assignments": "Секој нема распоред.",
+  "admin_no_professors": "Нема професори."
+}
Index: frontend/tsconfig.json
===================================================================
--- frontend/tsconfig.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ frontend/tsconfig.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,41 @@
+{
+  "compilerOptions": {
+    "target": "ES2017",
+    "lib": [
+      "dom",
+      "dom.iterable",
+      "esnext"
+    ],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "strict": true,
+    "esModuleInterop": true,
+    "module": "esnext",
+    "moduleResolution": "bundler",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "jsx": "react-jsx",
+    "incremental": true,
+    "plugins": [
+      {
+        "name": "next"
+      }
+    ],
+    "paths": {
+      "@/*": [
+        "./src/*"
+      ]
+    },
+    "noEmit": true
+  },
+  "include": [
+    "next-env.d.ts",
+    "**/*.ts",
+    "**/*.tsx",
+    ".next/types/**/*.ts",
+    ".next/dev/types/**/*.ts"
+  ],
+  "exclude": [
+    "node_modules"
+  ]
+}
Index: iknow-api.sln
===================================================================
--- iknow-api.sln	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api.sln	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,25 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36518.9 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iknow-api", "iknow-api\iknow-api.csproj", "{0812F190-420D-448B-9710-32E746C813B7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0812F190-420D-448B-9710-32E746C813B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0812F190-420D-448B-9710-32E746C813B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0812F190-420D-448B-9710-32E746C813B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0812F190-420D-448B-9710-32E746C813B7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {3E4D4C85-4096-402E-9FC3-19996D358FFE}
+	EndGlobalSection
+EndGlobal
Index: iknow-api/Controllers/AdminController.cs
===================================================================
--- iknow-api/Controllers/AdminController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Controllers/AdminController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,119 @@
+using System.Security.Claims;
+using iknow_api.DTOs;
+using iknow_api.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace iknow_api.Controllers
+{
+    /// <summary>
+    /// UC012 subjects, UC013 active semesters, UC014 professor assignments.
+    /// Every action requires the admin role, checked against the validated token.
+    /// </summary>
+    [ApiController]
+    [Route("api/[controller]")]
+    [Authorize]
+    public class AdminController : ControllerBase
+    {
+        private readonly IAdminService _adminService;
+
+        public AdminController(IAdminService adminService)
+        {
+            _adminService = adminService;
+        }
+
+        // ---------- UC012 ----------
+
+        [HttpGet("subjects")]
+        public async Task<IActionResult> GetSubjects() =>
+            RequireAdmin(out var error) ? Ok(await _adminService.GetSubjectsAsync()) : error;
+
+        [HttpPost("subjects")]
+        public async Task<IActionResult> CreateSubject([FromBody] SubjectWriteDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.CreateSubjectAsync(request)) : error;
+
+        [HttpPut("subjects/{id:int}")]
+        public async Task<IActionResult> UpdateSubject(int id, [FromBody] SubjectWriteDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.UpdateSubjectAsync(id, request)) : error;
+
+        [HttpDelete("subjects/{id:int}")]
+        public async Task<IActionResult> DeleteSubject(int id) =>
+            RequireAdmin(out var error) ? Result(await _adminService.DeleteSubjectAsync(id)) : error;
+
+        [HttpPost("subjects/{id:int}/majors")]
+        public async Task<IActionResult> LinkMajor(int id, [FromBody] MajorLinkDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.LinkMajorAsync(id, request)) : error;
+
+        [HttpDelete("subjects/{id:int}/majors/{majorId:int}")]
+        public async Task<IActionResult> UnlinkMajor(int id, int majorId) =>
+            RequireAdmin(out var error) ? Result(await _adminService.UnlinkMajorAsync(id, majorId)) : error;
+
+        [HttpPost("subjects/{id:int}/prerequisites")]
+        public async Task<IActionResult> AddPrerequisite(int id, [FromBody] PrerequisiteDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.AddPrerequisiteAsync(id, request)) : error;
+
+        [HttpDelete("subjects/{id:int}/prerequisites/{dependencyId:int}")]
+        public async Task<IActionResult> RemovePrerequisite(int id, int dependencyId) =>
+            RequireAdmin(out var error) ? Result(await _adminService.RemovePrerequisiteAsync(id, dependencyId)) : error;
+
+        // ---------- UC013 ----------
+
+        [HttpGet("semesters")]
+        public async Task<IActionResult> GetSemesters() =>
+            RequireAdmin(out var error) ? Ok(await _adminService.GetSemestersAsync()) : error;
+
+        [HttpPost("semesters")]
+        public async Task<IActionResult> CreateSemester([FromBody] SemesterWriteDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.CreateSemesterAsync(request)) : error;
+
+        // ---------- UC014 ----------
+
+        [HttpGet("schedule/{semesterId:int}")]
+        public async Task<IActionResult> GetSchedule(int semesterId)
+        {
+            if (!RequireAdmin(out var error)) return error;
+
+            var schedule = await _adminService.GetScheduleAsync(semesterId);
+            return schedule is null
+                ? NotFound(new AdminResultDto { Ok = false, Message = "Semester not found." })
+                : Ok(schedule);
+        }
+
+        [HttpPost("schedule")]
+        public async Task<IActionResult> Assign([FromBody] ScheduleWriteDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.AssignAsync(request)) : error;
+
+        [HttpDelete("schedule")]
+        public async Task<IActionResult> Unassign([FromBody] ScheduleWriteDto request) =>
+            RequireAdmin(out var error) ? Result(await _adminService.UnassignAsync(request)) : error;
+
+        // ---------- shared ----------
+
+        [HttpGet("majors")]
+        public async Task<IActionResult> GetMajors() =>
+            RequireAdmin(out var error) ? Ok(await _adminService.GetMajorsAsync()) : error;
+
+        private IActionResult Result(AdminResultDto result) =>
+            result.Ok ? Ok(result) : BadRequest(result);
+
+        /// <summary>
+        /// The role comes from the validated token, so it cannot be set by the caller.
+        /// </summary>
+        private bool RequireAdmin(out IActionResult error)
+        {
+            var role = User.FindFirst(ClaimTypes.Role)?.Value ?? User.FindFirst("role")?.Value;
+            if (!string.Equals(role, nameof(Models.UserRole.Admin), StringComparison.OrdinalIgnoreCase))
+            {
+                error = StatusCode(403, new AdminResultDto
+                {
+                    Ok = false,
+                    Message = "This endpoint is for administrators."
+                });
+                return false;
+            }
+
+            error = Ok();
+            return true;
+        }
+    }
+}
Index: iknow-api/Controllers/AuthController.cs
===================================================================
--- iknow-api/Controllers/AuthController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Controllers/AuthController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,86 @@
+﻿using iknow_api.DTOs;
+using iknow_api.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace iknow_api.Controllers
+{
+    [ApiController]
+    [Route("api/[controller]")]
+    public class AuthController : ControllerBase
+    {
+        private readonly IAuthService _authService;
+        private readonly IRefreshTokenService _refreshTokenService;
+
+        public AuthController(IAuthService authService, IRefreshTokenService refreshTokenService)
+        {
+            _authService = authService;
+            _refreshTokenService = refreshTokenService;
+        }
+
+        [HttpGet("testdb")]
+        public async Task<IActionResult> TestDb()
+        {
+            try
+            {
+                var count = await _authService.GetUsersCountAsync();
+                return Ok(new { message = "DB connection works!", usersCount = count });
+            }
+            catch (Exception ex)
+            {
+                return BadRequest(new { message = "DB connection failed", error = ex.Message });
+            }
+        }
+
+        [HttpPost("register")]
+        public async Task<IActionResult> Register([FromBody] RegisterDto request)
+        {
+            try
+            {
+                await _authService.RegisterAsync(request);
+                return Ok("User registered successfully");
+            }
+            catch (InvalidOperationException ex)
+            {
+                return BadRequest(new { message = ex.Message });
+            }
+            catch (Exception ex)
+            {
+                return StatusCode(500, new { message = "An error occurred during registration", error = ex.Message });
+            }
+        }
+
+        [HttpPost("login")]
+        public async Task<IActionResult> Login([FromBody] LoginDto request)
+        {
+            var result = await _authService.LoginAsync(request);
+            if (result == null) return Unauthorized("Invalid credentials");
+
+            return Ok(new
+            {
+                token = result.AccessToken,
+                refreshToken = result.RefreshToken,
+                role = result.Role
+            });
+        }
+
+        [Authorize]
+        [HttpGet("getstring")]
+        public IActionResult getstring()
+        {
+            return Ok(new { message = "You are authorized!" });
+        }
+
+        [HttpPost("verify-user-token")]
+        public async Task<IActionResult> VerifyToken([FromBody] VerifyRefreshTokenDto verifyRefreshToken)
+        {
+            if (await _refreshTokenService.VerifyRefreshToken(verifyRefreshToken))
+            {
+                return Ok(await _authService.GenerateNewJWT(verifyRefreshToken));
+            }
+
+            return BadRequest(new { message = "No token found!" });
+        }
+
+    }
+}
Index: iknow-api/Controllers/DbHealthController.cs
===================================================================
--- iknow-api/Controllers/DbHealthController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Controllers/DbHealthController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,49 @@
+using iknow_api.Data;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace iknow_api.Controllers;
+
+[ApiController]
+[Route("[controller]")]
+public class DbHealthController(AppDbContext db) : ControllerBase
+{
+    /// <summary>
+    /// Verifies that the SSH tunnel is up, the DB credentials work, and that
+    /// the entity mapping matches the schema created by sql/ddl.sql.
+    /// </summary>
+    [HttpGet]
+    public async Task<IActionResult> Get()
+    {
+        try
+        {
+            // EF projects SqlQuery onto a column named "Value", hence the alias.
+            var version = await db.Database
+                .SqlQuery<string>($"SELECT version() AS \"Value\"")
+                .SingleAsync();
+
+            return Ok(new
+            {
+                connected = true,
+                server = version,
+                counts = new
+                {
+                    users = await db.User.CountAsync(),
+                    subjects = await db.Subjects.CountAsync(),
+                    enrolledSemesters = await db.EnrolledSemesters.CountAsync(),
+                    semesterSubjects = await db.SemesterSubjects.CountAsync(),
+                    passedSubjects = await db.PassedSubjects.CountAsync(),
+                }
+            });
+        }
+        catch (Exception ex)
+        {
+            return StatusCode(503, new
+            {
+                connected = false,
+                error = ex.Message,
+                hint = "Is tunnel_scripta.cmd running and listening on localhost:9999?"
+            });
+        }
+    }
+}
Index: iknow-api/Controllers/EnrollmentController.cs
===================================================================
--- iknow-api/Controllers/EnrollmentController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Controllers/EnrollmentController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,78 @@
+using System.Security.Claims;
+using iknow_api.DTOs;
+using iknow_api.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace iknow_api.Controllers
+{
+    [ApiController]
+    [Route("api/[controller]")]
+    [Authorize]
+    public class EnrollmentController : ControllerBase
+    {
+        private readonly IEnrollmentService _enrollmentService;
+
+        public EnrollmentController(IEnrollmentService enrollmentService)
+        {
+            _enrollmentService = enrollmentService;
+        }
+
+        [HttpGet("options")]
+        public async Task<IActionResult> GetOptions()
+        {
+            if (!TryGetStudentId(out var studentId, out var error))
+            {
+                return error;
+            }
+
+            return Ok(await _enrollmentService.GetOptionsAsync(studentId));
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> Enroll([FromBody] EnrollSemesterRequestDto request)
+        {
+            if (!TryGetStudentId(out var studentId, out var error))
+            {
+                return error;
+            }
+
+            var result = await _enrollmentService.EnrollAsync(studentId, request);
+            return result.Ok ? Ok(result) : BadRequest(result);
+        }
+
+        /// <summary>
+        /// Reads the caller from the validated token, so a student can only ever
+        /// enrol themselves.
+        /// </summary>
+        private bool TryGetStudentId(out int studentId, out IActionResult error)
+        {
+            studentId = 0;
+            error = Forbid();
+
+            var role = User.FindFirst(ClaimTypes.Role)?.Value ?? User.FindFirst("role")?.Value;
+            if (!string.Equals(role, nameof(Models.UserRole.Student), StringComparison.OrdinalIgnoreCase))
+            {
+                error = StatusCode(403, new EnrollSemesterResultDto
+                {
+                    Ok = false,
+                    Message = "Only students can enrol in a semester."
+                });
+                return false;
+            }
+
+            var idClaim = User.FindFirst("id")?.Value;
+            if (!int.TryParse(idClaim, out studentId))
+            {
+                error = Unauthorized(new EnrollSemesterResultDto
+                {
+                    Ok = false,
+                    Message = "Token has no usable user id."
+                });
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
Index: iknow-api/Controllers/ProfController.cs
===================================================================
--- iknow-api/Controllers/ProfController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Controllers/ProfController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,93 @@
+using System.Security.Claims;
+using iknow_api.DTOs;
+using iknow_api.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace iknow_api.Controllers
+{
+    [ApiController]
+    [Route("api/[controller]")]
+    [Authorize]
+    public class ProfController : ControllerBase
+    {
+        private readonly IProfService _profService;
+
+        public ProfController(IProfService profService)
+        {
+            _profService = profService;
+        }
+
+        /// <summary>
+        /// The subjects this professor teaches, each with the students enrolled
+        /// in it and their grade so far.
+        /// </summary>
+        [HttpGet("students")]
+        public async Task<IActionResult> GetStudents()
+        {
+            if (!TryGetProfessorId(out var professorId, out var error))
+            {
+                return error;
+            }
+
+            return Ok(await _profService.GetStudentsBySubjectAsync(professorId));
+        }
+
+        [HttpPost("grade/add")]
+        public Task<IActionResult> AddGrade([FromBody] GradeRequestDto request) =>
+            SetGrade(request, GradeAction.Add);
+
+        [HttpPost("grade/edit")]
+        public Task<IActionResult> EditGrade([FromBody] GradeRequestDto request) =>
+            SetGrade(request, GradeAction.Edit);
+
+        [HttpPost("grade/remove")]
+        public Task<IActionResult> RemoveGrade([FromBody] GradeRequestDto request) =>
+            SetGrade(request, GradeAction.Remove);
+
+        private async Task<IActionResult> SetGrade(GradeRequestDto request, GradeAction action)
+        {
+            if (!TryGetProfessorId(out var professorId, out var error))
+            {
+                return error;
+            }
+
+            var result = await _profService.SetGradeAsync(professorId, request, action);
+            return result.Ok ? Ok(result) : BadRequest(result);
+        }
+
+        /// <summary>
+        /// Reads the caller from the validated token and requires the professor
+        /// role, so one professor can never act on another one's subjects.
+        /// </summary>
+        private bool TryGetProfessorId(out int professorId, out IActionResult error)
+        {
+            professorId = 0;
+            error = Forbid();
+
+            var role = User.FindFirst(ClaimTypes.Role)?.Value ?? User.FindFirst("role")?.Value;
+            if (!string.Equals(role, nameof(Models.UserRole.Professor), StringComparison.OrdinalIgnoreCase))
+            {
+                error = StatusCode(403, new GradeResultDto
+                {
+                    Ok = false,
+                    Message = "This endpoint is for professors."
+                });
+                return false;
+            }
+
+            var idClaim = User.FindFirst("id")?.Value;
+            if (!int.TryParse(idClaim, out professorId))
+            {
+                error = Unauthorized(new GradeResultDto
+                {
+                    Ok = false,
+                    Message = "Token has no usable user id."
+                });
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
Index: iknow-api/Controllers/UserController.cs
===================================================================
--- iknow-api/Controllers/UserController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Controllers/UserController.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,348 @@
+using iknow_api.DTOs;
+using iknow_api.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using iknow_api.Services;
+
+namespace iknow_api.Controllers
+{
+    [ApiController]
+    [Route("api/[controller]")]
+    public class UserController : Controller
+    {
+        IUserService _userService;
+        public UserController(IUserService userService)
+        {
+            _userService = userService;
+        }
+
+        //  "birthInfo": {
+        //    "placeOfBirth": "Скопје",
+        //    "municipalityOfBirth": "Скопје",
+        //    "country": "Република Северна Македонија"
+        //  },
+        //  "previousEducation": {
+        //    "type": "Гимназиско образование",
+        //    "profession": "",
+        //    "average": "54,857",
+        //    "language": "Македонски",
+        //    "country": "",
+        //    "previousUniversity": "Гимназиско образование",
+        //    "previousFaculty": "",
+        //    "previousStudyMode": ""
+        //  },
+        //  "enrollmentInfo": {
+        //    "enrollmentYear": "2023",
+        //    "status": "Редовен",
+        //    "cycle": "Прв циклус",
+        //    "program": "Примена на информациски технологии",
+        //    "quota": "Кофинансирање-Редовен (2023, 24600)",
+        //    "secondaryEducationNumber": "",
+        //    "previousEducationCredits": ""
+        //  },
+        //  "contact": {
+        //    "placeOfResidence": "Скопје",
+        //    "municipalityOfResidence": "Кисела Вода - Скопје",
+        //    "country": "Република Северна Македонија",
+        //    "address": "Драчево",
+        //    "temporaryAddress": "",
+        //    "phone": "",
+        //    "mobilePhone": "075295582",
+        //    "passportNumber": "",
+        //    "passportExpiryDate": "",
+        //    "email": "stefansaveski19@gmail.com",
+        //    "microsoftEmail": "stefan.saveski@students.finki.ukim.mk"
+        //  }
+        //}
+        [Authorize]
+        [HttpGet("getUser")]
+        public async Task<IActionResult> getUser()
+        {
+            //{
+            //  "personalInfo": {
+            //    "index": "233149/2023",
+            //    "embg": "/////////////",
+            //    "lastName": "Савески",
+            //    "middleName": "Дејан",
+            //    "firstName": "Стефан",
+            //    "maidenName": "",
+            //    "dateOfBirth": "19.08.2004",
+            //    "gender": "машки",
+            //    "nationality": "Македонец",
+            //    "citizenship": "Република Северна Македонија",
+            //    "scholarship": "Користи",
+            //    "currentPlan": "2023",
+            //    "registryNumber": "",
+            //    "notes": "Систематски преглед Студира 3 години",
+            //    "studyGroup": ""
+            //  },
+            var authHeader = Request.Headers["Authorization"].ToString();
+            if (authHeader.StartsWith("Bearer "))
+            {
+                var token = authHeader.Substring("Bearer ".Length).Trim();
+                // token = your JWT
+                var userData = await _userService.GetUserData(token);
+                if (userData == null) return Ok(new { info = "can't get info" });
+
+                // The study programme comes from the student's most recent
+                // enrolment. Within an academic year winter precedes summer,
+                // so order by year first and put winter ahead of summer.
+                var currentEnrolment = userData.Enrolments?
+                    .Where(es => es.Semester != null)
+                    .OrderByDescending(es => es.Semester!.Year)
+                    .ThenByDescending(es => es.Semester!.Type == sType.summer)
+                    .FirstOrDefault();
+
+                var personalInfo = new
+                {
+                    index = userData.Index ?? "",
+                    embg = userData.EMBG ?? "",
+                    lastName = userData.Surname ?? "",
+                    middleName = "", // Not an attribute of Users in the ER model
+                    firstName = userData.Name ?? "",
+                    maidenName = "", // Property doesn't exist in User model
+                    dateOfBirth = userData.Bday?.ToString("dd.MM.yyyy") ?? "",
+                    gender = "", // Not an attribute of Users in the ER model
+                    nationality = "", // Not an attribute of Users in the ER model
+                    citizenship = "", // Not an attribute of Users in the ER model
+                    scholarship = "",
+                    currentPlan = userData.EnrollmentYear?.ToString() ?? "",
+                    registryNumber = "",
+                    notes = "",
+                    studyGroup = ""
+                };
+                var birthInfo = new
+                {
+                    placeOfBirth = userData.ContactInfo?.City ?? "",
+                    municipalityOfBirth = userData.ContactInfo?.Municipality ?? "",
+                    country = "" // Not an attribute of Users in the ER model
+                };
+                var previousEducation = new
+                {
+                    type = userData.HighSchool?.HighSchoolType.ToString() ?? "",
+                    profession = "",
+                    average = userData.HighSchool?.GPA.ToString() ?? "",
+                    language = "", // Not an attribute of HighSchool in the ER model
+                    country = "",
+                    previousUniversity = userData.HighSchool?.HighSchoolType.ToString() ?? "",
+                    previousFaculty = "", // Property doesn't exist in HighSchool model
+                    previousStudyMode = "" // Property doesn't exist in HighSchool model
+                };
+                var enrollmentInfo = new
+                {
+                    enrollmentYear = userData.EnrollmentYear?.ToString() ?? "",
+                    status = "", // Not an attribute of Users in the ER model
+                    cycle = "Прв циклус",
+                    program = currentEnrolment?.Major?.Name ?? "",
+                    quota = userData.Quota?.ToString() ?? "",
+                    secondaryEducationNumber = "",
+                    previousEducationCredits = ""
+                };
+                var contact = new
+                {
+                    placeOfResidence = userData.ContactInfo?.City ?? "",
+                    municipalityOfResidence = userData.ContactInfo?.Municipality ?? "",
+                    country = "", // Not an attribute of Users in the ER model
+                    address = userData.ContactInfo?.Address ?? "",
+                    temporaryAddress = "",
+                    phone = "",
+                    mobilePhone = userData.ContactInfo?.PhoneNumber ?? "",
+                    passportNumber = "",
+                    passportExpiryDate = "",
+                    email = userData.Email ?? "",
+                    microsoftEmail = userData.ContactInfo?.MicrosoftEmail ?? ""
+                };
+                return Ok(new { personalInfo = personalInfo, birthInfo = birthInfo, previousEducation = previousEducation, enrollmentInfo = enrollmentInfo, contact = contact });
+                //return Ok(new { User = userData });
+            }
+            return null;
+
+        }
+        [Authorize]
+        [HttpGet("getSemesters")]
+        public async Task<IActionResult> getSemesters()
+        {
+            var authHeader = Request.Headers["Authorization"].ToString();
+            if (authHeader.StartsWith("Bearer "))
+            {
+                var token = authHeader.Substring("Bearer ".Length).Trim();
+                // token = your JWT
+                var userData = await _userService.GetUserSemesters(token);
+                var results = new List<object>();
+
+                for (int i = 0; i < userData.Count; i++)
+                {
+                    var newResult = new
+                    {
+                        id = userData[i].Id,
+                        // sType declares summer first, so compare against the member
+                        // rather than the ordinal - == 0 meant summer, not winter.
+                        semester = (userData[i].Semester.Type == sType.winter ? "Зимски" : "Летен") + $"({userData[i].Semester.Year}/{userData[i].Semester.Year + 1})",
+                        direction = userData[i].Major?.Name ?? "",
+                        quota = userData[i].QuotaType.ToString(),
+                        note = userData[i].Note ?? "",
+                        studentCom = userData[i].StudentComment ?? "",
+                        sum = "0,00",
+                        paid = "0,00",
+                        ukim = "",
+                        createdOn = userData[i].CratedAt.ToString("dd.MM.yyyy"),
+                        dateChanged = userData[i].LastChange?.ToString("dd.MM.yyyy") ?? "",
+                        credits = "0,00",
+                        type = "Ред.",
+                        doc = "Не",
+                        doc1 = "Не",
+                        verified = "Не",
+                        taxes = "0,00",
+                        signatures = "0/5",
+                        status = "валиден",
+                        completed = userData[i].Verified.HasValue ? "Да" : "Не"
+                    };
+                    results.Add(newResult);
+                }
+                if (userData == null) return Ok(new { info = "can't get info" });
+                return Ok(new { semesters = results });
+            }
+            return null;
+        }
+
+        [Authorize]
+        [HttpGet("getSubjects")]
+        public async Task<IActionResult> getSubjects()
+        {
+            var authHeader = Request.Headers["Authorization"].ToString();
+            var token = authHeader.Substring("Bearer ".Length).Trim();
+            // token = your JWT
+            var userData = await _userService.GetUserSemesters(token);
+            var results = new List<object>();
+            var random = new Random();
+            for (int i = 0; i < userData.Count; i++)
+            {
+                var newResult = new
+                {
+                    id = userData[i].Id,
+                    name = (userData[i].Semester.Type == sType.winter ? "Зимски" : "Летен") + $"({userData[i].Semester.Year}/{userData[i].Semester.Year + 1})",
+                    status = "валиден",
+                    serviceNumber = 1000000 + random.Next(10000, 100000)
+                };
+                results.Add(newResult);
+            }
+                
+            
+            var subjectsBySemester = new Dictionary<string, List<object>>();
+
+            foreach (var enrollment in userData)
+            {
+                // Create semester key like "winter_2025_2026" or "summer_2025_2026"
+                var semesterType = enrollment.Semester.Type == sType.winter ? "winter" : "summer";
+                var semesterKey = $"{semesterType}_{enrollment.Semester.Year}_{enrollment.Semester.Year + 1}";
+
+                // Initialize list if this semester key doesn't exist
+                if (!subjectsBySemester.ContainsKey(semesterKey))
+                {
+                    subjectsBySemester[semesterKey] = new List<object>();
+                }
+
+                // Add subjects from this semester enrollment
+                if (enrollment.SemesterSubjects != null)
+                {
+                    foreach (var semesterSubject in enrollment.SemesterSubjects)
+                    {
+                        var subject = semesterSubject.Subject;
+                        if (subject != null)
+                        {
+                            var subjectData = new
+                            {
+                                id = subject.Id,
+                                code = subject.Code ?? "",
+                                hours = "2+4", // You may need to add this to your Subject model
+                                kojPat = 1, // You may need to add this field
+                                name = subject.Name ?? "",
+                                semester = 5, // You may need to calculate or add this field
+                                status = "Зад.", // Determine based on PassedSubject or other logic
+                                signature = semesterSubject.Signature ? "Да" : "Не",
+                                group = "", // You may need to add this field
+                                professor = semesterSubject.Professor?.Name + " " + semesterSubject.Professor?.Surname ?? "",
+                            };
+                            subjectsBySemester[semesterKey].Add(subjectData);
+                        }
+                    }
+                }
+                
+            }
+            var currentSemester = userData.FirstOrDefault(); // Get the most recent/current semester
+            var semesterTypeGlobal = currentSemester.Semester.Type == sType.winter ? "winter" : "summer";
+            var semesterData = new
+            {
+                id = $"{semesterTypeGlobal}_{currentSemester.Semester.Year}_{currentSemester.Semester.Year + 1}",
+                name = (currentSemester.Semester.Type == sType.winter ? "Зимски" : "Летен") + $" ({currentSemester.Semester.Year}/{currentSemester.Semester.Year + 1})",
+                status = "валиден",
+                serviceNumber = (1000000 + random.Next(10000, 100000)).ToString(),
+                ticketNumber = random.Next(100000, 1000000).ToString(),
+                debt = "0,00",
+                financialInfo = new
+                {
+                    sum = 1,
+                    paid = "0,00",
+                    due = "0,00",
+                    materialCosts = "Осигурување, Административна такса, Тетратки (испити), зимски семестар: 1000,00",
+                    credits = "30,00",
+                    totalCredits = "30,00",
+                    MKSA = "750,00",
+                    electronicRegistration = "100,00",
+                    eUKIM = "350,00",
+                    bankProvision = "25,00",
+                    total = "2226,00"
+                }
+            };
+            if (userData == null) return Ok(new { info = "can't get info" });
+            //return Ok(new { semester = userData });
+            return Ok(new { semesters = results, currentSemestar = semesterData, subjectsBySemester = subjectsBySemester });
+        }
+
+        [Authorize]
+        [HttpGet("getPassedSubjects")]
+        public async Task<IActionResult> getPassedSubjects()
+        {
+            var authHeader = Request.Headers["Authorization"].ToString();
+            if (!authHeader.StartsWith("Bearer "))
+                return Unauthorized();
+
+            var token = authHeader.Substring("Bearer ".Length).Trim();
+            var passedSubjects = await _userService.GetUserPassedSubjects(token);
+
+            if (passedSubjects == null || !passedSubjects.Any())
+                return Ok(new { info = "No passed subjects found", passedSubjects = new List<object>() });
+
+            var results = new List<object>();
+
+            foreach (var passed in passedSubjects)
+            {
+                if (passed.SemesterSubject?.Subject != null)
+                {
+                    var result = new
+                    {
+                        id = passed.Id,
+                        subjectId = passed.SemesterSubject.Subject.Id,
+                        code = passed.SemesterSubject.Subject.Code ?? "",
+                        subject = passed.SemesterSubject.Subject.Name ?? "",
+                        credits = passed.SemesterSubject.Subject.AwardedCredits ?? 0,
+                        grade = (int)passed.Grade,
+                        gradeText = passed.Grade.ToString(),
+                        date = passed.DatePassed.ToString("dd.MM.yyyy"),
+                        semester = passed.SemesterSubject.EnrolledSemester?.Semester != null
+                            ? (passed.SemesterSubject.EnrolledSemester.Semester.Type == sType.winter ? "Зимски" : "Летен") + 
+                              $" ({passed.SemesterSubject.EnrolledSemester.Semester.Year}/{passed.SemesterSubject.EnrolledSemester.Semester.Year + 1})"
+                            : "",
+                        professor = passed.SemesterSubject.Professor != null
+                            ? $"{passed.SemesterSubject.Professor.Name} {passed.SemesterSubject.Professor.Surname}".Trim()
+                            : ""
+                    };
+                    results.Add(result);
+                }
+            }
+
+            return Ok(new { passedSubjects = results });
+        }
+
+    }
+}
Index: iknow-api/DTOs/AdminDTO.cs
===================================================================
--- iknow-api/DTOs/AdminDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/DTOs/AdminDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,121 @@
+namespace iknow_api.DTOs
+{
+    // ---------- UC012 subjects ----------
+
+    public class AdminSubjectDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? Code { get; set; }
+        public int AwardedCredits { get; set; }
+        public int? DependencyCredit { get; set; }
+        public List<SubjectMajorDto> Majors { get; set; } = new();
+        public List<SubjectRefDto> Prerequisites { get; set; } = new();
+        /// <summary>How many enrolments already contain this subject; it cannot be deleted while this is above zero.</summary>
+        public int EnrolledCount { get; set; }
+    }
+
+    public class SubjectMajorDto
+    {
+        public int MajorId { get; set; }
+        public string? MajorName { get; set; }
+        public int MandatorySemester { get; set; }
+    }
+
+    public class SubjectRefDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? Code { get; set; }
+    }
+
+    public class SubjectWriteDto
+    {
+        public string? Name { get; set; }
+        public string? Code { get; set; }
+        public int AwardedCredits { get; set; }
+        public int? DependencyCredit { get; set; }
+    }
+
+    public class MajorLinkDto
+    {
+        public int MajorId { get; set; }
+        public int MandatorySemester { get; set; }
+    }
+
+    public class PrerequisiteDto
+    {
+        public int DependencyId { get; set; }
+    }
+
+    // ---------- UC013 semesters ----------
+
+    public class AdminSemesterDto
+    {
+        public int Id { get; set; }
+        public int Year { get; set; }
+        public string? Type { get; set; }
+        public string? Name { get; set; }
+        public int EnrolmentCount { get; set; }
+        /// <summary>Subjects with no professor teaching them in this semester.</summary>
+        public List<SubjectRefDto> UncoveredSubjects { get; set; } = new();
+    }
+
+    public class SemesterWriteDto
+    {
+        public int Year { get; set; }
+        /// <summary>"winter" or "summer".</summary>
+        public string? Type { get; set; }
+    }
+
+    // ---------- UC014 schedule ----------
+
+    public class ScheduleDto
+    {
+        public int SemesterId { get; set; }
+        public string? SemesterName { get; set; }
+        public List<ScheduleRowDto> Assignments { get; set; } = new();
+        public List<ProfessorLoadDto> Load { get; set; } = new();
+        public List<SubjectRefDto> UncoveredSubjects { get; set; } = new();
+        public List<SubjectRefDto> AllSubjects { get; set; } = new();
+        public List<ProfessorRefDto> Professors { get; set; } = new();
+    }
+
+    public class ScheduleRowDto
+    {
+        public int SubjectId { get; set; }
+        public string? SubjectName { get; set; }
+        public string? SubjectCode { get; set; }
+        public int ProfessorId { get; set; }
+        public string? ProfessorName { get; set; }
+    }
+
+    public class ProfessorRefDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+    }
+
+    public class ProfessorLoadDto
+    {
+        public int ProfessorId { get; set; }
+        public string? ProfessorName { get; set; }
+        public int Subjects { get; set; }
+    }
+
+    public class ScheduleWriteDto
+    {
+        public int ProfessorId { get; set; }
+        public int SemesterId { get; set; }
+        public int SubjectId { get; set; }
+    }
+
+    // ---------- shared ----------
+
+    public class AdminResultDto
+    {
+        public bool Ok { get; set; }
+        public string? Message { get; set; }
+        public int? Id { get; set; }
+    }
+}
Index: iknow-api/DTOs/EnrollmentDTO.cs
===================================================================
--- iknow-api/DTOs/EnrollmentDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/DTOs/EnrollmentDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,57 @@
+namespace iknow_api.DTOs
+{
+    /// <summary>Everything the enrolment form needs to render.</summary>
+    public class EnrollmentOptionsDto
+    {
+        /// <summary>How many subjects an enrolment must contain.</summary>
+        public int RequiredSubjects { get; set; }
+
+        /// <summary>Semesters this student has not enrolled in yet.</summary>
+        public List<SemesterOptionDto> Semesters { get; set; } = new();
+
+        public List<MajorOptionDto> Majors { get; set; } = new();
+
+        /// <summary>The major from the most recent enrolment, if there is one.</summary>
+        public int? DefaultMajorId { get; set; }
+    }
+
+    public class SemesterOptionDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public int Year { get; set; }
+        public string? Type { get; set; }
+    }
+
+    public class MajorOptionDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public List<SubjectOptionDto> Subjects { get; set; } = new();
+    }
+
+    public class SubjectOptionDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? Code { get; set; }
+        public int Credits { get; set; }
+        public int MandatorySemester { get; set; }
+        /// <summary>True when the student already passed this subject.</summary>
+        public bool AlreadyPassed { get; set; }
+    }
+
+    public class EnrollSemesterRequestDto
+    {
+        public int SemesterId { get; set; }
+        public int MajorId { get; set; }
+        public List<int> SubjectIds { get; set; } = new();
+    }
+
+    public class EnrollSemesterResultDto
+    {
+        public bool Ok { get; set; }
+        public string? Message { get; set; }
+        public int? EnrolledSemesterId { get; set; }
+    }
+}
Index: iknow-api/DTOs/ProfDTO.cs
===================================================================
--- iknow-api/DTOs/ProfDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/DTOs/ProfDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,36 @@
+namespace iknow_api.DTOs
+{
+    /// <summary>One subject a professor teaches, with the students enrolled in it.</summary>
+    public class SubjectStudentsDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? Code { get; set; }
+        public List<EnrolledStudentDto> Users { get; set; } = new();
+    }
+
+    public class EnrolledStudentDto
+    {
+        /// <summary>users.id - what the grading endpoints expect as StudentId.</summary>
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        /// <summary>users.index - the number a professor actually recognises.</summary>
+        public string? Index { get; set; }
+        /// <summary>0 when the subject has not been graded yet.</summary>
+        public int Grade { get; set; }
+        public string? Semester { get; set; }
+    }
+
+    public class GradeRequestDto
+    {
+        public int StudentId { get; set; }
+        public int SubjectId { get; set; }
+        public int Grade { get; set; }
+    }
+
+    public class GradeResultDto
+    {
+        public bool Ok { get; set; }
+        public string? Message { get; set; }
+    }
+}
Index: iknow-api/DTOs/RefreshTokenDTO.cs
===================================================================
--- iknow-api/DTOs/RefreshTokenDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/DTOs/RefreshTokenDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,14 @@
+namespace iknow_api.DTOs
+{
+    public class VerifyRefreshTokenDto
+    {
+        public string token { get; set; } = string.Empty;
+    }
+
+    public class AuthResultDto
+    {
+        public string AccessToken { get; set; } = string.Empty;
+        public string? RefreshToken { get; set; }
+        public string Role { get; set; } = string.Empty;
+    }
+}
Index: iknow-api/DTOs/UserDTO.cs
===================================================================
--- iknow-api/DTOs/UserDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/DTOs/UserDTO.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,74 @@
+﻿using System.Text.Json.Serialization;
+
+namespace iknow_api.DTOs
+{
+    // Login DTO
+    public class LoginDto
+    {
+        public string Email { get; set; } = string.Empty;
+        public string Password { get; set; } = string.Empty;
+        public bool GenerateRefreshToken { get; set; }
+    }
+    public class GetUserDataDto
+    {
+        public string? JWT { get; set; }
+    }
+
+    // Registration DTO
+    public class RegisterDto
+    {
+        public string Name { get; set; } = string.Empty;
+        public string? MiddleName { get; set; }
+        public string Surname { get; set; } = string.Empty;
+        public string EMBG { get; set; } = string.Empty;
+        public string? Index { get; set; }
+        public string Email { get; set; } = string.Empty;
+        public string Password { get; set; } = string.Empty;
+        public DateTime Bday { get; set; }
+        public UserRole Role { get; set; }
+        public float gpa { get; set; }
+        public HighSchoolType tip { get; set; }
+        public string city { get; set; } = string.Empty;
+        public string address { get; set; } = string.Empty;
+        public string municipality { get; set; } = string.Empty;
+        public string phoneNumber { get; set; } = string.Empty;
+        public string microsoftEmail { get; set; } = string.Empty;
+        public int enrollmentYear { get; set; }
+        public Quota quotaType { get; set; }
+        public int majorType { get; set; }
+        public string? gender { get; set; }
+        public string? nationality { get; set; }
+        public string? citizenship { get; set; }
+        public string? studyType { get; set; }
+        public string? studyStatus { get; set; }
+    }
+
+    // User response DTO (for returning user data without password)
+    public class UserResponseDto
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? Surname { get; set; }
+        public string? Index { get; set; }
+        public string? Email { get; set; }
+        public DateTime Bday { get; set; }
+        public DateTime CreatedAt { get; set; }
+        public UserRole Role { get; set; }
+    }
+
+    // User role enum
+    public enum UserRole
+    {
+        Admin,
+        Professor,
+        Student
+    }
+    public enum HighSchoolType
+    {
+        strucen, gimnazija
+    }
+    public enum Quota
+    {
+        drzavna, privatna, stipendija
+    }
+}
Index: iknow-api/Data/AppDbContext.cs
===================================================================
--- iknow-api/Data/AppDbContext.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Data/AppDbContext.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,378 @@
+using Microsoft.EntityFrameworkCore;
+using iknow_api.Models;
+
+namespace iknow_api.Data
+{
+    /// <summary>
+    /// The schema is owned by sql/ddl.sql, not by EF migrations. Every entity
+    /// below is mapped explicitly onto the table and column names in that
+    /// script; nothing here may rely on EF naming conventions.
+    /// </summary>
+    public class AppDbContext : DbContext
+    {
+        /// <summary>
+        /// The schema created by sql/schema_creation.sql. Every table and enum
+        /// type is qualified with it, so nothing depends on search_path.
+        /// </summary>
+        public const string ProjectSchema = "project";
+
+        public AppDbContext(DbContextOptions<AppDbContext> options)
+            : base(options) { }
+
+        public DbSet<User> User { get; set; }
+        public DbSet<ContactInfo> ContactInfo { get; set; }
+        public DbSet<HighSchool> HighSchool { get; set; }
+        public DbSet<RefreshToken> RefreshToken { get; set; }
+        public DbSet<Subject> Subjects { get; set; }
+        public DbSet<DependencySubject> DependencySubjects { get; set; }
+        public DbSet<Major> Majors { get; set; }
+        public DbSet<PassedSubject> PassedSubjects { get; set; }
+        public DbSet<EnrolledSemesters> EnrolledSemesters { get; set; }
+        public DbSet<ActiveSemesters> ActiveSemesters { get; set; }
+        public DbSet<SemesterSubject> SemesterSubjects { get; set; }
+        public DbSet<MajorSubjects> MajorSubjects { get; set; }
+        public DbSet<UserDocuments> UserDocuments { get; set; }
+        public DbSet<Documents> Documents { get; set; }
+        public DbSet<Payment> Payments { get; set; }
+        public DbSet<ProfessorSubjects> ProfessorSubjects { get; set; }
+
+        protected override void OnModelCreating(ModelBuilder modelBuilder)
+        {
+            base.OnModelCreating(modelBuilder);
+
+            // The enum types themselves are declared in ddl.sql; this tells EF
+            // they exist so it does not try to treat the columns as text.
+            modelBuilder.HasPostgresEnum<UserRole>(ProjectSchema, "user_role");
+            modelBuilder.HasPostgresEnum<HighSchoolType>(ProjectSchema, "hs_type");
+            modelBuilder.HasPostgresEnum<Quota>(ProjectSchema, "quota_type");
+            modelBuilder.HasPostgresEnum<sType>(ProjectSchema, "semester_type");
+            modelBuilder.HasPostgresEnum<Grade>(ProjectSchema, "grade_type");
+
+            // -------------------------
+            // users
+            // -------------------------
+            modelBuilder.Entity<User>(e =>
+            {
+                e.ToTable("users", ProjectSchema);
+                e.HasKey(u => u.Id);
+                e.Property(u => u.Id).HasColumnName("id");
+                e.Property(u => u.Name).HasColumnName("name");
+                e.Property(u => u.EMBG).HasColumnName("embg");
+                e.Property(u => u.Surname).HasColumnName("surname");
+                e.Property(u => u.Index).HasColumnName("index");
+                e.Property(u => u.Bday).HasColumnName("bday").HasColumnType("timestamp without time zone");
+                e.Property(u => u.Email).HasColumnName("email");
+                e.Property(u => u.PasswordHash).HasColumnName("password");
+                e.Property(u => u.Role).HasColumnName("role");
+                e.Property(u => u.Quota).HasColumnName("quota");
+                e.Property(u => u.EnrollmentYear).HasColumnName("enrollment_year");
+                e.Property(u => u.CreatedAt).HasColumnName("created_at").HasColumnType("timestamp without time zone");
+                e.HasIndex(u => u.Email).IsUnique();
+            });
+
+            // -------------------------
+            // high_school
+            // -------------------------
+            modelBuilder.Entity<HighSchool>(e =>
+            {
+                e.ToTable("high_school", ProjectSchema);
+                e.HasKey(h => h.Id);
+                e.Property(h => h.Id).HasColumnName("id");
+                e.Property(h => h.UserId).HasColumnName("user_id");
+                e.Property(h => h.GPA).HasColumnName("gpa");
+                e.Property(h => h.HighSchoolType).HasColumnName("type");
+                e.HasOne(h => h.User)
+                 .WithOne(u => u.HighSchool)
+                 .HasForeignKey<HighSchool>(h => h.UserId)
+                 .OnDelete(DeleteBehavior.Restrict);
+            });
+
+            // -------------------------
+            // contact
+            // -------------------------
+            modelBuilder.Entity<ContactInfo>(e =>
+            {
+                e.ToTable("contact", ProjectSchema);
+                e.HasKey(c => c.Id);
+                e.Property(c => c.Id).HasColumnName("id");
+                e.Property(c => c.UserId).HasColumnName("user_id");
+                e.Property(c => c.City).HasColumnName("city");
+                e.Property(c => c.Municipality).HasColumnName("municipality");
+                e.Property(c => c.Address).HasColumnName("address");
+                e.Property(c => c.PhoneNumber).HasColumnName("number");
+                e.Property(c => c.MicrosoftEmail).HasColumnName("microsoft_email");
+                e.HasOne(c => c.User)
+                 .WithOne(u => u.ContactInfo)
+                 .HasForeignKey<ContactInfo>(c => c.UserId)
+                 .OnDelete(DeleteBehavior.Restrict);
+            });
+
+            // -------------------------
+            // major
+            // -------------------------
+            modelBuilder.Entity<Major>(e =>
+            {
+                e.ToTable("major", ProjectSchema);
+                e.HasKey(m => m.Id);
+                e.Property(m => m.Id).HasColumnName("id");
+                e.Property(m => m.Name).HasColumnName("name");
+            });
+
+            // -------------------------
+            // active_semesters
+            // -------------------------
+            modelBuilder.Entity<ActiveSemesters>(e =>
+            {
+                e.ToTable("active_semesters", ProjectSchema);
+                e.HasKey(a => a.Id);
+                e.Property(a => a.Id).HasColumnName("id");
+                e.Property(a => a.Year).HasColumnName("year");
+                e.Property(a => a.Type).HasColumnName("type");
+            });
+
+            // -------------------------
+            // subjects
+            // -------------------------
+            modelBuilder.Entity<Subject>(e =>
+            {
+                e.ToTable("subjects", ProjectSchema);
+                e.HasKey(s => s.Id);
+                e.Property(s => s.Id).HasColumnName("id");
+                e.Property(s => s.Name).HasColumnName("name");
+                e.Property(s => s.Code).HasColumnName("code");
+                e.Property(s => s.AwardedCredits).HasColumnName("awarded_credits");
+                e.Property(s => s.DependencyCredit).HasColumnName("dependency_credit");
+            });
+
+            // -------------------------
+            // enrolled_semesters
+            // -------------------------
+            modelBuilder.Entity<EnrolledSemesters>(e =>
+            {
+                e.ToTable("enrolled_semesters", ProjectSchema);
+                e.HasKey(es => es.Id);
+                e.Property(es => es.Id).HasColumnName("id");
+                e.Property(es => es.UserId).HasColumnName("user_id");
+                e.Property(es => es.QuotaType).HasColumnName("quota");
+                e.Property(es => es.MajorId).HasColumnName("major_id");
+                e.Property(es => es.Note).HasColumnName("note");
+                e.Property(es => es.StudentComment).HasColumnName("student_comment");
+                e.Property(es => es.CratedAt).HasColumnName("created_at").HasColumnType("timestamp without time zone");
+                e.Property(es => es.LastChange).HasColumnName("last_change").HasColumnType("timestamp without time zone");
+                e.Property(es => es.Verified).HasColumnName("completed").HasColumnType("timestamp without time zone");
+                e.Property(es => es.SemesterId).HasColumnName("semester_id");
+
+                e.HasOne(es => es.User)
+                 .WithMany(u => u.Enrolments)
+                 .HasForeignKey(es => es.UserId)
+                 .OnDelete(DeleteBehavior.Restrict);
+
+                // Note: this deliberately keys off SemesterId. An earlier version
+                // pointed the foreign key at es.Id, which silently tied every
+                // enrolment to the semester that happened to share its id.
+                e.HasOne(es => es.Semester)
+                 .WithMany(a => a.EnrolledSemesters)
+                 .HasForeignKey(es => es.SemesterId)
+                 .OnDelete(DeleteBehavior.Restrict);
+
+                e.HasOne(es => es.Major)
+                 .WithMany()
+                 .HasForeignKey(es => es.MajorId)
+                 .OnDelete(DeleteBehavior.Restrict);
+            });
+
+            // -------------------------
+            // semesters_subjects
+            // -------------------------
+            modelBuilder.Entity<SemesterSubject>(e =>
+            {
+                e.ToTable("semesters_subjects", ProjectSchema);
+                e.HasKey(ss => ss.Id);
+                e.Property(ss => ss.Id).HasColumnName("id");
+                e.Property(ss => ss.EnrolledSemesterId).HasColumnName("enrolled_semesters_id");
+                e.Property(ss => ss.SubjectId).HasColumnName("subjects_id");
+                e.Property(ss => ss.ProfessorId).HasColumnName("professor_id");
+                e.Property(ss => ss.Signature).HasColumnName("signature");
+
+                e.HasOne(ss => ss.Professor)
+                 .WithMany(u => u.TeachingSubjects)
+                 .HasForeignKey(ss => ss.ProfessorId)
+                 .OnDelete(DeleteBehavior.Restrict);
+
+                e.HasOne(ss => ss.Subject)
+                 .WithMany(s => s.SemesterSubjects)
+                 .HasForeignKey(ss => ss.SubjectId)
+                 .OnDelete(DeleteBehavior.Restrict);
+
+                e.HasOne(ss => ss.EnrolledSemester)
+                 .WithMany(es => es.SemesterSubjects)
+                 .HasForeignKey(ss => ss.EnrolledSemesterId)
+                 .OnDelete(DeleteBehavior.Restrict);
+            });
+
+            // -------------------------
+            // passed_subjects
+            // -------------------------
+            modelBuilder.Entity<PassedSubject>(e =>
+            {
+                e.ToTable("passed_subjects", ProjectSchema);
+                e.HasKey(ps => ps.Id);
+                e.Property(ps => ps.Id).HasColumnName("id");
+                e.Property(ps => ps.SemesterSubjectId).HasColumnName("enrolled_id");
+                e.Property(ps => ps.Grade).HasColumnName("grade");
+                e.Property(ps => ps.DatePassed).HasColumnName("date_passed").HasColumnType("timestamp without time zone");
+
+                e.HasOne(ps => ps.SemesterSubject)
+                 .WithOne(ss => ss.PassedSubject)
+                 .HasForeignKey<PassedSubject>(ps => ps.SemesterSubjectId)
+                 .OnDelete(DeleteBehavior.Cascade);
+            });
+
+            // -------------------------
+            // documents
+            // -------------------------
+            modelBuilder.Entity<Documents>(e =>
+            {
+                e.ToTable("documents", ProjectSchema);
+                e.HasKey(d => d.Id);
+                e.Property(d => d.Id).HasColumnName("id");
+                e.Property(d => d.Name).HasColumnName("type");
+                e.Property(d => d.Body).HasColumnName("body");
+                e.Property(d => d.Cost).HasColumnName("cost");
+            });
+
+            // -------------------------
+            // user_documents
+            // -------------------------
+            modelBuilder.Entity<UserDocuments>(e =>
+            {
+                e.ToTable("user_documents", ProjectSchema);
+                e.HasKey(ud => new { ud.UserId, ud.DocumentId });
+                e.Property(ud => ud.UserId).HasColumnName("user_id");
+                e.Property(ud => ud.DocumentId).HasColumnName("document_id");
+
+                e.HasOne(ud => ud.User)
+                 .WithMany(u => u.Documents)
+                 .HasForeignKey(ud => ud.UserId)
+                 .OnDelete(DeleteBehavior.Cascade);
+
+                e.HasOne(ud => ud.Documents)
+                 .WithMany(d => d.User)
+                 .HasForeignKey(ud => ud.DocumentId)
+                 .OnDelete(DeleteBehavior.Cascade);
+            });
+
+            // -------------------------
+            // token
+            // -------------------------
+            modelBuilder.Entity<RefreshToken>(e =>
+            {
+                e.ToTable("token", ProjectSchema);
+                e.HasKey(t => t.Id);
+                e.Property(t => t.Id).HasColumnName("id");
+                e.Property(t => t.UserId).HasColumnName("user_id");
+                e.Property(t => t.Token).HasColumnName("token");
+                e.Property(t => t.ExpiresAt).HasColumnName("expires_at").HasColumnType("timestamp without time zone");
+                e.Property(t => t.IsValid).HasColumnName("is_valid");
+
+                e.HasOne(t => t.User)
+                 .WithMany()
+                 .HasForeignKey(t => t.UserId)
+                 .OnDelete(DeleteBehavior.Cascade);
+            });
+
+            // -------------------------
+            // payment
+            // -------------------------
+            modelBuilder.Entity<Payment>(e =>
+            {
+                e.ToTable("payment", ProjectSchema);
+                e.HasKey(p => p.Id);
+                e.Property(p => p.Id).HasColumnName("id");
+                e.Property(p => p.UserId).HasColumnName("user_id");
+                e.Property(p => p.EnrollmentInfoId).HasColumnName("enrollment_id");
+                e.Property(p => p.Amount).HasColumnName("amount");
+
+                e.HasOne(p => p.User)
+                 .WithMany(u => u.Payments)
+                 .HasForeignKey(p => p.UserId)
+                 .OnDelete(DeleteBehavior.Cascade);
+
+                e.HasOne(p => p.EnrolledSemesters)
+                 .WithMany(es => es.Users)
+                 .HasForeignKey(p => p.EnrollmentInfoId)
+                 .OnDelete(DeleteBehavior.Cascade);
+            });
+
+            // -------------------------
+            // major_subjects
+            // -------------------------
+            modelBuilder.Entity<MajorSubjects>(e =>
+            {
+                e.ToTable("major_subjects", ProjectSchema);
+                e.HasKey(ms => new { ms.MajorId, ms.SubjectId });
+                e.Property(ms => ms.MajorId).HasColumnName("major_id");
+                e.Property(ms => ms.SubjectId).HasColumnName("subject_id");
+                e.Property(ms => ms.MandatorySemester).HasColumnName("mandatory_semester");
+
+                e.HasOne(ms => ms.Majors)
+                 .WithMany(m => m.Subjects)
+                 .HasForeignKey(ms => ms.MajorId)
+                 .OnDelete(DeleteBehavior.Cascade);
+
+                e.HasOne(ms => ms.Subjects)
+                 .WithMany(s => s.Majors)
+                 .HasForeignKey(ms => ms.SubjectId)
+                 .OnDelete(DeleteBehavior.Cascade);
+            });
+
+            // -------------------------
+            // dependency_subject
+            // -------------------------
+            modelBuilder.Entity<DependencySubject>(e =>
+            {
+                e.ToTable("dependency_subject", ProjectSchema);
+                e.HasKey(ds => new { ds.SubjectId, ds.DependencyId });
+                e.Property(ds => ds.SubjectId).HasColumnName("subject_id");
+                e.Property(ds => ds.DependencyId).HasColumnName("dependency_id");
+
+                e.HasOne(ds => ds.Subject)
+                 .WithMany(s => s.Dependencies)
+                 .HasForeignKey(ds => ds.SubjectId)
+                 .OnDelete(DeleteBehavior.Restrict);
+
+                e.HasOne(ds => ds.Dependency)
+                 .WithMany(s => s.Dependents)
+                 .HasForeignKey(ds => ds.DependencyId)
+                 .OnDelete(DeleteBehavior.Restrict);
+            });
+
+            // -------------------------
+            // professour_subjects  (spelling matches the table in ddl.sql)
+            // -------------------------
+            modelBuilder.Entity<ProfessorSubjects>(e =>
+            {
+                e.ToTable("professour_subjects", ProjectSchema);
+                e.HasKey(ps => new { ps.ProfessorId, ps.SemesterId, ps.SubjectId });
+                e.Property(ps => ps.ProfessorId).HasColumnName("prof_id");
+                e.Property(ps => ps.SemesterId).HasColumnName("active_semester_id");
+                e.Property(ps => ps.SubjectId).HasColumnName("subject_id");
+
+                e.HasOne(ps => ps.Professor)
+                 .WithMany()
+                 .HasForeignKey(ps => ps.ProfessorId)
+                 .OnDelete(DeleteBehavior.Cascade);
+
+                e.HasOne(ps => ps.Semester)
+                 .WithMany()
+                 .HasForeignKey(ps => ps.SemesterId)
+                 .OnDelete(DeleteBehavior.Cascade);
+
+                e.HasOne(ps => ps.Subject)
+                 .WithMany()
+                 .HasForeignKey(ps => ps.SubjectId)
+                 .OnDelete(DeleteBehavior.Cascade);
+            });
+        }
+    }
+}
Index: iknow-api/Data/PgEnumLabels.cs
===================================================================
--- iknow-api/Data/PgEnumLabels.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Data/PgEnumLabels.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,49 @@
+using iknow_api.Models;
+using Npgsql;
+
+namespace iknow_api.Data
+{
+    /// <summary>
+    /// Maps CLR enum member names onto the labels declared in sql/ddl.sql.
+    /// Most labels are just the lowercased member name; the ones that are not
+    /// (UserRole.Professor -> 'prof', Grade.Ten -> '10') are listed explicitly.
+    ///
+    /// The instances are static on purpose. EF Core caches its internal service
+    /// provider against the DbContext options, and a fresh translator instance
+    /// on every resolution makes each set of options look different - EF then
+    /// builds a new provider per resolution and throws
+    /// ManyServiceProvidersCreatedWarning once it has built twenty.
+    /// </summary>
+    public sealed class PgEnumLabels : INpgsqlNameTranslator
+    {
+        public static readonly PgEnumLabels UserRole = new(
+            new Dictionary<string, string>
+            {
+                [nameof(Models.UserRole.Admin)] = "admin",
+                [nameof(Models.UserRole.Professor)] = "prof",
+                [nameof(Models.UserRole.Student)] = "student",
+            });
+
+        public static readonly PgEnumLabels Grade = new(
+            new Dictionary<string, string>
+            {
+                [nameof(Models.Grade.Six)] = "6",
+                [nameof(Models.Grade.Seven)] = "7",
+                [nameof(Models.Grade.Eight)] = "8",
+                [nameof(Models.Grade.Nine)] = "9",
+                [nameof(Models.Grade.Ten)] = "10",
+            });
+
+        /// <summary>Lowercases the member name, which is all the other enums need.</summary>
+        public static readonly PgEnumLabels Lowercase = new(new Dictionary<string, string>());
+
+        private readonly IReadOnlyDictionary<string, string> _labels;
+
+        private PgEnumLabels(IReadOnlyDictionary<string, string> labels) => _labels = labels;
+
+        public string TranslateTypeName(string clrName) => clrName;
+
+        public string TranslateMemberName(string clrName) =>
+            _labels.TryGetValue(clrName, out var label) ? label : clrName.ToLowerInvariant();
+    }
+}
Index: iknow-api/Models/ActiveSemester.cs
===================================================================
--- iknow-api/Models/ActiveSemester.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/ActiveSemester.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,18 @@
+
+
+
+
+namespace iknow_api.Models
+{
+    public enum sType
+    {
+        summer,winter
+    }
+    public class ActiveSemesters
+    {
+        public int Id { get; set; }
+        public int Year { get; set; }
+        public sType Type { get; set; }
+        public ICollection<EnrolledSemesters>? EnrolledSemesters { get; set; }
+    }
+}
Index: iknow-api/Models/ContactInfo.cs
===================================================================
--- iknow-api/Models/ContactInfo.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/ContactInfo.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,17 @@
+﻿using System.ComponentModel.DataAnnotations.Schema;
+
+namespace iknow_api.Models
+{
+    public class ContactInfo
+    {
+        public int Id { get; set; }
+        public string? City { get; set; }
+        public string? Address { get; set; }
+        public string? Municipality { get; set; }
+        public string? PhoneNumber { get; set; }
+        public string? MicrosoftEmail { get; set; }
+        
+        public int UserId { get; set; }
+        public User? User { get; set; }
+    }
+}
Index: iknow-api/Models/DependencySubject.cs
===================================================================
--- iknow-api/Models/DependencySubject.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/DependencySubject.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,10 @@
+namespace iknow_api.Models
+{
+    public class DependencySubject
+    {
+        public int SubjectId { get; set; }
+        public int DependencyId { get; set; }
+        public Subject? Subject { get; set; }
+        public Subject? Dependency { get; set; }
+    }
+}
Index: iknow-api/Models/Documents.cs
===================================================================
--- iknow-api/Models/Documents.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/Documents.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,11 @@
+namespace iknow_api.Models
+{
+    public class Documents
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? Body { get; set; }
+        public int Cost { get; set; }
+        public ICollection<UserDocuments>? User { get; set; }
+    }
+}
Index: iknow-api/Models/EnrolledSemesters.cs
===================================================================
--- iknow-api/Models/EnrolledSemesters.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/EnrolledSemesters.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,24 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace iknow_api.Models
+{
+    public class EnrolledSemesters
+    {
+        //Add type of semester winter/summer
+        public int Id { get; set; }
+        public int UserId { get; set; }
+        public User? User { get; set; }
+        public Quota QuotaType { get; set; }
+        public int MajorId { get; set; }
+        public string? StudentComment { get; set; }
+        public string? Note { get; set; }
+        public DateTime CratedAt { get; set; }
+        public DateTime? LastChange { get; set; }
+        public DateTime? Verified { get; set; }
+        public int SemesterId { get; set; }
+        public ActiveSemesters? Semester { get; set; }
+        public Major? Major { get; set; }
+        public ICollection<Payment>? Users { get; set; }
+        public ICollection<SemesterSubject>? SemesterSubjects { get; set; }
+    }
+}
Index: iknow-api/Models/HighSchool.cs
===================================================================
--- iknow-api/Models/HighSchool.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/HighSchool.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,16 @@
+namespace iknow_api.Models
+{
+    public enum HighSchoolType
+    {
+        Strucen, Gimnazija
+    }
+
+    public class HighSchool
+    {
+        public int Id { get; set; }
+        public float GPA { get; set; }
+        public HighSchoolType HighSchoolType { get; set; }
+        public int UserId { get; set; }
+        public User? User { get; set; }
+    }
+}
Index: iknow-api/Models/Major.cs
===================================================================
--- iknow-api/Models/Major.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/Major.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,12 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace iknow_api.Models
+{
+    public class Major
+    {
+        public int Id { get; set; }
+
+        public string? Name { get; set; }
+        public ICollection<MajorSubjects>? Subjects { get; set; }
+    }
+}
Index: iknow-api/Models/MajorSubjects.cs
===================================================================
--- iknow-api/Models/MajorSubjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/MajorSubjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,11 @@
+namespace iknow_api.Models
+{
+    public class MajorSubjects
+    {
+        public int MajorId { get; set; }
+        public int SubjectId { get; set; }
+        public int MandatorySemester { get; set; }
+        public Major? Majors { get; set; }
+        public Subject? Subjects { get; set; }
+    }
+}
Index: iknow-api/Models/PassedSubject.cs
===================================================================
--- iknow-api/Models/PassedSubject.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/PassedSubject.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,20 @@
+namespace iknow_api.Models
+{
+    public enum Grade
+    {
+        Six = 6,
+        Seven = 7,
+        Eight = 8,
+        Nine = 9,
+        Ten = 10
+    }
+
+    public class PassedSubject
+    {
+        public int Id { get; set; }
+        public int SemesterSubjectId { get; set; }
+        public SemesterSubject? SemesterSubject { get; set; }
+        public Grade Grade { get; set; }
+        public DateTime DatePassed { get; set; }
+    }
+}
Index: iknow-api/Models/Payment.cs
===================================================================
--- iknow-api/Models/Payment.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/Payment.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace iknow_api.Models
+{
+    public class Payment
+    {
+        public int Id { get; set; }
+
+        public int UserId { get; set; }
+        public User? User { get; set; }
+        public int EnrollmentInfoId { get; set; }
+        public int Amount { get; set; }
+        public EnrolledSemesters? EnrolledSemesters { get; set; }
+
+    }
+}
Index: iknow-api/Models/ProfessorSubjects.cs
===================================================================
--- iknow-api/Models/ProfessorSubjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/ProfessorSubjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,14 @@
+﻿
+namespace iknow_api.Models
+{
+    public class ProfessorSubjects
+    {
+        public int ProfessorId { get; set; }
+        public User? Professor { get; set; }
+        public int SemesterId { get; set; }
+        public ActiveSemesters? Semester { get; set; }
+        public int SubjectId { get; set; }
+        public Subject? Subject { get; set; }
+    }
+}
+
Index: iknow-api/Models/Quota.cs
===================================================================
--- iknow-api/Models/Quota.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/Quota.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,7 @@
+namespace iknow_api.Models
+{
+    public enum Quota
+    {
+        drzavna, privatna, stipendija
+    }
+}
Index: iknow-api/Models/RefreshToken.cs
===================================================================
--- iknow-api/Models/RefreshToken.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/RefreshToken.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,14 @@
+using iknow_api.Models;
+
+namespace iknow_api.Models
+{
+    public class RefreshToken
+    {
+        public int Id { get; set; }
+        public int UserId { get; set; }
+        public User? User { get; set; } 
+        public string? Token { get; set; }
+        public DateTime ExpiresAt { get; set; }
+        public bool IsValid { get; set; }
+    }
+}
Index: iknow-api/Models/SemesterSubjects.cs
===================================================================
--- iknow-api/Models/SemesterSubjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/SemesterSubjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,19 @@
+namespace iknow_api.Models
+{
+    // The student is reached through EnrolledSemester.UserId; the ER model
+    // links SemestersSubjects to Users only through the professor.
+    public class SemesterSubject
+    {
+        public int Id { get; set; }
+
+        public int EnrolledSemesterId { get; set; }
+        public int SubjectId { get; set; }
+        public int ProfessorId { get; set; }
+        public bool Signature { get; set; }
+
+        public EnrolledSemesters? EnrolledSemester { get; set; }
+        public Subject? Subject { get; set; }
+        public User? Professor { get; set; }
+        public PassedSubject? PassedSubject { get; set; }
+    }
+}
Index: iknow-api/Models/Subjects.cs
===================================================================
--- iknow-api/Models/Subjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/Subjects.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,16 @@
+namespace iknow_api.Models
+{
+    public class Subject
+    {
+        public int Id { get; set; }                       
+        public string? Name { get; set; }                 
+        public string? Code { get; set; }                  
+        public int? AwardedCredits { get; set; } 
+        public int? DependencyCredit { get; set; }
+        public ICollection<DependencySubject>? Dependencies { get; set; }   
+        public ICollection<DependencySubject>? Dependents { get; set; }
+        public ICollection<MajorSubjects>? Majors { get; set; }
+        public ICollection<SemesterSubject>? SemesterSubjects { get; set; }
+        
+    }
+}
Index: iknow-api/Models/User.cs
===================================================================
--- iknow-api/Models/User.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/User.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,39 @@
+namespace iknow_api.Models
+{
+    public enum UserRole
+    {
+        Admin,
+        Professor,
+        Student
+    }
+
+    // Attributes follow the Users entity in the ER model exactly.
+    public class User
+    {
+        public int Id { get; set; }
+        public string? Name { get; set; }
+        public string? EMBG { get; set; }
+        public string? Surname { get; set; }
+        public string? Index { get; set; }
+        public string? Email { get; set; }
+        public string? PasswordHash { get; set; }
+        public DateTime? Bday { get; set; }
+        public DateTime CreatedAt { get; set; }
+        public UserRole Role { get; set; }
+        public Quota? Quota { get; set; }
+        public int? EnrollmentYear { get; set; }
+
+        public HighSchool? HighSchool { get; set; }
+        public ContactInfo? ContactInfo { get; set; }
+        public ICollection<UserDocuments>? Documents { get; set; }
+
+        // Named for the relationship it carries: Users 1 --pays-- N Payment.
+        public ICollection<Payment>? Payments { get; set; }
+
+        // Users 1 --submits-- N EnrolledSemesters
+        public ICollection<EnrolledSemesters>? Enrolments { get; set; }
+
+        // Users 1 --teaches-- N SemestersSubjects
+        public ICollection<SemesterSubject>? TeachingSubjects { get; set; }
+    }
+}
Index: iknow-api/Models/UserDocuments.cs
===================================================================
--- iknow-api/Models/UserDocuments.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Models/UserDocuments.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,10 @@
+namespace iknow_api.Models
+{
+    public class UserDocuments
+    {
+        public int UserId { get; set; }
+        public int DocumentId { get; set; }
+        public User? User{ get; set; }
+        public Documents? Documents{ get; set; }
+    }
+}
Index: iknow-api/Program.cs
===================================================================
--- iknow-api/Program.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Program.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,109 @@
+using System.Text;
+using System.Text.Json.Serialization;
+using iknow_api.Data;
+using iknow_api.Models;
+using iknow_api.Repositories;
+using iknow_api.Services;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.IdentityModel.Tokens;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add CORS policy
+builder.Services.AddCors(options =>
+{
+    options.AddPolicy("AllowFrontend", policy =>
+    {
+        var allowedOrigins = builder.Configuration.GetSection("AllowedOrigins").Get<string[]>() 
+            ?? new[] { "http://localhost:3000" };
+        
+        policy.WithOrigins(allowedOrigins) // Your frontend URL(s)
+              .AllowAnyHeader()
+              .AllowAnyMethod()
+              .AllowCredentials();
+    });
+});
+
+builder.Services.AddAuthentication(options =>
+{
+    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
+    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
+})
+.AddJwtBearer(options =>
+{
+    options.RequireHttpsMetadata = false; // only for development
+    options.SaveToken = true;
+    options.TokenValidationParameters = new TokenValidationParameters
+    {
+        ValidateIssuer = true,
+        ValidIssuer = "iknow-api",
+
+        ValidateAudience = true,
+        ValidAudience = "iknow-api",
+
+        ValidateLifetime = true,
+
+        ValidateIssuerSigningKey = true,
+        IssuerSigningKey = new SymmetricSecurityKey(
+            Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
+    };
+});
+// Add services to the container.
+builder.Services.AddControllers()
+    .AddJsonOptions(options =>
+    {
+        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
+        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
+        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
+    });
+builder.Services.AddOpenApi();
+
+// Register DbContext.
+// The database lives behind the SSH tunnel: tunnel_scripta.cmd maps
+// localhost:9999 to the faculty Postgres server. Start it before the API.
+// The enum labels come from sql/ddl.sql, so each CLR enum is mapped onto its
+// Postgres type by name; PgEnumLabels covers the members whose label is not
+// simply the lowercased member name.
+builder.Services.AddDbContext<AppDbContext>(options =>
+    options.UseNpgsql(
+        builder.Configuration.GetConnectionString("DefaultConnection"),
+        npgsql =>
+        {
+            npgsql.MapEnum<UserRole>("user_role", AppDbContext.ProjectSchema, PgEnumLabels.UserRole);
+            npgsql.MapEnum<HighSchoolType>("hs_type", AppDbContext.ProjectSchema, PgEnumLabels.Lowercase);
+            npgsql.MapEnum<Quota>("quota_type", AppDbContext.ProjectSchema, PgEnumLabels.Lowercase);
+            npgsql.MapEnum<sType>("semester_type", AppDbContext.ProjectSchema, PgEnumLabels.Lowercase);
+            npgsql.MapEnum<Grade>("grade_type", AppDbContext.ProjectSchema, PgEnumLabels.Grade);
+        }));
+
+// Register your services
+builder.Services.AddScoped<IAuthService, AuthService>();
+builder.Services.AddScoped<IUserRepository, UserRepository>(); // You'll need to add the UserRepository implementation
+builder.Services.AddScoped<IUserService, UserService>();
+
+builder.Services.AddScoped<IRefreshTokenService, RefreshTokenService>();
+builder.Services.AddScoped<IUserRepository, UserRepository>(); 
+builder.Services.AddScoped<IRefreshTokenRepository, RefreshTokenRepository>(); 
+builder.Services.AddScoped<IProfRepository, ProfRepository>();
+builder.Services.AddScoped<IProfService, ProfService>();
+builder.Services.AddScoped<IEnrollmentService, EnrollmentService>();
+builder.Services.AddScoped<IAdminService, AdminService>();
+builder.Services.AddAuthorization();
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+    app.MapOpenApi();
+}
+
+// Enable CORS - must be called before UseAuthentication and UseAuthorization
+app.UseCors("AllowFrontend");
+
+app.UseHttpsRedirection();
+app.UseAuthentication(); // <-- must come BEFORE UseAuthorization
+app.UseAuthorization();
+app.MapControllers();
+
+app.Run();
Index: iknow-api/Properties/launchSettings.json
===================================================================
--- iknow-api/Properties/launchSettings.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Properties/launchSettings.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,23 @@
+﻿{
+  "$schema": "https://json.schemastore.org/launchsettings.json",
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": false,
+      "applicationUrl": "http://localhost:5147",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "https": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": false,
+      "applicationUrl": "https://localhost:7248;http://localhost:5147",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}
Index: iknow-api/Repository/Implementations/ProfRepository.cs
===================================================================
--- iknow-api/Repository/Implementations/ProfRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Repository/Implementations/ProfRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,77 @@
+using iknow_api.Data;
+using iknow_api.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace iknow_api.Repositories
+{
+    public class ProfRepository : IProfRepository
+    {
+        private readonly AppDbContext _context;
+
+        public ProfRepository(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        /// <summary>
+        /// A professor teaches a subject for a given enrolment, so the students
+        /// are reached through semesters_subjects.professor_id and the student
+        /// through the enrolment - matching the ER model, which does not link
+        /// SemestersSubjects to a student directly.
+        /// </summary>
+        private IQueryable<SemesterSubject> TaughtBy(int professorId) =>
+            _context.SemesterSubjects
+                .Where(ss => ss.ProfessorId == professorId)
+                .Include(ss => ss.Subject)
+                .Include(ss => ss.PassedSubject)
+                .Include(ss => ss.EnrolledSemester!)
+                    .ThenInclude(es => es.User)
+                .Include(ss => ss.EnrolledSemester!)
+                    .ThenInclude(es => es.Semester);
+
+        public async Task<List<SemesterSubject>> GetTaughtSemesterSubjectsAsync(int professorId) =>
+            await TaughtBy(professorId)
+                .AsNoTracking()
+                .AsSplitQuery()
+                .ToListAsync();
+
+        public async Task<SemesterSubject?> FindTaughtSemesterSubjectAsync(
+            int professorId, int studentId, int subjectId)
+        {
+            var candidates = await TaughtBy(professorId)
+                .Where(ss => ss.SubjectId == subjectId
+                          && ss.EnrolledSemester!.UserId == studentId)
+                .AsSplitQuery()
+                .ToListAsync();
+
+            // Most recent enrolment first. Semesters are labelled Year/Year+1
+            // throughout the app, so within one year summer follows winter.
+            return candidates
+                .OrderByDescending(ss => ss.EnrolledSemester!.Semester!.Year)
+                .ThenByDescending(ss => ss.EnrolledSemester!.Semester!.Type == sType.summer)
+                .FirstOrDefault();
+        }
+
+        public async Task<PassedSubject?> GetPassedSubjectAsync(int semesterSubjectId) =>
+            await _context.PassedSubjects
+                .FirstOrDefaultAsync(ps => ps.SemesterSubjectId == semesterSubjectId);
+
+        public async Task AddPassedSubjectAsync(PassedSubject passed)
+        {
+            _context.PassedSubjects.Add(passed);
+            await _context.SaveChangesAsync();
+        }
+
+        public async Task UpdatePassedSubjectAsync(PassedSubject passed)
+        {
+            _context.PassedSubjects.Update(passed);
+            await _context.SaveChangesAsync();
+        }
+
+        public async Task RemovePassedSubjectAsync(PassedSubject passed)
+        {
+            _context.PassedSubjects.Remove(passed);
+            await _context.SaveChangesAsync();
+        }
+    }
+}
Index: iknow-api/Repository/Implementations/RefreshTokenRepository.cs
===================================================================
--- iknow-api/Repository/Implementations/RefreshTokenRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Repository/Implementations/RefreshTokenRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,49 @@
+using iknow_api.Models;
+using iknow_api.Data;
+using iknow_api.Models;
+using Microsoft.EntityFrameworkCore;
+using iknow_api.Services;
+using iknow_api.DTOs;
+using System.Runtime.CompilerServices;
+
+namespace iknow_api.Repositories
+{
+    public class RefreshTokenRepository : IRefreshTokenRepository
+    {
+        private readonly AppDbContext _context;
+
+        public RefreshTokenRepository(AppDbContext context)
+        {
+            _context = context;
+        }
+        
+        public async Task AddTokenAsync(RefreshToken refreshToken)
+        {
+             _context.RefreshToken.Add(refreshToken);
+            await _context.SaveChangesAsync();
+        }
+
+        public Task<bool> DeleteTokenAsync(string refreshTokenDto)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<int?> GetUserId(string refreshTokenDto)
+        {
+            var token = await _context.RefreshToken.FirstOrDefaultAsync(u => u.Token == refreshTokenDto);
+            return token?.UserId ;
+        }
+
+        public async Task<bool> VerifyTokenAsync(VerifyRefreshTokenDto refreshTokenDto)
+        {
+            var token = await _context.RefreshToken
+                .FirstOrDefaultAsync(rt =>
+                    rt.Token == refreshTokenDto.token &&
+                    rt.IsValid &&
+                    rt.ExpiresAt > DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified));
+
+            return token != null;
+        }
+
+    }
+}
Index: iknow-api/Repository/Implementations/UserRepository.cs
===================================================================
--- iknow-api/Repository/Implementations/UserRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Repository/Implementations/UserRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,99 @@
+using iknow_api.Models;
+using iknow_api.Data;
+using Microsoft.EntityFrameworkCore;
+
+namespace iknow_api.Repositories
+{
+    public class UserRepository : IUserRepository
+    {
+        private readonly AppDbContext _context;
+
+        public UserRepository(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        public async Task<bool> UserExistsAsync(string username)
+        {
+            return await _context.User.AnyAsync(u => u.Email == username);
+        }
+
+        public async Task<User?> GetUserByUsernameAsync(string username)
+        {
+            return await _context.User.FirstOrDefaultAsync(u => u.Email == username);
+        }
+        
+        public async Task<User?> GetUserByIdAsync(int id)
+        {
+            return await _context.User
+                .Include(u => u.ContactInfo)
+                .Include(u => u.HighSchool)
+                // The study programme is reached through the enrolment, since
+                // Major hangs off EnrolledSemesters rather than off Users.
+                .Include(u => u.Enrolments!)
+                    .ThenInclude(es => es.Major)
+                .Include(u => u.Enrolments!)
+                    .ThenInclude(es => es.Semester)
+                .AsSplitQuery()
+                .FirstOrDefaultAsync(u => u.Id == id);
+        }
+
+
+        public async Task<User?> GetOnlyUserByIdAsync(int id)
+        {
+            return await _context.User.FirstOrDefaultAsync(u => u.Id == id);
+        }
+        public async Task AddUserAsync(User user)
+        {
+            _context.User.Add(user);
+            await _context.SaveChangesAsync();
+        }
+        public async Task AddContactAsync(ContactInfo contactInfo)
+        {
+            _context.ContactInfo.Add(contactInfo);
+            await _context.SaveChangesAsync();
+        }
+        public async Task AddHighSchoolAsync(HighSchool highSchool)
+        {
+            _context.HighSchool.Add(highSchool);
+            await _context.SaveChangesAsync();
+        }       
+
+        public async Task<int> GetUsersCountAsync()
+        {
+            return await _context.User.CountAsync();
+        }
+        public async Task<List<EnrolledSemesters>> GetUserSemestersAsync(int id)
+        {
+            return await _context.EnrolledSemesters
+                .AsNoTracking()
+                .Include(es => es.Major)
+                .Include(es => es.Semester)
+                .Include(es => es.SemesterSubjects)
+                    .ThenInclude(ss => ss.Subject)
+                .Include(es => es.SemesterSubjects)
+                    .ThenInclude(ss => ss.Professor)
+                .Where(es => es.UserId == id)
+                .AsSplitQuery() // This helps avoid cartesian explosion
+                .ToListAsync();
+        }
+
+        public async Task<List<PassedSubject>> GetUserPassedSubjectsAsync(int id)
+        {
+            return await _context.PassedSubjects
+                .AsNoTracking()
+                .Include(ps => ps.SemesterSubject)
+                    .ThenInclude(ss => ss.Subject)
+                .Include(ps => ps.SemesterSubject)
+                    .ThenInclude(ss => ss.EnrolledSemester)
+                        .ThenInclude(es => es.Semester)
+                .Include(ps => ps.SemesterSubject)
+                    .ThenInclude(ss => ss.Professor)
+                // The ER model reaches the student through the enrolment,
+                // not through a user_id on semesters_subjects.
+                .Where(ps => ps.SemesterSubject.EnrolledSemester.UserId == id)
+                .ToListAsync();
+        }
+
+    }
+}
Index: iknow-api/Repository/Interface/IProfRepository.cs
===================================================================
--- iknow-api/Repository/Interface/IProfRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Repository/Interface/IProfRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,26 @@
+using iknow_api.Models;
+
+namespace iknow_api.Repositories
+{
+    public interface IProfRepository
+    {
+        /// <summary>
+        /// Every semester-subject row taught by this professor, with the
+        /// enrolment, student, subject, semester and grade loaded.
+        /// </summary>
+        Task<List<SemesterSubject>> GetTaughtSemesterSubjectsAsync(int professorId);
+
+        /// <summary>
+        /// The semester-subject row this professor teaches for one student and
+        /// subject. When a student has taken the subject more than once, the
+        /// most recent enrolment wins. Null when the professor does not teach
+        /// that student in that subject.
+        /// </summary>
+        Task<SemesterSubject?> FindTaughtSemesterSubjectAsync(int professorId, int studentId, int subjectId);
+
+        Task<PassedSubject?> GetPassedSubjectAsync(int semesterSubjectId);
+        Task AddPassedSubjectAsync(PassedSubject passed);
+        Task UpdatePassedSubjectAsync(PassedSubject passed);
+        Task RemovePassedSubjectAsync(PassedSubject passed);
+    }
+}
Index: iknow-api/Repository/Interface/IRefreshTokenRepository.cs
===================================================================
--- iknow-api/Repository/Interface/IRefreshTokenRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Repository/Interface/IRefreshTokenRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,12 @@
+using iknow_api.DTOs;
+using iknow_api.Models;
+namespace iknow_api.Repositories{
+    public interface IRefreshTokenRepository
+    {
+        Task AddTokenAsync(RefreshToken refreshToken);
+        Task<bool> VerifyTokenAsync(VerifyRefreshTokenDto refreshTokenDto);
+        Task<bool> DeleteTokenAsync(string refreshTokenDto);
+        Task<int?> GetUserId(string refreshTokenDto);
+        
+    }
+}
Index: iknow-api/Repository/Interface/IUserRepository.cs
===================================================================
--- iknow-api/Repository/Interface/IUserRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Repository/Interface/IUserRepository.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,17 @@
+using iknow_api.Models;
+namespace iknow_api.Repositories
+{
+    public interface IUserRepository
+    {
+        Task<bool> UserExistsAsync(string username);
+        Task<User?> GetUserByUsernameAsync(string username);
+        Task AddUserAsync(User user);
+        Task AddContactAsync(ContactInfo contactInfo);
+        Task AddHighSchoolAsync(HighSchool highSchool);
+        Task<int> GetUsersCountAsync();
+        Task<User?> GetUserByIdAsync(int id);
+        Task<List<EnrolledSemesters>?> GetUserSemestersAsync(int id);
+        Task<User?> GetOnlyUserByIdAsync(int id);
+        Task<List<PassedSubject>> GetUserPassedSubjectsAsync(int id);
+    }
+}
Index: iknow-api/Services/Implementations/AdminService.cs
===================================================================
--- iknow-api/Services/Implementations/AdminService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Implementations/AdminService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,445 @@
+using iknow_api.Data;
+using iknow_api.DTOs;
+using iknow_api.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace iknow_api.Services
+{
+    /// <summary>
+    /// Backs UC012 (subjects), UC013 (active semesters) and UC014 (professor
+    /// assignments). Every method reports constraint problems as a sentence
+    /// rather than letting a database exception reach the controller.
+    /// </summary>
+    public class AdminService : IAdminService
+    {
+        private readonly AppDbContext _context;
+
+        public AdminService(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        private static string SemesterName(ActiveSemesters s) =>
+            $"{(s.Type == sType.winter ? "Зимски" : "Летен")}({s.Year}/{s.Year + 1})";
+
+        // ============================================================
+        //  UC012 - subjects
+        // ============================================================
+
+        public async Task<List<AdminSubjectDto>> GetSubjectsAsync()
+        {
+            var subjects = await _context.Subjects.AsNoTracking().ToListAsync();
+
+            var majorLinks = await _context.MajorSubjects.AsNoTracking()
+                .Include(ms => ms.Majors).ToListAsync();
+
+            var prerequisites = await _context.DependencySubjects.AsNoTracking().ToListAsync();
+
+            // A subject that students already took cannot be deleted.
+            var enrolledCounts = await _context.SemesterSubjects.AsNoTracking()
+                .GroupBy(ss => ss.SubjectId)
+                .Select(g => new { SubjectId = g.Key, Count = g.Count() })
+                .ToDictionaryAsync(x => x.SubjectId, x => x.Count);
+
+            var byId = subjects.ToDictionary(s => s.Id);
+
+            return subjects
+                .OrderBy(s => s.Code)
+                .Select(s => new AdminSubjectDto
+                {
+                    Id = s.Id,
+                    Name = s.Name,
+                    Code = s.Code,
+                    AwardedCredits = s.AwardedCredits ?? 0,
+                    DependencyCredit = s.DependencyCredit,
+                    EnrolledCount = enrolledCounts.TryGetValue(s.Id, out var c) ? c : 0,
+                    Majors = majorLinks
+                        .Where(ms => ms.SubjectId == s.Id)
+                        .Select(ms => new SubjectMajorDto
+                        {
+                            MajorId = ms.MajorId,
+                            MajorName = ms.Majors?.Name,
+                            MandatorySemester = ms.MandatorySemester
+                        })
+                        .OrderBy(m => m.MajorName)
+                        .ToList(),
+                    Prerequisites = prerequisites
+                        .Where(d => d.SubjectId == s.Id && byId.ContainsKey(d.DependencyId))
+                        .Select(d => new SubjectRefDto
+                        {
+                            Id = d.DependencyId,
+                            Name = byId[d.DependencyId].Name,
+                            Code = byId[d.DependencyId].Code
+                        })
+                        .OrderBy(p => p.Code)
+                        .ToList()
+                })
+                .ToList();
+        }
+
+        public async Task<AdminResultDto> CreateSubjectAsync(SubjectWriteDto request)
+        {
+            if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Code))
+            {
+                return Fail("Name and code are required.");
+            }
+            if (request.AwardedCredits <= 0)
+            {
+                return Fail("Awarded credits must be greater than zero.");
+            }
+            // subjects.name and subjects.code are both UNIQUE.
+            if (await _context.Subjects.AnyAsync(s => s.Name == request.Name))
+            {
+                return Fail($"A subject named '{request.Name}' already exists.");
+            }
+            if (await _context.Subjects.AnyAsync(s => s.Code == request.Code))
+            {
+                return Fail($"Subject code '{request.Code}' is already taken.");
+            }
+
+            var subject = new Subject
+            {
+                Name = request.Name,
+                Code = request.Code,
+                AwardedCredits = request.AwardedCredits,
+                DependencyCredit = request.DependencyCredit
+            };
+            _context.Subjects.Add(subject);
+            await _context.SaveChangesAsync();
+
+            return Ok($"Subject '{subject.Name}' created.", subject.Id);
+        }
+
+        public async Task<AdminResultDto> UpdateSubjectAsync(int subjectId, SubjectWriteDto request)
+        {
+            var subject = await _context.Subjects.FirstOrDefaultAsync(s => s.Id == subjectId);
+            if (subject is null) return Fail("Subject not found.");
+
+            if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Code))
+            {
+                return Fail("Name and code are required.");
+            }
+            if (request.AwardedCredits <= 0)
+            {
+                return Fail("Awarded credits must be greater than zero.");
+            }
+            if (await _context.Subjects.AnyAsync(s => s.Name == request.Name && s.Id != subjectId))
+            {
+                return Fail($"Another subject is already named '{request.Name}'.");
+            }
+            if (await _context.Subjects.AnyAsync(s => s.Code == request.Code && s.Id != subjectId))
+            {
+                return Fail($"Subject code '{request.Code}' is already taken.");
+            }
+
+            subject.Name = request.Name;
+            subject.Code = request.Code;
+            subject.AwardedCredits = request.AwardedCredits;
+            subject.DependencyCredit = request.DependencyCredit;
+            await _context.SaveChangesAsync();
+
+            return Ok($"Subject '{subject.Name}' updated.", subject.Id);
+        }
+
+        public async Task<AdminResultDto> DeleteSubjectAsync(int subjectId)
+        {
+            var subject = await _context.Subjects.FirstOrDefaultAsync(s => s.Id == subjectId);
+            if (subject is null) return Fail("Subject not found.");
+
+            // semesters_subjects references subjects, so a taken subject cannot go.
+            var taken = await _context.SemesterSubjects.CountAsync(ss => ss.SubjectId == subjectId);
+            if (taken > 0)
+            {
+                return Fail($"Cannot delete: {taken} enrolment(s) already contain this subject.");
+            }
+
+            await using var transaction = await _context.Database.BeginTransactionAsync();
+            try
+            {
+                // The mapping rows must go first; their foreign keys would block the delete.
+                var prereqs = await _context.DependencySubjects
+                    .Where(d => d.SubjectId == subjectId || d.DependencyId == subjectId)
+                    .ToListAsync();
+                _context.DependencySubjects.RemoveRange(prereqs);
+
+                var majors = await _context.MajorSubjects
+                    .Where(ms => ms.SubjectId == subjectId).ToListAsync();
+                _context.MajorSubjects.RemoveRange(majors);
+
+                var teaching = await _context.ProfessorSubjects
+                    .Where(ps => ps.SubjectId == subjectId).ToListAsync();
+                _context.ProfessorSubjects.RemoveRange(teaching);
+
+                _context.Subjects.Remove(subject);
+                await _context.SaveChangesAsync();
+                await transaction.CommitAsync();
+
+                return Ok($"Subject '{subject.Name}' deleted.");
+            }
+            catch
+            {
+                await transaction.RollbackAsync();
+                throw;
+            }
+        }
+
+        public async Task<AdminResultDto> LinkMajorAsync(int subjectId, MajorLinkDto request)
+        {
+            if (!await _context.Subjects.AnyAsync(s => s.Id == subjectId))
+                return Fail("Subject not found.");
+            if (!await _context.Majors.AnyAsync(m => m.Id == request.MajorId))
+                return Fail("Study programme not found.");
+            if (request.MandatorySemester < 1)
+                return Fail("Semester must be 1 or greater.");
+
+            var existing = await _context.MajorSubjects
+                .FirstOrDefaultAsync(ms => ms.SubjectId == subjectId && ms.MajorId == request.MajorId);
+
+            if (existing is not null)
+            {
+                existing.MandatorySemester = request.MandatorySemester;
+                await _context.SaveChangesAsync();
+                return Ok("Study programme mapping updated.");
+            }
+
+            _context.MajorSubjects.Add(new MajorSubjects
+            {
+                SubjectId = subjectId,
+                MajorId = request.MajorId,
+                MandatorySemester = request.MandatorySemester
+            });
+            await _context.SaveChangesAsync();
+            return Ok("Subject added to the study programme.");
+        }
+
+        public async Task<AdminResultDto> UnlinkMajorAsync(int subjectId, int majorId)
+        {
+            var row = await _context.MajorSubjects
+                .FirstOrDefaultAsync(ms => ms.SubjectId == subjectId && ms.MajorId == majorId);
+            if (row is null) return Fail("That subject is not in that study programme.");
+
+            _context.MajorSubjects.Remove(row);
+            await _context.SaveChangesAsync();
+            return Ok("Subject removed from the study programme.");
+        }
+
+        public async Task<AdminResultDto> AddPrerequisiteAsync(int subjectId, PrerequisiteDto request)
+        {
+            if (subjectId == request.DependencyId)
+            {
+                // Mirrors CHECK (subject_id <> dependency_id).
+                return Fail("A subject cannot be its own prerequisite.");
+            }
+            if (!await _context.Subjects.AnyAsync(s => s.Id == subjectId))
+                return Fail("Subject not found.");
+            if (!await _context.Subjects.AnyAsync(s => s.Id == request.DependencyId))
+                return Fail("Prerequisite subject not found.");
+            if (await _context.DependencySubjects.AnyAsync(
+                    d => d.SubjectId == subjectId && d.DependencyId == request.DependencyId))
+                return Fail("That prerequisite is already set.");
+
+            // Refuse a direct cycle: A requires B while B already requires A.
+            if (await _context.DependencySubjects.AnyAsync(
+                    d => d.SubjectId == request.DependencyId && d.DependencyId == subjectId))
+                return Fail("That would create a circular prerequisite.");
+
+            _context.DependencySubjects.Add(new DependencySubject
+            {
+                SubjectId = subjectId,
+                DependencyId = request.DependencyId
+            });
+            await _context.SaveChangesAsync();
+            return Ok("Prerequisite added.");
+        }
+
+        public async Task<AdminResultDto> RemovePrerequisiteAsync(int subjectId, int dependencyId)
+        {
+            var row = await _context.DependencySubjects
+                .FirstOrDefaultAsync(d => d.SubjectId == subjectId && d.DependencyId == dependencyId);
+            if (row is null) return Fail("That prerequisite is not set.");
+
+            _context.DependencySubjects.Remove(row);
+            await _context.SaveChangesAsync();
+            return Ok("Prerequisite removed.");
+        }
+
+        // ============================================================
+        //  UC013 - active semesters
+        // ============================================================
+
+        public async Task<List<AdminSemesterDto>> GetSemestersAsync()
+        {
+            var semesters = await _context.ActiveSemesters.AsNoTracking().ToListAsync();
+            var subjects = await _context.Subjects.AsNoTracking().ToListAsync();
+            var teaching = await _context.ProfessorSubjects.AsNoTracking().ToListAsync();
+
+            var enrolments = await _context.EnrolledSemesters.AsNoTracking()
+                .GroupBy(es => es.SemesterId)
+                .Select(g => new { SemesterId = g.Key, Count = g.Count() })
+                .ToDictionaryAsync(x => x.SemesterId, x => x.Count);
+
+            return semesters
+                .OrderByDescending(s => s.Year)
+                .ThenByDescending(s => s.Type == sType.summer)
+                .Select(s =>
+                {
+                    var covered = teaching
+                        .Where(t => t.SemesterId == s.Id)
+                        .Select(t => t.SubjectId)
+                        .ToHashSet();
+
+                    return new AdminSemesterDto
+                    {
+                        Id = s.Id,
+                        Year = s.Year,
+                        Type = s.Type.ToString(),
+                        Name = SemesterName(s),
+                        EnrolmentCount = enrolments.TryGetValue(s.Id, out var c) ? c : 0,
+                        UncoveredSubjects = subjects
+                            .Where(sub => !covered.Contains(sub.Id))
+                            .OrderBy(sub => sub.Code)
+                            .Select(sub => new SubjectRefDto { Id = sub.Id, Name = sub.Name, Code = sub.Code })
+                            .ToList()
+                    };
+                })
+                .ToList();
+        }
+
+        public async Task<AdminResultDto> CreateSemesterAsync(SemesterWriteDto request)
+        {
+            if (!Enum.TryParse<sType>(request.Type, ignoreCase: true, out var type))
+            {
+                return Fail("Semester type must be 'winter' or 'summer'.");
+            }
+            if (request.Year < 2000 || request.Year > 2100)
+            {
+                return Fail("Year looks wrong; expected something between 2000 and 2100.");
+            }
+            // active_semesters has UNIQUE (year, type).
+            if (await _context.ActiveSemesters.AnyAsync(a => a.Year == request.Year && a.Type == type))
+            {
+                return Fail("That semester is already open.");
+            }
+
+            var semester = new ActiveSemesters { Year = request.Year, Type = type };
+            _context.ActiveSemesters.Add(semester);
+            await _context.SaveChangesAsync();
+
+            return Ok($"Semester {SemesterName(semester)} opened.", semester.Id);
+        }
+
+        // ============================================================
+        //  UC014 - professor assignments
+        // ============================================================
+
+        public async Task<ScheduleDto?> GetScheduleAsync(int semesterId)
+        {
+            var semester = await _context.ActiveSemesters.AsNoTracking()
+                .FirstOrDefaultAsync(a => a.Id == semesterId);
+            if (semester is null) return null;
+
+            var subjects = await _context.Subjects.AsNoTracking().ToListAsync();
+            var professors = await _context.User.AsNoTracking()
+                .Where(u => u.Role == Models.UserRole.Professor).ToListAsync();
+            var assignments = await _context.ProfessorSubjects.AsNoTracking()
+                .Where(ps => ps.SemesterId == semesterId).ToListAsync();
+
+            var subjectById = subjects.ToDictionary(s => s.Id);
+            var profById = professors.ToDictionary(p => p.Id);
+            var covered = assignments.Select(a => a.SubjectId).ToHashSet();
+
+            return new ScheduleDto
+            {
+                SemesterId = semester.Id,
+                SemesterName = SemesterName(semester),
+                Assignments = assignments
+                    .Where(a => subjectById.ContainsKey(a.SubjectId) && profById.ContainsKey(a.ProfessorId))
+                    .Select(a => new ScheduleRowDto
+                    {
+                        SubjectId = a.SubjectId,
+                        SubjectName = subjectById[a.SubjectId].Name,
+                        SubjectCode = subjectById[a.SubjectId].Code,
+                        ProfessorId = a.ProfessorId,
+                        ProfessorName = $"{profById[a.ProfessorId].Name} {profById[a.ProfessorId].Surname}".Trim()
+                    })
+                    .OrderBy(r => r.SubjectCode)
+                    .ToList(),
+                Load = professors
+                    .Select(p => new ProfessorLoadDto
+                    {
+                        ProfessorId = p.Id,
+                        ProfessorName = $"{p.Name} {p.Surname}".Trim(),
+                        Subjects = assignments.Count(a => a.ProfessorId == p.Id)
+                    })
+                    .OrderByDescending(l => l.Subjects).ThenBy(l => l.ProfessorName)
+                    .ToList(),
+                UncoveredSubjects = subjects
+                    .Where(s => !covered.Contains(s.Id))
+                    .OrderBy(s => s.Code)
+                    .Select(s => new SubjectRefDto { Id = s.Id, Name = s.Name, Code = s.Code })
+                    .ToList(),
+                AllSubjects = subjects
+                    .OrderBy(s => s.Code)
+                    .Select(s => new SubjectRefDto { Id = s.Id, Name = s.Name, Code = s.Code })
+                    .ToList(),
+                Professors = professors
+                    .OrderBy(p => p.Surname)
+                    .Select(p => new ProfessorRefDto { Id = p.Id, Name = $"{p.Name} {p.Surname}".Trim() })
+                    .ToList()
+            };
+        }
+
+        public async Task<AdminResultDto> AssignAsync(ScheduleWriteDto request)
+        {
+            var professor = await _context.User
+                .FirstOrDefaultAsync(u => u.Id == request.ProfessorId);
+            if (professor is null) return Fail("Professor not found.");
+            if (professor.Role != Models.UserRole.Professor)
+                return Fail("That user is not a professor.");
+            if (!await _context.ActiveSemesters.AnyAsync(a => a.Id == request.SemesterId))
+                return Fail("Semester not found.");
+            if (!await _context.Subjects.AnyAsync(s => s.Id == request.SubjectId))
+                return Fail("Subject not found.");
+
+            var exists = await _context.ProfessorSubjects.AnyAsync(
+                ps => ps.ProfessorId == request.ProfessorId
+                   && ps.SemesterId == request.SemesterId
+                   && ps.SubjectId == request.SubjectId);
+            if (exists) return Ok("That assignment already exists.");
+
+            _context.ProfessorSubjects.Add(new ProfessorSubjects
+            {
+                ProfessorId = request.ProfessorId,
+                SemesterId = request.SemesterId,
+                SubjectId = request.SubjectId
+            });
+            await _context.SaveChangesAsync();
+            return Ok("Professor assigned to the subject.");
+        }
+
+        public async Task<AdminResultDto> UnassignAsync(ScheduleWriteDto request)
+        {
+            var row = await _context.ProfessorSubjects.FirstOrDefaultAsync(
+                ps => ps.ProfessorId == request.ProfessorId
+                   && ps.SemesterId == request.SemesterId
+                   && ps.SubjectId == request.SubjectId);
+            if (row is null) return Fail("That assignment does not exist.");
+
+            _context.ProfessorSubjects.Remove(row);
+            await _context.SaveChangesAsync();
+            return Ok("Assignment removed.");
+        }
+
+        public async Task<List<SubjectRefDto>> GetMajorsAsync() =>
+            await _context.Majors.AsNoTracking()
+                .OrderBy(m => m.Name)
+                .Select(m => new SubjectRefDto { Id = m.Id, Name = m.Name, Code = null })
+                .ToListAsync();
+
+        private static AdminResultDto Ok(string message, int? id = null) =>
+            new() { Ok = true, Message = message, Id = id };
+
+        private static AdminResultDto Fail(string message) =>
+            new() { Ok = false, Message = message };
+    }
+}
Index: iknow-api/Services/Implementations/AuthService.cs
===================================================================
--- iknow-api/Services/Implementations/AuthService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Implementations/AuthService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,175 @@
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+using BCrypt.Net;
+using iknow_api.Models;
+using iknow_api.DTOs;
+using iknow_api.Repositories;
+using Microsoft.IdentityModel.Tokens;
+using iknow_api.Data;
+
+namespace iknow_api.Services
+{
+    public class AuthService : IAuthService
+    {
+        private readonly IUserRepository _userRepository;
+        private readonly IRefreshTokenRepository _refreshTokenRepository;
+        private readonly IRefreshTokenService _refreshTokenService;
+        private readonly IConfiguration _configuration;
+        private readonly AppDbContext _context;
+
+        public AuthService(IUserRepository userRepository, IConfiguration configuration,
+                            IRefreshTokenService refreshTokenService, IRefreshTokenRepository refreshTokenRepository,
+                            AppDbContext context)
+        {
+            _userRepository = userRepository;
+            _configuration = configuration;
+            _refreshTokenService = refreshTokenService;
+            _refreshTokenRepository = refreshTokenRepository;
+            _context = context;
+        }
+
+        public async Task<bool> RegisterAsync(RegisterDto registerDto)
+        {
+            // Debug: Log all incoming DTO values
+            Console.WriteLine("=== RegisterDto Debug Info ===");
+            Console.WriteLine($"Name: {registerDto.Name}");
+            Console.WriteLine($"Email: {registerDto.Email}");
+            Console.WriteLine($"majorType: {registerDto.majorType}");
+            Console.WriteLine($"enrollmentYear: {registerDto.enrollmentYear}");
+            Console.WriteLine($"quotaType: {registerDto.quotaType}");
+            Console.WriteLine($"Role: {registerDto.Role}");
+            Console.WriteLine($"tip: {registerDto.tip}");
+            Console.WriteLine("==============================");
+
+            // Check if user already exists
+            if (await _userRepository.UserExistsAsync(registerDto.Email))
+                throw new InvalidOperationException("User with this email already exists");
+
+            // Use a transaction to ensure all entities are saved together
+            using var transaction = await _context.Database.BeginTransactionAsync();
+            try
+            {
+                // quota and enrollment_year are attributes of Users in the ER
+                // model, so they are set here rather than on a separate entity.
+                var user = new User
+                {
+                    Name = registerDto.Name,
+                    Surname = registerDto.Surname,
+                    Index = registerDto.Index,
+                    Email = registerDto.Email,
+                    PasswordHash = BCrypt.Net.BCrypt.HashPassword(registerDto.Password),
+                    Bday = DateTime.SpecifyKind(registerDto.Bday, DateTimeKind.Unspecified),
+                    CreatedAt = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified),
+                    Role = (Models.UserRole)registerDto.Role,
+                    EMBG = registerDto.EMBG,
+                    Quota = (Models.Quota)registerDto.quotaType,
+                    EnrollmentYear = registerDto.enrollmentYear
+                };
+
+                _context.User.Add(user);
+                await _context.SaveChangesAsync();
+                
+                int userId = user.Id;
+                
+                var contactInfo = new ContactInfo
+                {
+                    UserId = userId,
+                    City = registerDto.city,
+                    Address = registerDto.address,
+                    Municipality = registerDto.municipality,
+                    PhoneNumber = registerDto.phoneNumber,
+                    MicrosoftEmail = registerDto.microsoftEmail
+                };
+                
+                var highSchool = new HighSchool
+                {
+                    UserId = userId,
+                    GPA = registerDto.gpa,
+                    HighSchoolType = (Models.HighSchoolType)registerDto.tip
+                };
+
+                _context.ContactInfo.Add(contactInfo);
+                _context.HighSchool.Add(highSchool);
+                
+                // Save all related entities in a single transaction
+                await _context.SaveChangesAsync();
+                await transaction.CommitAsync();
+                
+                return true;
+            }
+            catch
+            {
+                await transaction.RollbackAsync();
+                throw;
+            }
+        }
+
+        public async Task<AuthResultDto?> LoginAsync(LoginDto loginDto)
+        {
+            var user = await _userRepository.GetUserByUsernameAsync(loginDto.Email);
+            if (user == null || !BCrypt.Net.BCrypt.Verify(loginDto.Password, user.PasswordHash))
+                return null;
+
+            var result = new AuthResultDto
+            {
+                AccessToken = CreateToken(user),
+                Role = user.Role.ToString()
+            };
+
+            if (loginDto.GenerateRefreshToken)
+            {
+                result.RefreshToken = await _refreshTokenService.GenerateRefreshToken(user.Id);
+            }
+
+            return result;
+        }
+
+        public async Task<int> GetUsersCountAsync()
+        {
+            return await _userRepository.GetUsersCountAsync();
+        }
+
+        public async Task<AuthResultDto> GenerateNewJWT(VerifyRefreshTokenDto token)
+        {
+            int userid = await _refreshTokenRepository.GetUserId(token.token) ?? 0;
+            User? user = await _userRepository.GetOnlyUserByIdAsync(userid);
+
+            if (user == null)
+                throw new InvalidOperationException("User not found for provided refresh token.");
+
+            return new AuthResultDto
+            {
+                AccessToken = CreateToken(user),
+                Role = user.Role.ToString()
+            };
+        }
+
+        private string CreateToken(User user)
+        {
+            var claims = new[]
+            {
+                new Claim("id", user.Id.ToString()),
+                new Claim("email", user.Email ?? string.Empty),
+                new Claim("role", user.Role.ToString())
+            };
+
+            var keyString = _configuration["Jwt:Key"];
+            if (string.IsNullOrEmpty(keyString))
+                throw new Exception("JWT Key is missing in configuration!");
+
+            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keyString));
+            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
+
+            var jwt = new JwtSecurityToken(
+                issuer: "iknow-api",
+                audience: "iknow-api",
+                claims: claims,
+                expires: DateTime.UtcNow.AddHours(1),
+                signingCredentials: creds
+            );
+
+            return new JwtSecurityTokenHandler().WriteToken(jwt);
+        }
+    }
+}
Index: iknow-api/Services/Implementations/EnrollmentService.cs
===================================================================
--- iknow-api/Services/Implementations/EnrollmentService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Implementations/EnrollmentService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,232 @@
+using iknow_api.Data;
+using iknow_api.DTOs;
+using iknow_api.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace iknow_api.Services
+{
+    public class EnrollmentService : IEnrollmentService
+    {
+        /// <summary>An enrolment is exactly this many subjects.</summary>
+        public const int RequiredSubjects = 5;
+
+        private readonly AppDbContext _context;
+
+        public EnrollmentService(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        public async Task<EnrollmentOptionsDto> GetOptionsAsync(int studentId)
+        {
+            var enrolments = await _context.EnrolledSemesters
+                .AsNoTracking()
+                .Include(es => es.Semester)
+                .Where(es => es.UserId == studentId)
+                .ToListAsync();
+
+            var takenSemesterIds = enrolments.Select(es => es.SemesterId).ToHashSet();
+
+            var available = await _context.ActiveSemesters
+                .AsNoTracking()
+                .Where(a => !takenSemesterIds.Contains(a.Id))
+                .ToListAsync();
+
+            // Semesters are labelled Year/Year+1, so within a year winter comes first.
+            var semesters = available
+                .OrderBy(a => a.Year)
+                .ThenBy(a => a.Type == sType.summer)
+                .Select(a => new SemesterOptionDto
+                {
+                    Id = a.Id,
+                    Year = a.Year,
+                    Type = a.Type.ToString(),
+                    Name = $"{(a.Type == sType.winter ? "Зимски" : "Летен")}({a.Year}/{a.Year + 1})"
+                })
+                .ToList();
+
+            var passedSubjectIds = await _context.PassedSubjects
+                .AsNoTracking()
+                .Where(ps => ps.SemesterSubject!.EnrolledSemester!.UserId == studentId)
+                .Select(ps => ps.SemesterSubject!.SubjectId)
+                .ToListAsync();
+            var passed = passedSubjectIds.ToHashSet();
+
+            var majorRows = await _context.MajorSubjects
+                .AsNoTracking()
+                .Include(ms => ms.Majors)
+                .Include(ms => ms.Subjects)
+                .ToListAsync();
+
+            var majors = majorRows
+                .Where(ms => ms.Majors != null && ms.Subjects != null)
+                .GroupBy(ms => ms.Majors!.Id)
+                .Select(g => new MajorOptionDto
+                {
+                    Id = g.Key,
+                    Name = g.First().Majors!.Name,
+                    Subjects = g
+                        .Select(ms => new SubjectOptionDto
+                        {
+                            Id = ms.Subjects!.Id,
+                            Name = ms.Subjects.Name,
+                            Code = ms.Subjects.Code,
+                            Credits = ms.Subjects.AwardedCredits ?? 0,
+                            MandatorySemester = ms.MandatorySemester,
+                            AlreadyPassed = passed.Contains(ms.Subjects.Id)
+                        })
+                        .OrderBy(x => x.MandatorySemester)
+                        .ThenBy(x => x.Name)
+                        .ToList()
+                })
+                .OrderBy(m => m.Name)
+                .ToList();
+
+            var latest = enrolments
+                .Where(es => es.Semester != null)
+                .OrderByDescending(es => es.Semester!.Year)
+                .ThenByDescending(es => es.Semester!.Type == sType.summer)
+                .FirstOrDefault();
+
+            return new EnrollmentOptionsDto
+            {
+                RequiredSubjects = RequiredSubjects,
+                Semesters = semesters,
+                Majors = majors,
+                DefaultMajorId = latest?.MajorId
+            };
+        }
+
+        public async Task<EnrollSemesterResultDto> EnrollAsync(
+            int studentId, EnrollSemesterRequestDto request)
+        {
+            var subjectIds = request.SubjectIds?.Distinct().ToList() ?? new List<int>();
+
+            if (subjectIds.Count != RequiredSubjects)
+            {
+                return Fail($"Pick exactly {RequiredSubjects} different subjects; got {subjectIds.Count}.");
+            }
+
+            if (!await _context.ActiveSemesters.AnyAsync(a => a.Id == request.SemesterId))
+            {
+                return Fail("That semester does not exist.");
+            }
+
+            // enrolled_semesters has UNIQUE (user_id, semester_id); check first so
+            // the student gets a sentence rather than a constraint violation.
+            if (await _context.EnrolledSemesters.AnyAsync(
+                    es => es.UserId == studentId && es.SemesterId == request.SemesterId))
+            {
+                return Fail("You are already enrolled in that semester.");
+            }
+
+            if (!await _context.Majors.AnyAsync(m => m.Id == request.MajorId))
+            {
+                return Fail("That study programme does not exist.");
+            }
+
+            var offered = await _context.MajorSubjects
+                .Where(ms => ms.MajorId == request.MajorId)
+                .Select(ms => ms.SubjectId)
+                .ToListAsync();
+
+            var notOffered = subjectIds.Except(offered).ToList();
+            if (notOffered.Count > 0)
+            {
+                return Fail($"Subject(s) {string.Join(", ", notOffered)} are not offered by that study programme.");
+            }
+
+            // semesters_subjects.professor_id is NOT NULL, so every chosen subject
+            // needs somebody teaching it that semester.
+            var teachers = await _context.ProfessorSubjects
+                .Where(ps => ps.SemesterId == request.SemesterId && subjectIds.Contains(ps.SubjectId))
+                .ToListAsync();
+
+            // A subject can be taught by more than one professor in the same
+            // semester. Spread students over them instead of always taking the
+            // lowest id, which would leave the other professor with nobody.
+            var currentLoad = await _context.SemesterSubjects
+                .Where(ss => subjectIds.Contains(ss.SubjectId)
+                          && ss.EnrolledSemester!.SemesterId == request.SemesterId)
+                .GroupBy(ss => new { ss.SubjectId, ss.ProfessorId })
+                .Select(g => new { g.Key.SubjectId, g.Key.ProfessorId, Count = g.Count() })
+                .ToListAsync();
+
+            var loadLookup = currentLoad.ToDictionary(
+                x => (x.SubjectId, x.ProfessorId), x => x.Count);
+
+            var professorBySubject = teachers
+                .GroupBy(ps => ps.SubjectId)
+                .ToDictionary(
+                    g => g.Key,
+                    // Fewest students first; professor id only breaks ties, so
+                    // the choice stays deterministic and testable.
+                    g => g.OrderBy(ps => loadLookup.TryGetValue((ps.SubjectId, ps.ProfessorId), out var n) ? n : 0)
+                          .ThenBy(ps => ps.ProfessorId)
+                          .First().ProfessorId);
+
+            var untaught = subjectIds.Where(id => !professorBySubject.ContainsKey(id)).ToList();
+            if (untaught.Count > 0)
+            {
+                return Fail($"Subject(s) {string.Join(", ", untaught)} are not taught in that semester.");
+            }
+
+            var student = await _context.User.FirstOrDefaultAsync(u => u.Id == studentId);
+            if (student is null)
+            {
+                return Fail("Student not found.");
+            }
+
+            var now = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
+
+            await using var transaction = await _context.Database.BeginTransactionAsync();
+            try
+            {
+                var enrolment = new EnrolledSemesters
+                {
+                    UserId = studentId,
+                    SemesterId = request.SemesterId,
+                    MajorId = request.MajorId,
+                    // enrolled_semesters.quota is NOT NULL; fall back to the
+                    // state quota when the student record has none.
+                    QuotaType = student.Quota ?? Models.Quota.drzavna,
+                    CratedAt = now,
+                    LastChange = now,
+                    Verified = null
+                };
+
+                _context.EnrolledSemesters.Add(enrolment);
+                await _context.SaveChangesAsync();
+
+                foreach (var subjectId in subjectIds)
+                {
+                    _context.SemesterSubjects.Add(new SemesterSubject
+                    {
+                        EnrolledSemesterId = enrolment.Id,
+                        SubjectId = subjectId,
+                        ProfessorId = professorBySubject[subjectId],
+                        Signature = false
+                    });
+                }
+
+                await _context.SaveChangesAsync();
+                await transaction.CommitAsync();
+
+                return new EnrollSemesterResultDto
+                {
+                    Ok = true,
+                    Message = $"Enrolled with {subjectIds.Count} subjects.",
+                    EnrolledSemesterId = enrolment.Id
+                };
+            }
+            catch
+            {
+                await transaction.RollbackAsync();
+                throw;
+            }
+        }
+
+        private static EnrollSemesterResultDto Fail(string message) =>
+            new() { Ok = false, Message = message };
+    }
+}
Index: iknow-api/Services/Implementations/ProfService.cs
===================================================================
--- iknow-api/Services/Implementations/ProfService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Implementations/ProfService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,122 @@
+using iknow_api.DTOs;
+using iknow_api.Models;
+using iknow_api.Repositories;
+
+namespace iknow_api.Services
+{
+    public class ProfService : IProfService
+    {
+        private readonly IProfRepository _profRepository;
+
+        public ProfService(IProfRepository profRepository)
+        {
+            _profRepository = profRepository;
+        }
+
+        public async Task<List<SubjectStudentsDto>> GetStudentsBySubjectAsync(int professorId)
+        {
+            var taught = await _profRepository.GetTaughtSemesterSubjectsAsync(professorId);
+
+            return taught
+                .Where(ss => ss.Subject != null && ss.EnrolledSemester?.User != null)
+                .GroupBy(ss => ss.Subject!.Id)
+                .Select(group =>
+                {
+                    var subject = group.First().Subject!;
+                    return new SubjectStudentsDto
+                    {
+                        Id = subject.Id,
+                        Name = subject.Name,
+                        Code = subject.Code,
+                        Users = group
+                            .Select(ss =>
+                            {
+                                var student = ss.EnrolledSemester!.User!;
+                                var semester = ss.EnrolledSemester.Semester;
+                                return new EnrolledStudentDto
+                                {
+                                    Id = student.Id,
+                                    Name = $"{student.Name} {student.Surname}".Trim(),
+                                    Index = student.Index,
+                                    // 0 means "not graded yet"; the enum starts at 6.
+                                    Grade = ss.PassedSubject is null ? 0 : (int)ss.PassedSubject.Grade,
+                                    Semester = semester is null
+                                        ? null
+                                        : $"{(semester.Type == sType.winter ? "Зимски" : "Летен")}({semester.Year}/{semester.Year + 1})"
+                                };
+                            })
+                            .OrderBy(u => u.Name)
+                            .ToList()
+                    };
+                })
+                .OrderBy(s => s.Name)
+                .ToList();
+        }
+
+        public async Task<GradeResultDto> SetGradeAsync(
+            int professorId, GradeRequestDto request, GradeAction action)
+        {
+            // grade_type only declares 6..10, so anything else cannot be stored.
+            if (action != GradeAction.Remove && !Enum.IsDefined(typeof(Grade), request.Grade))
+            {
+                return Fail($"Grade must be between 6 and 10; got {request.Grade}.");
+            }
+
+            // This also enforces authorisation: the lookup is scoped to the
+            // subjects this professor actually teaches.
+            var semesterSubject = await _profRepository.FindTaughtSemesterSubjectAsync(
+                professorId, request.StudentId, request.SubjectId);
+
+            if (semesterSubject is null)
+            {
+                return Fail("You do not teach this student in this subject.");
+            }
+
+            var existing = await _profRepository.GetPassedSubjectAsync(semesterSubject.Id);
+
+            switch (action)
+            {
+                case GradeAction.Add:
+                    if (existing is not null)
+                    {
+                        return Fail("This subject is already graded. Use edit to change the grade.");
+                    }
+                    await _profRepository.AddPassedSubjectAsync(new PassedSubject
+                    {
+                        SemesterSubjectId = semesterSubject.Id,
+                        Grade = (Grade)request.Grade,
+                        // date_passed is `timestamp without time zone`.
+                        DatePassed = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified)
+                    });
+                    return Ok($"Grade {request.Grade} added.");
+
+                case GradeAction.Edit:
+                    if (existing is null)
+                    {
+                        return Fail("This subject has no grade yet. Use add first.");
+                    }
+                    existing.Grade = (Grade)request.Grade;
+                    existing.DatePassed = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);
+                    await _profRepository.UpdatePassedSubjectAsync(existing);
+                    return Ok($"Grade changed to {request.Grade}.");
+
+                case GradeAction.Remove:
+                    if (existing is null)
+                    {
+                        return Fail("This subject has no grade to remove.");
+                    }
+                    await _profRepository.RemovePassedSubjectAsync(existing);
+                    return Ok("Grade removed.");
+
+                default:
+                    return Fail("Unknown action.");
+            }
+        }
+
+        private static GradeResultDto Ok(string message) =>
+            new() { Ok = true, Message = message };
+
+        private static GradeResultDto Fail(string message) =>
+            new() { Ok = false, Message = message };
+    }
+}
Index: iknow-api/Services/Implementations/RefreshTokenService.cs
===================================================================
--- iknow-api/Services/Implementations/RefreshTokenService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Implementations/RefreshTokenService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,50 @@
+using iknow_api.DTOs;
+using iknow_api.Services;
+using System.Security.Cryptography;
+using iknow_api.Models;
+using iknow_api.Models;
+using iknow_api.Repositories;
+
+namespace iknow_api.Services
+{
+    public class RefreshTokenService : IRefreshTokenService
+    {
+        private readonly IRefreshTokenRepository _refreshTokenRepository;
+        public RefreshTokenService(IRefreshTokenRepository refreshTokenRepository)
+        {
+            _refreshTokenRepository = refreshTokenRepository;
+        }
+
+        public async Task<string> GenerateRefreshToken(int userid)
+        {
+            var randomNumber = new byte[32];
+
+            using (var rng = RandomNumberGenerator.Create())
+            {
+                rng.GetBytes(randomNumber);
+            }
+
+            var refreshToken = Convert.ToBase64String(randomNumber);
+
+            RefreshToken refreshTokenModel = new RefreshToken
+            {
+                Token = refreshToken,
+                UserId = userid,
+                ExpiresAt = DateTime.SpecifyKind(DateTime.UtcNow.AddMonths(1), DateTimeKind.Unspecified),
+                IsValid = true
+            };
+
+            await _refreshTokenRepository.AddTokenAsync(refreshTokenModel);
+
+            return refreshToken;
+        }
+
+        public async Task<bool> VerifyRefreshToken(VerifyRefreshTokenDto refreshTokenDto)
+        {
+
+            return await _refreshTokenRepository.VerifyTokenAsync(refreshTokenDto);
+        }
+
+        
+    }
+}
Index: iknow-api/Services/Implementations/UserService.cs
===================================================================
--- iknow-api/Services/Implementations/UserService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Implementations/UserService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,105 @@
+﻿using iknow_api.Repositories;
+using iknow_api.Services;
+using iknow_api.DTOs;
+using Microsoft.AspNetCore.Http.HttpResults;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+using Microsoft.IdentityModel.Tokens;
+using iknow_api.Models;
+
+namespace iknow_api.Services
+{
+    public class UserService : IUserService
+    {
+
+        private readonly IUserRepository _userRepository;
+        private readonly IConfiguration _configuration;
+        public UserService(IUserRepository userRepository, IConfiguration configuration)
+        {
+            _userRepository = userRepository;
+            _configuration = configuration;
+        }
+        public async Task<User> GetUserData(string JWT)
+        {
+            var userId = ExtractUserIdFromJwt(JWT);
+            if (userId == null)
+                return null;
+
+            // Now you can use userId to fetch user data
+            var user = await _userRepository.GetUserByIdAsync(userId.Value);
+            if(user == null)
+                return null;
+            else
+                return user;
+        }
+        public async Task<List<EnrolledSemesters>> GetUserSemesters(string JWT)
+        {
+            var userId = ExtractUserIdFromJwt(JWT);
+            if (userId == null)
+                return null;
+
+            // Now you can use userId to fetch user data
+            var semesters = await _userRepository.GetUserSemestersAsync(userId.Value);
+            if (semesters == null)
+                return null;
+            else
+                return semesters;
+        }
+
+        public async Task<List<PassedSubject>> GetUserPassedSubjects(string JWT)
+        {
+            var userId = ExtractUserIdFromJwt(JWT);
+            if (userId == null)
+                return null;
+
+            var passedSubjects = await _userRepository.GetUserPassedSubjectsAsync(userId.Value);
+            if (passedSubjects == null)
+                return null;
+            else
+                return passedSubjects;
+        }
+
+        private int? ExtractUserIdFromJwt(string token)
+        {
+            try
+            {
+                var tokenHandler = new JwtSecurityTokenHandler();
+                var keyString = _configuration["Jwt:Key"];
+                
+                if (string.IsNullOrEmpty(keyString))
+                    return null;
+
+                var key = Encoding.UTF8.GetBytes(keyString);
+
+                var validationParameters = new TokenValidationParameters
+                {
+                    ValidateIssuerSigningKey = true,
+                    IssuerSigningKey = new SymmetricSecurityKey(key),
+                    ValidateIssuer = true,
+                    ValidIssuer = "iknow-api",
+                    ValidateAudience = true,
+                    ValidAudience = "iknow-api",
+                    ValidateLifetime = true,
+                    ClockSkew = TimeSpan.Zero
+                };
+
+                var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
+                
+                // Extract the "id" claim that was set in AuthService.CreateToken
+                var userIdClaim = principal.FindFirst("id");
+                
+                if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId))
+                {
+                    return userId;
+                }
+
+                return null;
+            }
+            catch
+            {
+                return null;
+            }
+        }
+    }
+}
Index: iknow-api/Services/Interfaces/IAdminService.cs
===================================================================
--- iknow-api/Services/Interfaces/IAdminService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Interfaces/IAdminService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,28 @@
+using iknow_api.DTOs;
+
+namespace iknow_api.Services
+{
+    public interface IAdminService
+    {
+        // UC012 - subjects
+        Task<List<AdminSubjectDto>> GetSubjectsAsync();
+        Task<AdminResultDto> CreateSubjectAsync(SubjectWriteDto request);
+        Task<AdminResultDto> UpdateSubjectAsync(int subjectId, SubjectWriteDto request);
+        Task<AdminResultDto> DeleteSubjectAsync(int subjectId);
+        Task<AdminResultDto> LinkMajorAsync(int subjectId, MajorLinkDto request);
+        Task<AdminResultDto> UnlinkMajorAsync(int subjectId, int majorId);
+        Task<AdminResultDto> AddPrerequisiteAsync(int subjectId, PrerequisiteDto request);
+        Task<AdminResultDto> RemovePrerequisiteAsync(int subjectId, int dependencyId);
+
+        // UC013 - active semesters
+        Task<List<AdminSemesterDto>> GetSemestersAsync();
+        Task<AdminResultDto> CreateSemesterAsync(SemesterWriteDto request);
+
+        // UC014 - professor assignments
+        Task<ScheduleDto?> GetScheduleAsync(int semesterId);
+        Task<AdminResultDto> AssignAsync(ScheduleWriteDto request);
+        Task<AdminResultDto> UnassignAsync(ScheduleWriteDto request);
+
+        Task<List<SubjectRefDto>> GetMajorsAsync();
+    }
+}
Index: iknow-api/Services/Interfaces/IAuthService.cs
===================================================================
--- iknow-api/Services/Interfaces/IAuthService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Interfaces/IAuthService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,13 @@
+﻿using iknow_api.DTOs;
+using iknow_api.Models;
+namespace iknow_api.Services
+{
+    public interface IAuthService
+    {
+        Task<bool> RegisterAsync(RegisterDto registerDto);
+        Task<AuthResultDto?> LoginAsync(LoginDto loginDto);
+        Task<int> GetUsersCountAsync();
+        Task<AuthResultDto> GenerateNewJWT(VerifyRefreshTokenDto token);
+       
+    }
+}
Index: iknow-api/Services/Interfaces/IEnrollmentService.cs
===================================================================
--- iknow-api/Services/Interfaces/IEnrollmentService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Interfaces/IEnrollmentService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,16 @@
+using iknow_api.DTOs;
+
+namespace iknow_api.Services
+{
+    public interface IEnrollmentService
+    {
+        /// <summary>The semesters, majors and subjects this student may enrol in.</summary>
+        Task<EnrollmentOptionsDto> GetOptionsAsync(int studentId);
+
+        /// <summary>
+        /// Creates one enrolled_semesters row and its semesters_subjects rows,
+        /// or returns why it could not.
+        /// </summary>
+        Task<EnrollSemesterResultDto> EnrollAsync(int studentId, EnrollSemesterRequestDto request);
+    }
+}
Index: iknow-api/Services/Interfaces/IProfService.cs
===================================================================
--- iknow-api/Services/Interfaces/IProfService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Interfaces/IProfService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,18 @@
+using iknow_api.DTOs;
+
+namespace iknow_api.Services
+{
+    public enum GradeAction
+    {
+        Add,
+        Edit,
+        Remove
+    }
+
+    public interface IProfService
+    {
+        Task<List<SubjectStudentsDto>> GetStudentsBySubjectAsync(int professorId);
+
+        Task<GradeResultDto> SetGradeAsync(int professorId, GradeRequestDto request, GradeAction action);
+    }
+}
Index: iknow-api/Services/Interfaces/IRefreshTokenService.cs
===================================================================
--- iknow-api/Services/Interfaces/IRefreshTokenService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Interfaces/IRefreshTokenService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,10 @@
+using iknow_api.DTOs;
+
+namespace iknow_api.Services
+{
+    public interface IRefreshTokenService
+    {
+        Task<bool> VerifyRefreshToken(VerifyRefreshTokenDto refreshTokenDto);
+        Task<string> GenerateRefreshToken(int userid);
+    }
+}
Index: iknow-api/Services/Interfaces/IUserService.cs
===================================================================
--- iknow-api/Services/Interfaces/IUserService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/Services/Interfaces/IUserService.cs	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,11 @@
+﻿using iknow_api.DTOs;
+using iknow_api.Models;
+namespace iknow_api.Services
+{
+    public interface IUserService
+    {
+        Task<User> GetUserData(string userId);
+        Task<List<EnrolledSemesters>> GetUserSemesters(string userId);
+        Task<List<PassedSubject>> GetUserPassedSubjects(string userId);
+    }
+}
Index: iknow-api/appsettings.Development.json.example
===================================================================
--- iknow-api/appsettings.Development.json.example	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/appsettings.Development.json.example	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,14 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "ConnectionStrings": {
+    "DefaultConnection": "Host=localhost;Port=9999;Database=db_202526z_va_prj_know2026;Username=db_202526z_va_prj_iknow2026_owner;Password=YOUR_DB_PASSWORD_HERE;Search Path=project;Include Error Detail=true"
+  },
+  "Jwt": {
+    "Key": "ANY_LOCAL_SIGNING_KEY_AT_LEAST_32_CHARACTERS_LONG"
+  }
+}
Index: iknow-api/appsettings.json
===================================================================
--- iknow-api/appsettings.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/appsettings.json	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,13 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedOrigins": [
+    "http://localhost:3000",
+    "https://iknow-remaster.vercel.app"
+  ],
+  "AllowedHosts": "*"
+}
Index: iknow-api/iknow-api.csproj
===================================================================
--- iknow-api/iknow-api.csproj	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/iknow-api.csproj	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net9.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <RootNamespace>iknow_api</RootNamespace>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.10" />
+    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.9" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.10">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
+    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
+  </ItemGroup>
+
+</Project>
Index: iknow-api/iknow-api.http
===================================================================
--- iknow-api/iknow-api.http	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ iknow-api/iknow-api.http	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,6 @@
+@iknow_api_HostAddress = http://localhost:5147
+
+GET {{iknow_api_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
Index: xt.config.ts
===================================================================
--- next.config.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,7 +1,0 @@
-import type { NextConfig } from "next";
-
-const nextConfig: NextConfig = {
-  /* config options here */
-};
-
-export default nextConfig;
Index: ckage-lock.json
===================================================================
--- package-lock.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,7383 +1,0 @@
-{
-  "name": "iknow-remaster",
-  "version": "0.1.0",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "iknow-remaster",
-      "version": "0.1.0",
-      "dependencies": {
-        "@fortawesome/fontawesome-svg-core": "^7.0.1",
-        "@fortawesome/free-brands-svg-icons": "^7.0.1",
-        "@fortawesome/free-regular-svg-icons": "^7.0.1",
-        "@fortawesome/free-solid-svg-icons": "^7.0.1",
-        "@fortawesome/react-fontawesome": "^3.0.2",
-        "class-variance-authority": "^0.7.1",
-        "clsx": "^2.1.1",
-        "i18next": "^25.8.0",
-        "jspdf": "^4.1.0",
-        "jspdf-autotable": "^5.0.7",
-        "lucide-react": "^0.544.0",
-        "next": "^16.1.6",
-        "next-intl": "^4.8.0",
-        "next-themes": "^0.4.6",
-        "react": "^19.2.4",
-        "react-dom": "^19.2.4",
-        "react-i18next": "^16.5.4",
-        "tailwind-merge": "^3.3.1"
-      },
-      "devDependencies": {
-        "@eslint/eslintrc": "^3",
-        "@tailwindcss/postcss": "^4",
-        "@types/node": "^20",
-        "@types/react": "^19",
-        "@types/react-dom": "^19",
-        "autoprefixer": "^10.4.21",
-        "eslint": "^9",
-        "eslint-config-next": "15.5.4",
-        "postcss": "^8.5.6",
-        "tailwindcss": "^4.1.13",
-        "tw-animate-css": "^1.4.0",
-        "typescript": "^5"
-      }
-    },
-    "node_modules/@alloc/quick-lru": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
-      "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/@babel/runtime": {
-      "version": "7.28.6",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
-      "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@emnapi/core": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz",
-      "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/wasi-threads": "1.1.0",
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@emnapi/runtime": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
-      "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@emnapi/wasi-threads": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
-      "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@eslint-community/eslint-utils": {
-      "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
-      "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "eslint-visitor-keys": "^3.4.3"
-      },
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
-      }
-    },
-    "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
-    "node_modules/@eslint-community/regexpp": {
-      "version": "4.12.2",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
-      "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
-      }
-    },
-    "node_modules/@eslint/config-array": {
-      "version": "0.21.1",
-      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
-      "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@eslint/object-schema": "^2.1.7",
-        "debug": "^4.3.1",
-        "minimatch": "^3.1.2"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      }
-    },
-    "node_modules/@eslint/config-helpers": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
-      "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@eslint/core": "^0.17.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      }
-    },
-    "node_modules/@eslint/core": {
-      "version": "0.17.0",
-      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
-      "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@types/json-schema": "^7.0.15"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      }
-    },
-    "node_modules/@eslint/eslintrc": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
-      "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "ajv": "^6.12.4",
-        "debug": "^4.3.2",
-        "espree": "^10.0.1",
-        "globals": "^14.0.0",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.2.1",
-        "js-yaml": "^4.1.1",
-        "minimatch": "^3.1.2",
-        "strip-json-comments": "^3.1.1"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
-    "node_modules/@eslint/js": {
-      "version": "9.39.2",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
-      "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://eslint.org/donate"
-      }
-    },
-    "node_modules/@eslint/object-schema": {
-      "version": "2.1.7",
-      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
-      "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      }
-    },
-    "node_modules/@eslint/plugin-kit": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
-      "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@eslint/core": "^0.17.0",
-        "levn": "^0.4.1"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      }
-    },
-    "node_modules/@formatjs/ecma402-abstract": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-3.1.0.tgz",
-      "integrity": "sha512-CjP1sUzM7XiQW6YluDreN+dMvcKZysO/J4ikvuDjDyd6nSOoSqAK9gvD1s75ZFaJVXtYOsz+y3CUXPZ1sKxcxw==",
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/fast-memoize": "3.1.0",
-        "@formatjs/intl-localematcher": "0.8.0",
-        "decimal.js": "^10.6.0",
-        "tslib": "^2.8.1"
-      }
-    },
-    "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": {
-      "version": "0.8.0",
-      "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.0.tgz",
-      "integrity": "sha512-zgMYWdUlmEZpX2Io+v3LHrfq9xZ6khpQVf9UAw2xYWhGerGgI9XgH1HvL/A34jWiruUJpYlP5pk4g8nIcaDrXQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/fast-memoize": "3.1.0",
-        "tslib": "^2.8.1"
-      }
-    },
-    "node_modules/@formatjs/fast-memoize": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.0.tgz",
-      "integrity": "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg==",
-      "license": "MIT",
-      "dependencies": {
-        "tslib": "^2.8.1"
-      }
-    },
-    "node_modules/@formatjs/icu-messageformat-parser": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.0.tgz",
-      "integrity": "sha512-Q01XuvtbDVCJQsG/E2MSfMZ+UdUoZV8v4Aex8tTH44SqKJZCeu5LjuclaKFUS0o1YoXndfEinJen5k1T1GR1vg==",
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/ecma402-abstract": "3.1.0",
-        "@formatjs/icu-skeleton-parser": "2.1.0",
-        "tslib": "^2.8.1"
-      }
-    },
-    "node_modules/@formatjs/icu-skeleton-parser": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.0.tgz",
-      "integrity": "sha512-wNer4imHDFBVAJnMb2OGoSyM4wL/uuLnuo5mrenliqkDaNjRbG4jzlJcwTTDEBhai8iCjnzUsE7xwNJC29SfWw==",
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/ecma402-abstract": "3.1.0",
-        "tslib": "^2.8.1"
-      }
-    },
-    "node_modules/@formatjs/intl-localematcher": {
-      "version": "0.5.10",
-      "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz",
-      "integrity": "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==",
-      "license": "MIT",
-      "dependencies": {
-        "tslib": "2"
-      }
-    },
-    "node_modules/@fortawesome/fontawesome-common-types": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.1.0.tgz",
-      "integrity": "sha512-l/BQM7fYntsCI//du+6sEnHOP6a74UixFyOYUyz2DLMXKx+6DEhfR3F2NYGE45XH1JJuIamacb4IZs9S0ZOWLA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@fortawesome/fontawesome-svg-core": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz",
-      "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@fortawesome/fontawesome-common-types": "7.1.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@fortawesome/free-brands-svg-icons": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-7.1.0.tgz",
-      "integrity": "sha512-9byUd9bgNfthsZAjBl6GxOu1VPHgBuRUP9juI7ZoM98h8xNPTCTagfwUFyYscdZq4Hr7gD1azMfM9s5tIWKZZA==",
-      "license": "(CC-BY-4.0 AND MIT)",
-      "dependencies": {
-        "@fortawesome/fontawesome-common-types": "7.1.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@fortawesome/free-regular-svg-icons": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-7.1.0.tgz",
-      "integrity": "sha512-0e2fdEyB4AR+e6kU4yxwA/MonnYcw/CsMEP9lH82ORFi9svA6/RhDyhxIv5mlJaldmaHLLYVTb+3iEr+PDSZuQ==",
-      "license": "(CC-BY-4.0 AND MIT)",
-      "dependencies": {
-        "@fortawesome/fontawesome-common-types": "7.1.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@fortawesome/free-solid-svg-icons": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.1.0.tgz",
-      "integrity": "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA==",
-      "license": "(CC-BY-4.0 AND MIT)",
-      "dependencies": {
-        "@fortawesome/fontawesome-common-types": "7.1.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/@fortawesome/react-fontawesome": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-3.1.1.tgz",
-      "integrity": "sha512-EDllr9hpodc21odmUywHS1alXNiCd4E8sp5GJ5s7wYINz8vSmMiNWpALTiuYODb865YyQ/NlyiN4mbXp7HCNqg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=20"
-      },
-      "peerDependencies": {
-        "@fortawesome/fontawesome-svg-core": "~6 || ~7",
-        "react": "^18.0.0 || ^19.0.0"
-      }
-    },
-    "node_modules/@humanfs/core": {
-      "version": "0.19.1",
-      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
-      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=18.18.0"
-      }
-    },
-    "node_modules/@humanfs/node": {
-      "version": "0.16.7",
-      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
-      "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@humanfs/core": "^0.19.1",
-        "@humanwhocodes/retry": "^0.4.0"
-      },
-      "engines": {
-        "node": ">=18.18.0"
-      }
-    },
-    "node_modules/@humanwhocodes/module-importer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=12.22"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/nzakas"
-      }
-    },
-    "node_modules/@humanwhocodes/retry": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
-      "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=18.18"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/nzakas"
-      }
-    },
-    "node_modules/@img/colour": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
-      "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@img/sharp-darwin-arm64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
-      "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-darwin-arm64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-darwin-x64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
-      "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-darwin-x64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-libvips-darwin-arm64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
-      "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-darwin-x64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
-      "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-arm": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
-      "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-arm64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
-      "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-ppc64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
-      "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-riscv64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
-      "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-s390x": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
-      "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
-      "cpu": [
-        "s390x"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linux-x64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
-      "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
-      "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-libvips-linuxmusl-x64": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
-      "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-linux-arm": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
-      "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-arm": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linux-arm64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
-      "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-arm64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linux-ppc64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
-      "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-ppc64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linux-riscv64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
-      "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
-      "cpu": [
-        "riscv64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-riscv64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linux-s390x": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
-      "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
-      "cpu": [
-        "s390x"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-s390x": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linux-x64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
-      "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linux-x64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linuxmusl-arm64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
-      "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-linuxmusl-x64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
-      "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
-      }
-    },
-    "node_modules/@img/sharp-wasm32": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
-      "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
-      "cpu": [
-        "wasm32"
-      ],
-      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/runtime": "^1.7.0"
-      },
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-win32-arm64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
-      "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0 AND LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-win32-ia32": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
-      "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
-      "cpu": [
-        "ia32"
-      ],
-      "license": "Apache-2.0 AND LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@img/sharp-win32-x64": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
-      "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0 AND LGPL-3.0-or-later",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      }
-    },
-    "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.13",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
-      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.5.0",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      }
-    },
-    "node_modules/@jridgewell/remapping": {
-      "version": "2.3.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
-      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/gen-mapping": "^0.3.5",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      }
-    },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
-      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.5.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
-      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.31",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
-      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/resolve-uri": "^3.1.0",
-        "@jridgewell/sourcemap-codec": "^1.4.14"
-      }
-    },
-    "node_modules/@napi-rs/wasm-runtime": {
-      "version": "0.2.12",
-      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
-      "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/core": "^1.4.3",
-        "@emnapi/runtime": "^1.4.3",
-        "@tybys/wasm-util": "^0.10.0"
-      }
-    },
-    "node_modules/@next/env": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
-      "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
-      "license": "MIT"
-    },
-    "node_modules/@next/eslint-plugin-next": {
-      "version": "15.5.4",
-      "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.4.tgz",
-      "integrity": "sha512-SR1vhXNNg16T4zffhJ4TS7Xn7eq4NfKfcOsRwea7RIAHrjRpI9ALYbamqIJqkAhowLlERffiwk0FMvTLNdnVtw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "fast-glob": "3.3.1"
-      }
-    },
-    "node_modules/@next/swc-darwin-arm64": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
-      "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-darwin-x64": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
-      "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-arm64-gnu": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
-      "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-arm64-musl": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
-      "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-x64-gnu": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
-      "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-x64-musl": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
-      "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-arm64-msvc": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
-      "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-x64-msvc": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
-      "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@nodelib/fs.scandir": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@nodelib/fs.stat": "2.0.5",
-        "run-parallel": "^1.1.9"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/@nodelib/fs.stat": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/@nodelib/fs.walk": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@nodelib/fs.scandir": "2.1.5",
-        "fastq": "^1.6.0"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/@nolyfill/is-core-module": {
-      "version": "1.0.39",
-      "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
-      "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=12.4.0"
-      }
-    },
-    "node_modules/@parcel/watcher": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
-      "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
-      "hasInstallScript": true,
-      "license": "MIT",
-      "dependencies": {
-        "detect-libc": "^2.0.3",
-        "is-glob": "^4.0.3",
-        "node-addon-api": "^7.0.0",
-        "picomatch": "^4.0.3"
-      },
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      },
-      "optionalDependencies": {
-        "@parcel/watcher-android-arm64": "2.5.6",
-        "@parcel/watcher-darwin-arm64": "2.5.6",
-        "@parcel/watcher-darwin-x64": "2.5.6",
-        "@parcel/watcher-freebsd-x64": "2.5.6",
-        "@parcel/watcher-linux-arm-glibc": "2.5.6",
-        "@parcel/watcher-linux-arm-musl": "2.5.6",
-        "@parcel/watcher-linux-arm64-glibc": "2.5.6",
-        "@parcel/watcher-linux-arm64-musl": "2.5.6",
-        "@parcel/watcher-linux-x64-glibc": "2.5.6",
-        "@parcel/watcher-linux-x64-musl": "2.5.6",
-        "@parcel/watcher-win32-arm64": "2.5.6",
-        "@parcel/watcher-win32-ia32": "2.5.6",
-        "@parcel/watcher-win32-x64": "2.5.6"
-      }
-    },
-    "node_modules/@parcel/watcher-android-arm64": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
-      "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-darwin-arm64": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
-      "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-darwin-x64": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
-      "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-freebsd-x64": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
-      "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-linux-arm-glibc": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
-      "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-linux-arm-musl": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
-      "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-linux-arm64-glibc": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
-      "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-linux-arm64-musl": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
-      "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-linux-x64-glibc": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
-      "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-linux-x64-musl": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
-      "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-win32-arm64": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
-      "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-win32-ia32": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
-      "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
-      "cpu": [
-        "ia32"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher-win32-x64": {
-      "version": "2.5.6",
-      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
-      "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/@parcel/watcher/node_modules/picomatch": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
-      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/@rtsao/scc": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
-      "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@rushstack/eslint-patch": {
-      "version": "1.15.0",
-      "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz",
-      "integrity": "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@schummar/icu-type-parser": {
-      "version": "1.21.5",
-      "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz",
-      "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==",
-      "license": "MIT"
-    },
-    "node_modules/@swc/core-darwin-arm64": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.11.tgz",
-      "integrity": "sha512-QoIupRWVH8AF1TgxYyeA5nS18dtqMuxNwchjBIwJo3RdwLEFiJq6onOx9JAxHtuPwUkIVuU2Xbp+jCJ7Vzmgtg==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-darwin-x64": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.11.tgz",
-      "integrity": "sha512-S52Gu1QtPSfBYDiejlcfp9GlN+NjTZBRRNsz8PNwBgSE626/FUf2PcllVUix7jqkoMC+t0rS8t+2/aSWlMuQtA==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-linux-arm-gnueabihf": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.11.tgz",
-      "integrity": "sha512-lXJs8oXo6Z4yCpimpQ8vPeCjkgoHu5NoMvmJZ8qxDyU99KVdg6KwU9H79vzrmB+HfH+dCZ7JGMqMF//f8Cfvdg==",
-      "cpu": [
-        "arm"
-      ],
-      "license": "Apache-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-linux-arm64-gnu": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.11.tgz",
-      "integrity": "sha512-chRsz1K52/vj8Mfq/QOugVphlKPWlMh10V99qfH41hbGvwAU6xSPd681upO4bKiOr9+mRIZZW+EfJqY42ZzRyA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-linux-arm64-musl": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.11.tgz",
-      "integrity": "sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-linux-x64-gnu": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.11.tgz",
-      "integrity": "sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-linux-x64-musl": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.11.tgz",
-      "integrity": "sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-win32-arm64-msvc": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.11.tgz",
-      "integrity": "sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==",
-      "cpu": [
-        "arm64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-win32-ia32-msvc": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.11.tgz",
-      "integrity": "sha512-6XnzORkZCQzvTQ6cPrU7iaT9+i145oLwnin8JrfsLG41wl26+5cNQ2XV3zcbrnFEV6esjOceom9YO1w9mGJByw==",
-      "cpu": [
-        "ia32"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/core-win32-x64-msvc": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.11.tgz",
-      "integrity": "sha512-IQ2n6af7XKLL6P1gIeZACskSxK8jWtoKpJWLZmdXTDj1MGzktUy4i+FvpdtxFmJWNavRWH1VmTr6kAubRDHeKw==",
-      "cpu": [
-        "x64"
-      ],
-      "license": "Apache-2.0 AND MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@swc/counter": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
-      "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
-      "license": "Apache-2.0"
-    },
-    "node_modules/@swc/helpers": {
-      "version": "0.5.15",
-      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
-      "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "tslib": "^2.8.0"
-      }
-    },
-    "node_modules/@swc/types": {
-      "version": "0.1.25",
-      "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz",
-      "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@swc/counter": "^0.1.3"
-      }
-    },
-    "node_modules/@tailwindcss/node": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
-      "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/remapping": "^2.3.4",
-        "enhanced-resolve": "^5.18.3",
-        "jiti": "^2.6.1",
-        "lightningcss": "1.30.2",
-        "magic-string": "^0.30.21",
-        "source-map-js": "^1.2.1",
-        "tailwindcss": "4.1.18"
-      }
-    },
-    "node_modules/@tailwindcss/oxide": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz",
-      "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 10"
-      },
-      "optionalDependencies": {
-        "@tailwindcss/oxide-android-arm64": "4.1.18",
-        "@tailwindcss/oxide-darwin-arm64": "4.1.18",
-        "@tailwindcss/oxide-darwin-x64": "4.1.18",
-        "@tailwindcss/oxide-freebsd-x64": "4.1.18",
-        "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18",
-        "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18",
-        "@tailwindcss/oxide-linux-arm64-musl": "4.1.18",
-        "@tailwindcss/oxide-linux-x64-gnu": "4.1.18",
-        "@tailwindcss/oxide-linux-x64-musl": "4.1.18",
-        "@tailwindcss/oxide-wasm32-wasi": "4.1.18",
-        "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18",
-        "@tailwindcss/oxide-win32-x64-msvc": "4.1.18"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-android-arm64": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz",
-      "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-darwin-arm64": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz",
-      "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-darwin-x64": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz",
-      "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-freebsd-x64": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz",
-      "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz",
-      "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz",
-      "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz",
-      "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz",
-      "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-linux-x64-musl": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz",
-      "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-wasm32-wasi": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz",
-      "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==",
-      "bundleDependencies": [
-        "@napi-rs/wasm-runtime",
-        "@emnapi/core",
-        "@emnapi/runtime",
-        "@tybys/wasm-util",
-        "@emnapi/wasi-threads",
-        "tslib"
-      ],
-      "cpu": [
-        "wasm32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@emnapi/core": "^1.7.1",
-        "@emnapi/runtime": "^1.7.1",
-        "@emnapi/wasi-threads": "^1.1.0",
-        "@napi-rs/wasm-runtime": "^1.1.0",
-        "@tybys/wasm-util": "^0.10.1",
-        "tslib": "^2.4.0"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz",
-      "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz",
-      "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@tailwindcss/postcss": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz",
-      "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@alloc/quick-lru": "^5.2.0",
-        "@tailwindcss/node": "4.1.18",
-        "@tailwindcss/oxide": "4.1.18",
-        "postcss": "^8.4.41",
-        "tailwindcss": "4.1.18"
-      }
-    },
-    "node_modules/@tybys/wasm-util": {
-      "version": "0.10.1",
-      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
-      "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@types/estree": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
-      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@types/json-schema": {
-      "version": "7.0.15",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
-      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@types/json5": {
-      "version": "0.0.29",
-      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@types/node": {
-      "version": "20.19.30",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz",
-      "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "undici-types": "~6.21.0"
-      }
-    },
-    "node_modules/@types/pako": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
-      "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
-      "license": "MIT"
-    },
-    "node_modules/@types/raf": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
-      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
-      "license": "MIT",
-      "optional": true
-    },
-    "node_modules/@types/react": {
-      "version": "19.2.10",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz",
-      "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "csstype": "^3.2.2"
-      }
-    },
-    "node_modules/@types/react-dom": {
-      "version": "19.2.3",
-      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
-      "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
-      "dev": true,
-      "license": "MIT",
-      "peerDependencies": {
-        "@types/react": "^19.2.0"
-      }
-    },
-    "node_modules/@types/trusted-types": {
-      "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
-      "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
-      "license": "MIT",
-      "optional": true
-    },
-    "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
-      "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@eslint-community/regexpp": "^4.12.2",
-        "@typescript-eslint/scope-manager": "8.54.0",
-        "@typescript-eslint/type-utils": "8.54.0",
-        "@typescript-eslint/utils": "8.54.0",
-        "@typescript-eslint/visitor-keys": "8.54.0",
-        "ignore": "^7.0.5",
-        "natural-compare": "^1.4.0",
-        "ts-api-utils": "^2.4.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "@typescript-eslint/parser": "^8.54.0",
-        "eslint": "^8.57.0 || ^9.0.0",
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
-      "version": "7.0.5",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
-      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 4"
-      }
-    },
-    "node_modules/@typescript-eslint/parser": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
-      "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@typescript-eslint/scope-manager": "8.54.0",
-        "@typescript-eslint/types": "8.54.0",
-        "@typescript-eslint/typescript-estree": "8.54.0",
-        "@typescript-eslint/visitor-keys": "8.54.0",
-        "debug": "^4.4.3"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^8.57.0 || ^9.0.0",
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/project-service": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
-      "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@typescript-eslint/tsconfig-utils": "^8.54.0",
-        "@typescript-eslint/types": "^8.54.0",
-        "debug": "^4.4.3"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/scope-manager": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
-      "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@typescript-eslint/types": "8.54.0",
-        "@typescript-eslint/visitor-keys": "8.54.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/tsconfig-utils": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
-      "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/type-utils": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
-      "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@typescript-eslint/types": "8.54.0",
-        "@typescript-eslint/typescript-estree": "8.54.0",
-        "@typescript-eslint/utils": "8.54.0",
-        "debug": "^4.4.3",
-        "ts-api-utils": "^2.4.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^8.57.0 || ^9.0.0",
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/types": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
-      "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
-      "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@typescript-eslint/project-service": "8.54.0",
-        "@typescript-eslint/tsconfig-utils": "8.54.0",
-        "@typescript-eslint/types": "8.54.0",
-        "@typescript-eslint/visitor-keys": "8.54.0",
-        "debug": "^4.4.3",
-        "minimatch": "^9.0.5",
-        "semver": "^7.7.3",
-        "tinyglobby": "^0.2.15",
-        "ts-api-utils": "^2.4.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
-      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "balanced-match": "^1.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
-      "version": "9.0.5",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
-      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "brace-expansion": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=16 || 14 >=14.17"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/@typescript-eslint/utils": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
-      "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@eslint-community/eslint-utils": "^4.9.1",
-        "@typescript-eslint/scope-manager": "8.54.0",
-        "@typescript-eslint/types": "8.54.0",
-        "@typescript-eslint/typescript-estree": "8.54.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^8.57.0 || ^9.0.0",
-        "typescript": ">=4.8.4 <6.0.0"
-      }
-    },
-    "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "8.54.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
-      "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@typescript-eslint/types": "8.54.0",
-        "eslint-visitor-keys": "^4.2.1"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/typescript-eslint"
-      }
-    },
-    "node_modules/@unrs/resolver-binding-android-arm-eabi": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
-      "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-android-arm64": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
-      "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-darwin-arm64": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
-      "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-darwin-x64": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
-      "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-freebsd-x64": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
-      "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
-      "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
-      "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
-      "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
-      "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
-      "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
-      "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
-      "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
-      "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
-      "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-linux-x64-musl": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
-      "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-wasm32-wasi": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
-      "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
-      "cpu": [
-        "wasm32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@napi-rs/wasm-runtime": "^0.2.11"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      }
-    },
-    "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
-      "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
-      "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
-      "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/acorn": {
-      "version": "8.15.0",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
-      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true,
-      "bin": {
-        "acorn": "bin/acorn"
-      },
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
-    "node_modules/acorn-jsx": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
-      "dev": true,
-      "license": "MIT",
-      "peerDependencies": {
-        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
-      }
-    },
-    "node_modules/ajv": {
-      "version": "6.12.6",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "fast-deep-equal": "^3.1.1",
-        "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.4.1",
-        "uri-js": "^4.2.2"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/epoberezkin"
-      }
-    },
-    "node_modules/ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "color-convert": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true,
-      "license": "Python-2.0"
-    },
-    "node_modules/aria-query": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
-      "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/array-buffer-byte-length": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
-      "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "is-array-buffer": "^3.0.5"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/array-includes": {
-      "version": "3.1.9",
-      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
-      "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.4",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.24.0",
-        "es-object-atoms": "^1.1.1",
-        "get-intrinsic": "^1.3.0",
-        "is-string": "^1.1.1",
-        "math-intrinsics": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/array.prototype.findlast": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
-      "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.2",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.0.0",
-        "es-shim-unscopables": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/array.prototype.findlastindex": {
-      "version": "1.2.6",
-      "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
-      "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.4",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.9",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.1.1",
-        "es-shim-unscopables": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/array.prototype.flat": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
-      "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.5",
-        "es-shim-unscopables": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/array.prototype.flatmap": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
-      "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.5",
-        "es-shim-unscopables": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/array.prototype.tosorted": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
-      "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.3",
-        "es-errors": "^1.3.0",
-        "es-shim-unscopables": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/arraybuffer.prototype.slice": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
-      "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "array-buffer-byte-length": "^1.0.1",
-        "call-bind": "^1.0.8",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.5",
-        "es-errors": "^1.3.0",
-        "get-intrinsic": "^1.2.6",
-        "is-array-buffer": "^3.0.4"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/ast-types-flow": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
-      "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/async-function": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
-      "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/autoprefixer": {
-      "version": "10.4.23",
-      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz",
-      "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "browserslist": "^4.28.1",
-        "caniuse-lite": "^1.0.30001760",
-        "fraction.js": "^5.3.4",
-        "picocolors": "^1.1.1",
-        "postcss-value-parser": "^4.2.0"
-      },
-      "bin": {
-        "autoprefixer": "bin/autoprefixer"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      },
-      "peerDependencies": {
-        "postcss": "^8.1.0"
-      }
-    },
-    "node_modules/available-typed-arrays": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
-      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "possible-typed-array-names": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/axe-core": {
-      "version": "4.11.1",
-      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz",
-      "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==",
-      "dev": true,
-      "license": "MPL-2.0",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/axobject-query": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
-      "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/balanced-match": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/base64-arraybuffer": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
-      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">= 0.6.0"
-      }
-    },
-    "node_modules/baseline-browser-mapping": {
-      "version": "2.9.19",
-      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
-      "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
-      "license": "Apache-2.0",
-      "bin": {
-        "baseline-browser-mapping": "dist/cli.js"
-      }
-    },
-    "node_modules/brace-expansion": {
-      "version": "1.1.12",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
-      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "node_modules/braces": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
-      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "fill-range": "^7.1.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/browserslist": {
-      "version": "4.28.1",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
-      "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/browserslist"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/browserslist"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "baseline-browser-mapping": "^2.9.0",
-        "caniuse-lite": "^1.0.30001759",
-        "electron-to-chromium": "^1.5.263",
-        "node-releases": "^2.0.27",
-        "update-browserslist-db": "^1.2.0"
-      },
-      "bin": {
-        "browserslist": "cli.js"
-      },
-      "engines": {
-        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
-      }
-    },
-    "node_modules/call-bind": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
-      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind-apply-helpers": "^1.0.0",
-        "es-define-property": "^1.0.0",
-        "get-intrinsic": "^1.2.4",
-        "set-function-length": "^1.2.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/call-bind-apply-helpers": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
-      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "function-bind": "^1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/call-bound": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
-      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind-apply-helpers": "^1.0.2",
-        "get-intrinsic": "^1.3.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/callsites": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/caniuse-lite": {
-      "version": "1.0.30001766",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
-      "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/browserslist"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "CC-BY-4.0"
-    },
-    "node_modules/canvg": {
-      "version": "3.0.11",
-      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
-      "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "@babel/runtime": "^7.12.5",
-        "@types/raf": "^3.4.0",
-        "core-js": "^3.8.3",
-        "raf": "^3.4.1",
-        "regenerator-runtime": "^0.13.7",
-        "rgbcolor": "^1.0.1",
-        "stackblur-canvas": "^2.0.0",
-        "svg-pathdata": "^6.0.3"
-      },
-      "engines": {
-        "node": ">=10.0.0"
-      }
-    },
-    "node_modules/chalk": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
-      }
-    },
-    "node_modules/class-variance-authority": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
-      "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
-      "license": "Apache-2.0",
-      "dependencies": {
-        "clsx": "^2.1.1"
-      },
-      "funding": {
-        "url": "https://polar.sh/cva"
-      }
-    },
-    "node_modules/client-only": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
-      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
-      "license": "MIT"
-    },
-    "node_modules/clsx": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
-      "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
-      "engines": {
-        "node": ">=7.0.0"
-      }
-    },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/core-js": {
-      "version": "3.48.0",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz",
-      "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==",
-      "hasInstallScript": true,
-      "license": "MIT",
-      "optional": true,
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/core-js"
-      }
-    },
-    "node_modules/cross-spawn": {
-      "version": "7.0.6",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
-      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/css-line-break": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
-      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "utrie": "^1.0.2"
-      }
-    },
-    "node_modules/csstype": {
-      "version": "3.2.3",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
-      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/damerau-levenshtein": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
-      "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
-      "dev": true,
-      "license": "BSD-2-Clause"
-    },
-    "node_modules/data-view-buffer": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
-      "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "es-errors": "^1.3.0",
-        "is-data-view": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/data-view-byte-length": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
-      "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "es-errors": "^1.3.0",
-        "is-data-view": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/inspect-js"
-      }
-    },
-    "node_modules/data-view-byte-offset": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
-      "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "es-errors": "^1.3.0",
-        "is-data-view": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/debug": {
-      "version": "4.4.3",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
-      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "ms": "^2.1.3"
-      },
-      "engines": {
-        "node": ">=6.0"
-      },
-      "peerDependenciesMeta": {
-        "supports-color": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/decimal.js": {
-      "version": "10.6.0",
-      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
-      "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
-      "license": "MIT"
-    },
-    "node_modules/deep-is": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/define-data-property": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
-      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-define-property": "^1.0.0",
-        "es-errors": "^1.3.0",
-        "gopd": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/define-properties": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
-      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "define-data-property": "^1.0.1",
-        "has-property-descriptors": "^1.0.0",
-        "object-keys": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/detect-libc": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
-      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
-      "license": "Apache-2.0",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/doctrine": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "esutils": "^2.0.2"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/dompurify": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
-      "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
-      "license": "(MPL-2.0 OR Apache-2.0)",
-      "optional": true,
-      "optionalDependencies": {
-        "@types/trusted-types": "^2.0.7"
-      }
-    },
-    "node_modules/dunder-proto": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
-      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind-apply-helpers": "^1.0.1",
-        "es-errors": "^1.3.0",
-        "gopd": "^1.2.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/electron-to-chromium": {
-      "version": "1.5.282",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.282.tgz",
-      "integrity": "sha512-FCPkJtpst28UmFzd903iU7PdeVTfY0KAeJy+Lk0GLZRwgwYHn/irRcaCbQQOmr5Vytc/7rcavsYLvTM8RiHYhQ==",
-      "dev": true,
-      "license": "ISC"
-    },
-    "node_modules/emoji-regex": {
-      "version": "9.2.2",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/enhanced-resolve": {
-      "version": "5.18.4",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
-      "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "graceful-fs": "^4.2.4",
-        "tapable": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=10.13.0"
-      }
-    },
-    "node_modules/es-abstract": {
-      "version": "1.24.1",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
-      "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "array-buffer-byte-length": "^1.0.2",
-        "arraybuffer.prototype.slice": "^1.0.4",
-        "available-typed-arrays": "^1.0.7",
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.4",
-        "data-view-buffer": "^1.0.2",
-        "data-view-byte-length": "^1.0.2",
-        "data-view-byte-offset": "^1.0.1",
-        "es-define-property": "^1.0.1",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.1.1",
-        "es-set-tostringtag": "^2.1.0",
-        "es-to-primitive": "^1.3.0",
-        "function.prototype.name": "^1.1.8",
-        "get-intrinsic": "^1.3.0",
-        "get-proto": "^1.0.1",
-        "get-symbol-description": "^1.1.0",
-        "globalthis": "^1.0.4",
-        "gopd": "^1.2.0",
-        "has-property-descriptors": "^1.0.2",
-        "has-proto": "^1.2.0",
-        "has-symbols": "^1.1.0",
-        "hasown": "^2.0.2",
-        "internal-slot": "^1.1.0",
-        "is-array-buffer": "^3.0.5",
-        "is-callable": "^1.2.7",
-        "is-data-view": "^1.0.2",
-        "is-negative-zero": "^2.0.3",
-        "is-regex": "^1.2.1",
-        "is-set": "^2.0.3",
-        "is-shared-array-buffer": "^1.0.4",
-        "is-string": "^1.1.1",
-        "is-typed-array": "^1.1.15",
-        "is-weakref": "^1.1.1",
-        "math-intrinsics": "^1.1.0",
-        "object-inspect": "^1.13.4",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.7",
-        "own-keys": "^1.0.1",
-        "regexp.prototype.flags": "^1.5.4",
-        "safe-array-concat": "^1.1.3",
-        "safe-push-apply": "^1.0.0",
-        "safe-regex-test": "^1.1.0",
-        "set-proto": "^1.0.0",
-        "stop-iteration-iterator": "^1.1.0",
-        "string.prototype.trim": "^1.2.10",
-        "string.prototype.trimend": "^1.0.9",
-        "string.prototype.trimstart": "^1.0.8",
-        "typed-array-buffer": "^1.0.3",
-        "typed-array-byte-length": "^1.0.3",
-        "typed-array-byte-offset": "^1.0.4",
-        "typed-array-length": "^1.0.7",
-        "unbox-primitive": "^1.1.0",
-        "which-typed-array": "^1.1.19"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/es-define-property": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
-      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/es-errors": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
-      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/es-iterator-helpers": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz",
-      "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.4",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.24.1",
-        "es-errors": "^1.3.0",
-        "es-set-tostringtag": "^2.1.0",
-        "function-bind": "^1.1.2",
-        "get-intrinsic": "^1.3.0",
-        "globalthis": "^1.0.4",
-        "gopd": "^1.2.0",
-        "has-property-descriptors": "^1.0.2",
-        "has-proto": "^1.2.0",
-        "has-symbols": "^1.1.0",
-        "internal-slot": "^1.1.0",
-        "iterator.prototype": "^1.1.5",
-        "safe-array-concat": "^1.1.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/es-object-atoms": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
-      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/es-set-tostringtag": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
-      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "get-intrinsic": "^1.2.6",
-        "has-tostringtag": "^1.0.2",
-        "hasown": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/es-shim-unscopables": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
-      "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "hasown": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/es-to-primitive": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
-      "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-callable": "^1.2.7",
-        "is-date-object": "^1.0.5",
-        "is-symbol": "^1.0.4"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/escalade": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
-      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/escape-string-regexp": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/eslint": {
-      "version": "9.39.2",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
-      "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@eslint-community/eslint-utils": "^4.8.0",
-        "@eslint-community/regexpp": "^4.12.1",
-        "@eslint/config-array": "^0.21.1",
-        "@eslint/config-helpers": "^0.4.2",
-        "@eslint/core": "^0.17.0",
-        "@eslint/eslintrc": "^3.3.1",
-        "@eslint/js": "9.39.2",
-        "@eslint/plugin-kit": "^0.4.1",
-        "@humanfs/node": "^0.16.6",
-        "@humanwhocodes/module-importer": "^1.0.1",
-        "@humanwhocodes/retry": "^0.4.2",
-        "@types/estree": "^1.0.6",
-        "ajv": "^6.12.4",
-        "chalk": "^4.0.0",
-        "cross-spawn": "^7.0.6",
-        "debug": "^4.3.2",
-        "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^8.4.0",
-        "eslint-visitor-keys": "^4.2.1",
-        "espree": "^10.4.0",
-        "esquery": "^1.5.0",
-        "esutils": "^2.0.2",
-        "fast-deep-equal": "^3.1.3",
-        "file-entry-cache": "^8.0.0",
-        "find-up": "^5.0.0",
-        "glob-parent": "^6.0.2",
-        "ignore": "^5.2.0",
-        "imurmurhash": "^0.1.4",
-        "is-glob": "^4.0.0",
-        "json-stable-stringify-without-jsonify": "^1.0.1",
-        "lodash.merge": "^4.6.2",
-        "minimatch": "^3.1.2",
-        "natural-compare": "^1.4.0",
-        "optionator": "^0.9.3"
-      },
-      "bin": {
-        "eslint": "bin/eslint.js"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://eslint.org/donate"
-      },
-      "peerDependencies": {
-        "jiti": "*"
-      },
-      "peerDependenciesMeta": {
-        "jiti": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/eslint-config-next": {
-      "version": "15.5.4",
-      "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.4.tgz",
-      "integrity": "sha512-BzgVVuT3kfJes8i2GHenC1SRJ+W3BTML11lAOYFOOPzrk2xp66jBOAGEFRw+3LkYCln5UzvFsLhojrshb5Zfaw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@next/eslint-plugin-next": "15.5.4",
-        "@rushstack/eslint-patch": "^1.10.3",
-        "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
-        "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
-        "eslint-import-resolver-node": "^0.3.6",
-        "eslint-import-resolver-typescript": "^3.5.2",
-        "eslint-plugin-import": "^2.31.0",
-        "eslint-plugin-jsx-a11y": "^6.10.0",
-        "eslint-plugin-react": "^7.37.0",
-        "eslint-plugin-react-hooks": "^5.0.0"
-      },
-      "peerDependencies": {
-        "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
-        "typescript": ">=3.3.1"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/eslint-import-resolver-node": {
-      "version": "0.3.9",
-      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
-      "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "debug": "^3.2.7",
-        "is-core-module": "^2.13.0",
-        "resolve": "^1.22.4"
-      }
-    },
-    "node_modules/eslint-import-resolver-node/node_modules/debug": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "ms": "^2.1.1"
-      }
-    },
-    "node_modules/eslint-import-resolver-typescript": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz",
-      "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "@nolyfill/is-core-module": "1.0.39",
-        "debug": "^4.4.0",
-        "get-tsconfig": "^4.10.0",
-        "is-bun-module": "^2.0.0",
-        "stable-hash": "^0.0.5",
-        "tinyglobby": "^0.2.13",
-        "unrs-resolver": "^1.6.2"
-      },
-      "engines": {
-        "node": "^14.18.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint-import-resolver-typescript"
-      },
-      "peerDependencies": {
-        "eslint": "*",
-        "eslint-plugin-import": "*",
-        "eslint-plugin-import-x": "*"
-      },
-      "peerDependenciesMeta": {
-        "eslint-plugin-import": {
-          "optional": true
-        },
-        "eslint-plugin-import-x": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/eslint-module-utils": {
-      "version": "2.12.1",
-      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
-      "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "debug": "^3.2.7"
-      },
-      "engines": {
-        "node": ">=4"
-      },
-      "peerDependenciesMeta": {
-        "eslint": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/eslint-module-utils/node_modules/debug": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "ms": "^2.1.1"
-      }
-    },
-    "node_modules/eslint-plugin-import": {
-      "version": "2.32.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
-      "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@rtsao/scc": "^1.1.0",
-        "array-includes": "^3.1.9",
-        "array.prototype.findlastindex": "^1.2.6",
-        "array.prototype.flat": "^1.3.3",
-        "array.prototype.flatmap": "^1.3.3",
-        "debug": "^3.2.7",
-        "doctrine": "^2.1.0",
-        "eslint-import-resolver-node": "^0.3.9",
-        "eslint-module-utils": "^2.12.1",
-        "hasown": "^2.0.2",
-        "is-core-module": "^2.16.1",
-        "is-glob": "^4.0.3",
-        "minimatch": "^3.1.2",
-        "object.fromentries": "^2.0.8",
-        "object.groupby": "^1.0.3",
-        "object.values": "^1.2.1",
-        "semver": "^6.3.1",
-        "string.prototype.trimend": "^1.0.9",
-        "tsconfig-paths": "^3.15.0"
-      },
-      "engines": {
-        "node": ">=4"
-      },
-      "peerDependencies": {
-        "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
-      }
-    },
-    "node_modules/eslint-plugin-import/node_modules/debug": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "ms": "^2.1.1"
-      }
-    },
-    "node_modules/eslint-plugin-import/node_modules/semver": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-      "dev": true,
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver.js"
-      }
-    },
-    "node_modules/eslint-plugin-jsx-a11y": {
-      "version": "6.10.2",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz",
-      "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "aria-query": "^5.3.2",
-        "array-includes": "^3.1.8",
-        "array.prototype.flatmap": "^1.3.2",
-        "ast-types-flow": "^0.0.8",
-        "axe-core": "^4.10.0",
-        "axobject-query": "^4.1.0",
-        "damerau-levenshtein": "^1.0.8",
-        "emoji-regex": "^9.2.2",
-        "hasown": "^2.0.2",
-        "jsx-ast-utils": "^3.3.5",
-        "language-tags": "^1.0.9",
-        "minimatch": "^3.1.2",
-        "object.fromentries": "^2.0.8",
-        "safe-regex-test": "^1.0.3",
-        "string.prototype.includes": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=4.0"
-      },
-      "peerDependencies": {
-        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
-      }
-    },
-    "node_modules/eslint-plugin-react": {
-      "version": "7.37.5",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
-      "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "array-includes": "^3.1.8",
-        "array.prototype.findlast": "^1.2.5",
-        "array.prototype.flatmap": "^1.3.3",
-        "array.prototype.tosorted": "^1.1.4",
-        "doctrine": "^2.1.0",
-        "es-iterator-helpers": "^1.2.1",
-        "estraverse": "^5.3.0",
-        "hasown": "^2.0.2",
-        "jsx-ast-utils": "^2.4.1 || ^3.0.0",
-        "minimatch": "^3.1.2",
-        "object.entries": "^1.1.9",
-        "object.fromentries": "^2.0.8",
-        "object.values": "^1.2.1",
-        "prop-types": "^15.8.1",
-        "resolve": "^2.0.0-next.5",
-        "semver": "^6.3.1",
-        "string.prototype.matchall": "^4.0.12",
-        "string.prototype.repeat": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      },
-      "peerDependencies": {
-        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
-      }
-    },
-    "node_modules/eslint-plugin-react-hooks": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
-      "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      },
-      "peerDependencies": {
-        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
-      }
-    },
-    "node_modules/eslint-plugin-react/node_modules/resolve": {
-      "version": "2.0.0-next.5",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
-      "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-core-module": "^2.13.0",
-        "path-parse": "^1.0.7",
-        "supports-preserve-symlinks-flag": "^1.0.0"
-      },
-      "bin": {
-        "resolve": "bin/resolve"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/eslint-plugin-react/node_modules/semver": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-      "dev": true,
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver.js"
-      }
-    },
-    "node_modules/eslint-scope": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
-      "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
-      "dev": true,
-      "license": "BSD-2-Clause",
-      "dependencies": {
-        "esrecurse": "^4.3.0",
-        "estraverse": "^5.2.0"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
-    "node_modules/eslint-visitor-keys": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
-      "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
-      "dev": true,
-      "license": "Apache-2.0",
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
-    "node_modules/espree": {
-      "version": "10.4.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
-      "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
-      "dev": true,
-      "license": "BSD-2-Clause",
-      "dependencies": {
-        "acorn": "^8.15.0",
-        "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^4.2.1"
-      },
-      "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      }
-    },
-    "node_modules/esquery": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
-      "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
-      "dev": true,
-      "license": "BSD-3-Clause",
-      "dependencies": {
-        "estraverse": "^5.1.0"
-      },
-      "engines": {
-        "node": ">=0.10"
-      }
-    },
-    "node_modules/esrecurse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
-      "dev": true,
-      "license": "BSD-2-Clause",
-      "dependencies": {
-        "estraverse": "^5.2.0"
-      },
-      "engines": {
-        "node": ">=4.0"
-      }
-    },
-    "node_modules/estraverse": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-      "dev": true,
-      "license": "BSD-2-Clause",
-      "engines": {
-        "node": ">=4.0"
-      }
-    },
-    "node_modules/esutils": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-      "dev": true,
-      "license": "BSD-2-Clause",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/fast-deep-equal": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/fast-glob": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
-      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@nodelib/fs.stat": "^2.0.2",
-        "@nodelib/fs.walk": "^1.2.3",
-        "glob-parent": "^5.1.2",
-        "merge2": "^1.3.0",
-        "micromatch": "^4.0.4"
-      },
-      "engines": {
-        "node": ">=8.6.0"
-      }
-    },
-    "node_modules/fast-glob/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/fast-json-stable-stringify": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/fast-png": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
-      "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/pako": "^2.0.3",
-        "iobuffer": "^5.3.2",
-        "pako": "^2.1.0"
-      }
-    },
-    "node_modules/fastq": {
-      "version": "1.20.1",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
-      "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "reusify": "^1.0.4"
-      }
-    },
-    "node_modules/fflate": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
-      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
-      "license": "MIT"
-    },
-    "node_modules/file-entry-cache": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
-      "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "flat-cache": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=16.0.0"
-      }
-    },
-    "node_modules/fill-range": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
-      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "to-regex-range": "^5.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/find-up": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "locate-path": "^6.0.0",
-        "path-exists": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/flat-cache": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
-      "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "flatted": "^3.2.9",
-        "keyv": "^4.5.4"
-      },
-      "engines": {
-        "node": ">=16"
-      }
-    },
-    "node_modules/flatted": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
-      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
-      "dev": true,
-      "license": "ISC"
-    },
-    "node_modules/for-each": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
-      "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-callable": "^1.2.7"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/fraction.js": {
-      "version": "5.3.4",
-      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
-      "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": "*"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/rawify"
-      }
-    },
-    "node_modules/function-bind": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
-      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "dev": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/function.prototype.name": {
-      "version": "1.1.8",
-      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
-      "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.3",
-        "define-properties": "^1.2.1",
-        "functions-have-names": "^1.2.3",
-        "hasown": "^2.0.2",
-        "is-callable": "^1.2.7"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/functions-have-names": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
-      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
-      "dev": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/generator-function": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
-      "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/get-intrinsic": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
-      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind-apply-helpers": "^1.0.2",
-        "es-define-property": "^1.0.1",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.1.1",
-        "function-bind": "^1.1.2",
-        "get-proto": "^1.0.1",
-        "gopd": "^1.2.0",
-        "has-symbols": "^1.1.0",
-        "hasown": "^2.0.2",
-        "math-intrinsics": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/get-proto": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
-      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "dunder-proto": "^1.0.1",
-        "es-object-atoms": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/get-symbol-description": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
-      "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "es-errors": "^1.3.0",
-        "get-intrinsic": "^1.2.6"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/get-tsconfig": {
-      "version": "4.13.0",
-      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
-      "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "resolve-pkg-maps": "^1.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
-      }
-    },
-    "node_modules/glob-parent": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "is-glob": "^4.0.3"
-      },
-      "engines": {
-        "node": ">=10.13.0"
-      }
-    },
-    "node_modules/globals": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
-      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/globalthis": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
-      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "define-properties": "^1.2.1",
-        "gopd": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/gopd": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
-      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/graceful-fs": {
-      "version": "4.2.11",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
-      "dev": true,
-      "license": "ISC"
-    },
-    "node_modules/has-bigints": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
-      "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/has-flag": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/has-property-descriptors": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
-      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-define-property": "^1.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/has-proto": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
-      "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "dunder-proto": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/has-symbols": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
-      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/has-tostringtag": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
-      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "has-symbols": "^1.0.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/hasown": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
-      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "function-bind": "^1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/html-parse-stringify": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
-      "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
-      "license": "MIT",
-      "dependencies": {
-        "void-elements": "3.1.0"
-      }
-    },
-    "node_modules/html2canvas": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
-      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "css-line-break": "^2.1.0",
-        "text-segmentation": "^1.0.3"
-      },
-      "engines": {
-        "node": ">=8.0.0"
-      }
-    },
-    "node_modules/i18next": {
-      "version": "25.8.0",
-      "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.0.tgz",
-      "integrity": "sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==",
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://locize.com"
-        },
-        {
-          "type": "individual",
-          "url": "https://locize.com/i18next.html"
-        },
-        {
-          "type": "individual",
-          "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
-        }
-      ],
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@babel/runtime": "^7.28.4"
-      },
-      "peerDependencies": {
-        "typescript": "^5"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/icu-minify": {
-      "version": "4.8.0",
-      "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.8.0.tgz",
-      "integrity": "sha512-CY90QvJwc5ghNW+2gepxz4RWogCnM0ynHEFWSDTfGmE4ZPCPDQfkU36AntjbLcwv1Js2AofIGkxNq/LVVpCCbQ==",
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://github.com/sponsors/amannn"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/icu-messageformat-parser": "^3.4.0"
-      }
-    },
-    "node_modules/ignore": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
-      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 4"
-      }
-    },
-    "node_modules/import-fresh": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
-      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "parent-module": "^1.0.0",
-        "resolve-from": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/imurmurhash": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.8.19"
-      }
-    },
-    "node_modules/internal-slot": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
-      "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "hasown": "^2.0.2",
-        "side-channel": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/intl-messageformat": {
-      "version": "11.1.1",
-      "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.1.1.tgz",
-      "integrity": "sha512-vnrF2f4vfsdaFY6tuLZfzGcx1GZFMFAq6c7QdK3HSXNcGXEIQncNgbeAcnpjAOszQzq3Jbol2SwgshIGY08WyA==",
-      "license": "BSD-3-Clause",
-      "dependencies": {
-        "@formatjs/ecma402-abstract": "3.1.0",
-        "@formatjs/fast-memoize": "3.1.0",
-        "@formatjs/icu-messageformat-parser": "3.5.0",
-        "tslib": "^2.8.1"
-      }
-    },
-    "node_modules/iobuffer": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
-      "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
-      "license": "MIT"
-    },
-    "node_modules/is-array-buffer": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
-      "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.3",
-        "get-intrinsic": "^1.2.6"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-async-function": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
-      "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "async-function": "^1.0.0",
-        "call-bound": "^1.0.3",
-        "get-proto": "^1.0.1",
-        "has-tostringtag": "^1.0.2",
-        "safe-regex-test": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-bigint": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
-      "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "has-bigints": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-boolean-object": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
-      "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "has-tostringtag": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-bun-module": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
-      "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "semver": "^7.7.1"
-      }
-    },
-    "node_modules/is-callable": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
-      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-core-module": {
-      "version": "2.16.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
-      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "hasown": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-data-view": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
-      "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "get-intrinsic": "^1.2.6",
-        "is-typed-array": "^1.1.13"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-date-object": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
-      "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "has-tostringtag": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/is-finalizationregistry": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
-      "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-generator-function": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
-      "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.4",
-        "generator-function": "^2.0.0",
-        "get-proto": "^1.0.1",
-        "has-tostringtag": "^1.0.2",
-        "safe-regex-test": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-glob": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-      "license": "MIT",
-      "dependencies": {
-        "is-extglob": "^2.1.1"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/is-map": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
-      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-negative-zero": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
-      "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-number": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.12.0"
-      }
-    },
-    "node_modules/is-number-object": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
-      "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "has-tostringtag": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-regex": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
-      "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "gopd": "^1.2.0",
-        "has-tostringtag": "^1.0.2",
-        "hasown": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-set": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
-      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-shared-array-buffer": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
-      "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-string": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
-      "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "has-tostringtag": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-symbol": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
-      "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "has-symbols": "^1.1.0",
-        "safe-regex-test": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-typed-array": {
-      "version": "1.1.15",
-      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
-      "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "which-typed-array": "^1.1.16"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-weakmap": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
-      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-weakref": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
-      "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/is-weakset": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
-      "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "get-intrinsic": "^1.2.6"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/isarray": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
-      "dev": true,
-      "license": "ISC"
-    },
-    "node_modules/iterator.prototype": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
-      "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "define-data-property": "^1.1.4",
-        "es-object-atoms": "^1.0.0",
-        "get-intrinsic": "^1.2.6",
-        "get-proto": "^1.0.0",
-        "has-symbols": "^1.1.0",
-        "set-function-name": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/jiti": {
-      "version": "2.6.1",
-      "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
-      "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
-      "dev": true,
-      "license": "MIT",
-      "bin": {
-        "jiti": "lib/jiti-cli.mjs"
-      }
-    },
-    "node_modules/js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/js-yaml": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
-      "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "argparse": "^2.0.1"
-      },
-      "bin": {
-        "js-yaml": "bin/js-yaml.js"
-      }
-    },
-    "node_modules/json-buffer": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/json-schema-traverse": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/json-stable-stringify-without-jsonify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/json5": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-      "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "minimist": "^1.2.0"
-      },
-      "bin": {
-        "json5": "lib/cli.js"
-      }
-    },
-    "node_modules/jspdf": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.1.0.tgz",
-      "integrity": "sha512-xd1d/XRkwqnsq6FP3zH1Q+Ejqn2ULIJeDZ+FTKpaabVpZREjsJKRJwuokTNgdqOU+fl55KgbvgZ1pRTSWCP2kQ==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "@babel/runtime": "^7.28.4",
-        "fast-png": "^6.2.0",
-        "fflate": "^0.8.1"
-      },
-      "optionalDependencies": {
-        "canvg": "^3.0.11",
-        "core-js": "^3.6.0",
-        "dompurify": "^3.3.1",
-        "html2canvas": "^1.0.0-rc.5"
-      }
-    },
-    "node_modules/jspdf-autotable": {
-      "version": "5.0.7",
-      "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-5.0.7.tgz",
-      "integrity": "sha512-2wr7H6liNDBYNwt25hMQwXkEWFOEopgKIvR1Eukuw6Zmprm/ZcnmLTQEjW7Xx3FCbD3v7pflLcnMAv/h1jFDQw==",
-      "license": "MIT",
-      "peerDependencies": {
-        "jspdf": "^2 || ^3 || ^4"
-      }
-    },
-    "node_modules/jsx-ast-utils": {
-      "version": "3.3.5",
-      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
-      "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "array-includes": "^3.1.6",
-        "array.prototype.flat": "^1.3.1",
-        "object.assign": "^4.1.4",
-        "object.values": "^1.1.6"
-      },
-      "engines": {
-        "node": ">=4.0"
-      }
-    },
-    "node_modules/keyv": {
-      "version": "4.5.4",
-      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
-      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "json-buffer": "3.0.1"
-      }
-    },
-    "node_modules/language-subtag-registry": {
-      "version": "0.3.23",
-      "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
-      "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
-      "dev": true,
-      "license": "CC0-1.0"
-    },
-    "node_modules/language-tags": {
-      "version": "1.0.9",
-      "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
-      "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "language-subtag-registry": "^0.3.20"
-      },
-      "engines": {
-        "node": ">=0.10"
-      }
-    },
-    "node_modules/levn": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "prelude-ls": "^1.2.1",
-        "type-check": "~0.4.0"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/lightningcss": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
-      "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
-      "dev": true,
-      "license": "MPL-2.0",
-      "dependencies": {
-        "detect-libc": "^2.0.3"
-      },
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      },
-      "optionalDependencies": {
-        "lightningcss-android-arm64": "1.30.2",
-        "lightningcss-darwin-arm64": "1.30.2",
-        "lightningcss-darwin-x64": "1.30.2",
-        "lightningcss-freebsd-x64": "1.30.2",
-        "lightningcss-linux-arm-gnueabihf": "1.30.2",
-        "lightningcss-linux-arm64-gnu": "1.30.2",
-        "lightningcss-linux-arm64-musl": "1.30.2",
-        "lightningcss-linux-x64-gnu": "1.30.2",
-        "lightningcss-linux-x64-musl": "1.30.2",
-        "lightningcss-win32-arm64-msvc": "1.30.2",
-        "lightningcss-win32-x64-msvc": "1.30.2"
-      }
-    },
-    "node_modules/lightningcss-android-arm64": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
-      "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-darwin-arm64": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
-      "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-darwin-x64": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
-      "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-freebsd-x64": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
-      "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-arm-gnueabihf": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
-      "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-arm64-gnu": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
-      "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-arm64-musl": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
-      "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-x64-gnu": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
-      "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-linux-x64-musl": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
-      "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-win32-arm64-msvc": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
-      "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/lightningcss-win32-x64-msvc": {
-      "version": "1.30.2",
-      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
-      "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MPL-2.0",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/parcel"
-      }
-    },
-    "node_modules/locate-path": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "p-locate": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/lodash.merge": {
-      "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "js-tokens": "^3.0.0 || ^4.0.0"
-      },
-      "bin": {
-        "loose-envify": "cli.js"
-      }
-    },
-    "node_modules/lucide-react": {
-      "version": "0.544.0",
-      "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz",
-      "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==",
-      "license": "ISC",
-      "peerDependencies": {
-        "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
-      }
-    },
-    "node_modules/magic-string": {
-      "version": "0.30.21",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
-      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.5.5"
-      }
-    },
-    "node_modules/math-intrinsics": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
-      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/merge2": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/micromatch": {
-      "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
-      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "braces": "^3.0.3",
-        "picomatch": "^2.3.1"
-      },
-      "engines": {
-        "node": ">=8.6"
-      }
-    },
-    "node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "brace-expansion": "^1.1.7"
-      },
-      "engines": {
-        "node": "*"
-      }
-    },
-    "node_modules/minimist": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-      "dev": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/ms": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/nanoid": {
-      "version": "3.3.11",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
-      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "bin": {
-        "nanoid": "bin/nanoid.cjs"
-      },
-      "engines": {
-        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
-      }
-    },
-    "node_modules/napi-postinstall": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
-      "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==",
-      "dev": true,
-      "license": "MIT",
-      "bin": {
-        "napi-postinstall": "lib/cli.js"
-      },
-      "engines": {
-        "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/napi-postinstall"
-      }
-    },
-    "node_modules/natural-compare": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/negotiator": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
-      "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
-    "node_modules/next": {
-      "version": "16.1.6",
-      "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
-      "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
-      "license": "MIT",
-      "dependencies": {
-        "@next/env": "16.1.6",
-        "@swc/helpers": "0.5.15",
-        "baseline-browser-mapping": "^2.8.3",
-        "caniuse-lite": "^1.0.30001579",
-        "postcss": "8.4.31",
-        "styled-jsx": "5.1.6"
-      },
-      "bin": {
-        "next": "dist/bin/next"
-      },
-      "engines": {
-        "node": ">=20.9.0"
-      },
-      "optionalDependencies": {
-        "@next/swc-darwin-arm64": "16.1.6",
-        "@next/swc-darwin-x64": "16.1.6",
-        "@next/swc-linux-arm64-gnu": "16.1.6",
-        "@next/swc-linux-arm64-musl": "16.1.6",
-        "@next/swc-linux-x64-gnu": "16.1.6",
-        "@next/swc-linux-x64-musl": "16.1.6",
-        "@next/swc-win32-arm64-msvc": "16.1.6",
-        "@next/swc-win32-x64-msvc": "16.1.6",
-        "sharp": "^0.34.4"
-      },
-      "peerDependencies": {
-        "@opentelemetry/api": "^1.1.0",
-        "@playwright/test": "^1.51.1",
-        "babel-plugin-react-compiler": "*",
-        "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
-        "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
-        "sass": "^1.3.0"
-      },
-      "peerDependenciesMeta": {
-        "@opentelemetry/api": {
-          "optional": true
-        },
-        "@playwright/test": {
-          "optional": true
-        },
-        "babel-plugin-react-compiler": {
-          "optional": true
-        },
-        "sass": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/next-intl": {
-      "version": "4.8.0",
-      "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.8.0.tgz",
-      "integrity": "sha512-HiKCfG0pQMJ2GhtkQur6C7mpMUBs6lc0+HAZTUDm/5Nwh3dSYi/uAcAl0SiQTd01GmDou6dobd2th4U802lxOg==",
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://github.com/sponsors/amannn"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/intl-localematcher": "^0.5.4",
-        "@parcel/watcher": "^2.4.1",
-        "@swc/core": "^1.15.2",
-        "icu-minify": "^4.8.0",
-        "negotiator": "^1.0.0",
-        "next-intl-swc-plugin-extractor": "^4.8.0",
-        "po-parser": "^2.1.1",
-        "use-intl": "^4.8.0"
-      },
-      "peerDependencies": {
-        "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0",
-        "typescript": "^5.0.0"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/next-intl-swc-plugin-extractor": {
-      "version": "4.8.0",
-      "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.8.0.tgz",
-      "integrity": "sha512-+uooJAaUUnctq/IZrKJrpoA8yB6/z5kDeraySZlT1+XaoU1i+Onaimo2y/vwlqSKPHVRdqx3aqhwRZPuh71LAw==",
-      "license": "MIT"
-    },
-    "node_modules/next-intl/node_modules/@swc/core": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.11.tgz",
-      "integrity": "sha512-iLmLTodbYxU39HhMPaMUooPwO/zqJWvsqkrXv1ZI38rMb048p6N7qtAtTp37sw9NzSrvH6oli8EdDygo09IZ/w==",
-      "hasInstallScript": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@swc/counter": "^0.1.3",
-        "@swc/types": "^0.1.25"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/swc"
-      },
-      "optionalDependencies": {
-        "@swc/core-darwin-arm64": "1.15.11",
-        "@swc/core-darwin-x64": "1.15.11",
-        "@swc/core-linux-arm-gnueabihf": "1.15.11",
-        "@swc/core-linux-arm64-gnu": "1.15.11",
-        "@swc/core-linux-arm64-musl": "1.15.11",
-        "@swc/core-linux-x64-gnu": "1.15.11",
-        "@swc/core-linux-x64-musl": "1.15.11",
-        "@swc/core-win32-arm64-msvc": "1.15.11",
-        "@swc/core-win32-ia32-msvc": "1.15.11",
-        "@swc/core-win32-x64-msvc": "1.15.11"
-      },
-      "peerDependencies": {
-        "@swc/helpers": ">=0.5.17"
-      },
-      "peerDependenciesMeta": {
-        "@swc/helpers": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/next-themes": {
-      "version": "0.4.6",
-      "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
-      "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
-      "license": "MIT",
-      "peerDependencies": {
-        "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
-        "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
-      }
-    },
-    "node_modules/next/node_modules/postcss": {
-      "version": "8.4.31",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
-      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "nanoid": "^3.3.6",
-        "picocolors": "^1.0.0",
-        "source-map-js": "^1.0.2"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/node-addon-api": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
-      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
-      "license": "MIT"
-    },
-    "node_modules/node-releases": {
-      "version": "2.0.27",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
-      "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/object-inspect": {
-      "version": "1.13.4",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
-      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/object-keys": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/object.assign": {
-      "version": "4.1.7",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
-      "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.3",
-        "define-properties": "^1.2.1",
-        "es-object-atoms": "^1.0.0",
-        "has-symbols": "^1.1.0",
-        "object-keys": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/object.entries": {
-      "version": "1.1.9",
-      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
-      "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.4",
-        "define-properties": "^1.2.1",
-        "es-object-atoms": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/object.fromentries": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
-      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.2",
-        "es-object-atoms": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/object.groupby": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
-      "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/object.values": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
-      "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.3",
-        "define-properties": "^1.2.1",
-        "es-object-atoms": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/optionator": {
-      "version": "0.9.4",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
-      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "deep-is": "^0.1.3",
-        "fast-levenshtein": "^2.0.6",
-        "levn": "^0.4.1",
-        "prelude-ls": "^1.2.1",
-        "type-check": "^0.4.0",
-        "word-wrap": "^1.2.5"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/own-keys": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
-      "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "get-intrinsic": "^1.2.6",
-        "object-keys": "^1.1.1",
-        "safe-push-apply": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/p-limit": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "yocto-queue": "^0.1.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/p-locate": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "p-limit": "^3.0.2"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/pako": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
-      "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
-      "license": "(MIT AND Zlib)"
-    },
-    "node_modules/parent-module": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "callsites": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/path-exists": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/path-key": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/path-parse": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/performance-now": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
-      "license": "MIT",
-      "optional": true
-    },
-    "node_modules/picocolors": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
-      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
-      "license": "ISC"
-    },
-    "node_modules/picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8.6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/po-parser": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz",
-      "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==",
-      "license": "MIT"
-    },
-    "node_modules/possible-typed-array-names": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
-      "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/postcss": {
-      "version": "8.5.6",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
-      "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/postcss/"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/postcss"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "nanoid": "^3.3.11",
-        "picocolors": "^1.1.1",
-        "source-map-js": "^1.2.1"
-      },
-      "engines": {
-        "node": "^10 || ^12 || >=14"
-      }
-    },
-    "node_modules/postcss-value-parser": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
-      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/prelude-ls": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/prop-types": {
-      "version": "15.8.1",
-      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
-      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "loose-envify": "^1.4.0",
-        "object-assign": "^4.1.1",
-        "react-is": "^16.13.1"
-      }
-    },
-    "node_modules/punycode": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/queue-microtask": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT"
-    },
-    "node_modules/raf": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
-      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "performance-now": "^2.1.0"
-      }
-    },
-    "node_modules/react": {
-      "version": "19.2.4",
-      "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
-      "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
-      "license": "MIT",
-      "peer": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/react-dom": {
-      "version": "19.2.4",
-      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
-      "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "scheduler": "^0.27.0"
-      },
-      "peerDependencies": {
-        "react": "^19.2.4"
-      }
-    },
-    "node_modules/react-i18next": {
-      "version": "16.5.4",
-      "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.4.tgz",
-      "integrity": "sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.28.4",
-        "html-parse-stringify": "^3.0.1",
-        "use-sync-external-store": "^1.6.0"
-      },
-      "peerDependencies": {
-        "i18next": ">= 25.6.2",
-        "react": ">= 16.8.0",
-        "typescript": "^5"
-      },
-      "peerDependenciesMeta": {
-        "react-dom": {
-          "optional": true
-        },
-        "react-native": {
-          "optional": true
-        },
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/react-is": {
-      "version": "16.13.1",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
-      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/reflect.getprototypeof": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
-      "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.9",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.0.0",
-        "get-intrinsic": "^1.2.7",
-        "get-proto": "^1.0.1",
-        "which-builtin-type": "^1.2.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/regenerator-runtime": {
-      "version": "0.13.11",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
-      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
-      "license": "MIT",
-      "optional": true
-    },
-    "node_modules/regexp.prototype.flags": {
-      "version": "1.5.4",
-      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
-      "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "define-properties": "^1.2.1",
-        "es-errors": "^1.3.0",
-        "get-proto": "^1.0.1",
-        "gopd": "^1.2.0",
-        "set-function-name": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/resolve": {
-      "version": "1.22.11",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
-      "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-core-module": "^2.16.1",
-        "path-parse": "^1.0.7",
-        "supports-preserve-symlinks-flag": "^1.0.0"
-      },
-      "bin": {
-        "resolve": "bin/resolve"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/resolve-from": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/resolve-pkg-maps": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
-      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
-      "dev": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
-      }
-    },
-    "node_modules/reusify": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
-      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "iojs": ">=1.0.0",
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/rgbcolor": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
-      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
-      "license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
-      "optional": true,
-      "engines": {
-        "node": ">= 0.8.15"
-      }
-    },
-    "node_modules/run-parallel": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
-      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "queue-microtask": "^1.2.2"
-      }
-    },
-    "node_modules/safe-array-concat": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
-      "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.2",
-        "get-intrinsic": "^1.2.6",
-        "has-symbols": "^1.1.0",
-        "isarray": "^2.0.5"
-      },
-      "engines": {
-        "node": ">=0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/safe-push-apply": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
-      "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "isarray": "^2.0.5"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/safe-regex-test": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
-      "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "es-errors": "^1.3.0",
-        "is-regex": "^1.2.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/scheduler": {
-      "version": "0.27.0",
-      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
-      "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
-      "license": "MIT"
-    },
-    "node_modules/semver": {
-      "version": "7.7.3",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
-      "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
-      "devOptional": true,
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/set-function-length": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
-      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "define-data-property": "^1.1.4",
-        "es-errors": "^1.3.0",
-        "function-bind": "^1.1.2",
-        "get-intrinsic": "^1.2.4",
-        "gopd": "^1.0.1",
-        "has-property-descriptors": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/set-function-name": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
-      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "define-data-property": "^1.1.4",
-        "es-errors": "^1.3.0",
-        "functions-have-names": "^1.2.3",
-        "has-property-descriptors": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/set-proto": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
-      "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "dunder-proto": "^1.0.1",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/sharp": {
-      "version": "0.34.5",
-      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
-      "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
-      "hasInstallScript": true,
-      "license": "Apache-2.0",
-      "optional": true,
-      "dependencies": {
-        "@img/colour": "^1.0.0",
-        "detect-libc": "^2.1.2",
-        "semver": "^7.7.3"
-      },
-      "engines": {
-        "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/libvips"
-      },
-      "optionalDependencies": {
-        "@img/sharp-darwin-arm64": "0.34.5",
-        "@img/sharp-darwin-x64": "0.34.5",
-        "@img/sharp-libvips-darwin-arm64": "1.2.4",
-        "@img/sharp-libvips-darwin-x64": "1.2.4",
-        "@img/sharp-libvips-linux-arm": "1.2.4",
-        "@img/sharp-libvips-linux-arm64": "1.2.4",
-        "@img/sharp-libvips-linux-ppc64": "1.2.4",
-        "@img/sharp-libvips-linux-riscv64": "1.2.4",
-        "@img/sharp-libvips-linux-s390x": "1.2.4",
-        "@img/sharp-libvips-linux-x64": "1.2.4",
-        "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
-        "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
-        "@img/sharp-linux-arm": "0.34.5",
-        "@img/sharp-linux-arm64": "0.34.5",
-        "@img/sharp-linux-ppc64": "0.34.5",
-        "@img/sharp-linux-riscv64": "0.34.5",
-        "@img/sharp-linux-s390x": "0.34.5",
-        "@img/sharp-linux-x64": "0.34.5",
-        "@img/sharp-linuxmusl-arm64": "0.34.5",
-        "@img/sharp-linuxmusl-x64": "0.34.5",
-        "@img/sharp-wasm32": "0.34.5",
-        "@img/sharp-win32-arm64": "0.34.5",
-        "@img/sharp-win32-ia32": "0.34.5",
-        "@img/sharp-win32-x64": "0.34.5"
-      }
-    },
-    "node_modules/shebang-command": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "shebang-regex": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/shebang-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/side-channel": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
-      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "object-inspect": "^1.13.3",
-        "side-channel-list": "^1.0.0",
-        "side-channel-map": "^1.0.1",
-        "side-channel-weakmap": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/side-channel-list": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
-      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "object-inspect": "^1.13.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/side-channel-map": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
-      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "es-errors": "^1.3.0",
-        "get-intrinsic": "^1.2.5",
-        "object-inspect": "^1.13.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/side-channel-weakmap": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
-      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "es-errors": "^1.3.0",
-        "get-intrinsic": "^1.2.5",
-        "object-inspect": "^1.13.3",
-        "side-channel-map": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/source-map-js": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
-      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
-      "license": "BSD-3-Clause",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/stable-hash": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
-      "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/stackblur-canvas": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
-      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">=0.1.14"
-      }
-    },
-    "node_modules/stop-iteration-iterator": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
-      "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "es-errors": "^1.3.0",
-        "internal-slot": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/string.prototype.includes": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
-      "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/string.prototype.matchall": {
-      "version": "4.0.12",
-      "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
-      "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.3",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.6",
-        "es-errors": "^1.3.0",
-        "es-object-atoms": "^1.0.0",
-        "get-intrinsic": "^1.2.6",
-        "gopd": "^1.2.0",
-        "has-symbols": "^1.1.0",
-        "internal-slot": "^1.1.0",
-        "regexp.prototype.flags": "^1.5.3",
-        "set-function-name": "^2.0.2",
-        "side-channel": "^1.1.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/string.prototype.repeat": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
-      "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.5"
-      }
-    },
-    "node_modules/string.prototype.trim": {
-      "version": "1.2.10",
-      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
-      "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.2",
-        "define-data-property": "^1.1.4",
-        "define-properties": "^1.2.1",
-        "es-abstract": "^1.23.5",
-        "es-object-atoms": "^1.0.0",
-        "has-property-descriptors": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/string.prototype.trimend": {
-      "version": "1.0.9",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
-      "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.2",
-        "define-properties": "^1.2.1",
-        "es-object-atoms": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/string.prototype.trimstart": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
-      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "define-properties": "^1.2.1",
-        "es-object-atoms": "^1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/strip-bom": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/strip-json-comments": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/styled-jsx": {
-      "version": "5.1.6",
-      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
-      "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
-      "license": "MIT",
-      "dependencies": {
-        "client-only": "0.0.1"
-      },
-      "engines": {
-        "node": ">= 12.0.0"
-      },
-      "peerDependencies": {
-        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
-      },
-      "peerDependenciesMeta": {
-        "@babel/core": {
-          "optional": true
-        },
-        "babel-plugin-macros": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/supports-color": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "has-flag": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/supports-preserve-symlinks-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/svg-pathdata": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
-      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
-      "license": "MIT",
-      "optional": true,
-      "engines": {
-        "node": ">=12.0.0"
-      }
-    },
-    "node_modules/tailwind-merge": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
-      "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
-      "license": "MIT",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/dcastil"
-      }
-    },
-    "node_modules/tailwindcss": {
-      "version": "4.1.18",
-      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
-      "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/tapable": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
-      "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/webpack"
-      }
-    },
-    "node_modules/text-segmentation": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
-      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "utrie": "^1.0.2"
-      }
-    },
-    "node_modules/tinyglobby": {
-      "version": "0.2.15",
-      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
-      "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "fdir": "^6.5.0",
-        "picomatch": "^4.0.3"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/SuperchupuDev"
-      }
-    },
-    "node_modules/tinyglobby/node_modules/fdir": {
-      "version": "6.5.0",
-      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
-      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=12.0.0"
-      },
-      "peerDependencies": {
-        "picomatch": "^3 || ^4"
-      },
-      "peerDependenciesMeta": {
-        "picomatch": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/tinyglobby/node_modules/picomatch": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
-      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
-      "dev": true,
-      "license": "MIT",
-      "peer": true,
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/to-regex-range": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-number": "^7.0.0"
-      },
-      "engines": {
-        "node": ">=8.0"
-      }
-    },
-    "node_modules/ts-api-utils": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
-      "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=18.12"
-      },
-      "peerDependencies": {
-        "typescript": ">=4.8.4"
-      }
-    },
-    "node_modules/tsconfig-paths": {
-      "version": "3.15.0",
-      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
-      "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@types/json5": "^0.0.29",
-        "json5": "^1.0.2",
-        "minimist": "^1.2.6",
-        "strip-bom": "^3.0.0"
-      }
-    },
-    "node_modules/tslib": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
-      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
-      "license": "0BSD"
-    },
-    "node_modules/tw-animate-css": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
-      "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
-      "dev": true,
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/Wombosvideo"
-      }
-    },
-    "node_modules/type-check": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "prelude-ls": "^1.2.1"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/typed-array-buffer": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
-      "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "es-errors": "^1.3.0",
-        "is-typed-array": "^1.1.14"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/typed-array-byte-length": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
-      "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.8",
-        "for-each": "^0.3.3",
-        "gopd": "^1.2.0",
-        "has-proto": "^1.2.0",
-        "is-typed-array": "^1.1.14"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/typed-array-byte-offset": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
-      "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "available-typed-arrays": "^1.0.7",
-        "call-bind": "^1.0.8",
-        "for-each": "^0.3.3",
-        "gopd": "^1.2.0",
-        "has-proto": "^1.2.0",
-        "is-typed-array": "^1.1.15",
-        "reflect.getprototypeof": "^1.0.9"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/typed-array-length": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
-      "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bind": "^1.0.7",
-        "for-each": "^0.3.3",
-        "gopd": "^1.0.1",
-        "is-typed-array": "^1.1.13",
-        "possible-typed-array-names": "^1.0.0",
-        "reflect.getprototypeof": "^1.0.6"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/typescript": {
-      "version": "5.9.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
-      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
-      "devOptional": true,
-      "license": "Apache-2.0",
-      "peer": true,
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/unbox-primitive": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
-      "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.3",
-        "has-bigints": "^1.0.2",
-        "has-symbols": "^1.1.0",
-        "which-boxed-primitive": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/undici-types": {
-      "version": "6.21.0",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
-      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/unrs-resolver": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
-      "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "dependencies": {
-        "napi-postinstall": "^0.3.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/unrs-resolver"
-      },
-      "optionalDependencies": {
-        "@unrs/resolver-binding-android-arm-eabi": "1.11.1",
-        "@unrs/resolver-binding-android-arm64": "1.11.1",
-        "@unrs/resolver-binding-darwin-arm64": "1.11.1",
-        "@unrs/resolver-binding-darwin-x64": "1.11.1",
-        "@unrs/resolver-binding-freebsd-x64": "1.11.1",
-        "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1",
-        "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1",
-        "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1",
-        "@unrs/resolver-binding-linux-arm64-musl": "1.11.1",
-        "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1",
-        "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1",
-        "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1",
-        "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1",
-        "@unrs/resolver-binding-linux-x64-gnu": "1.11.1",
-        "@unrs/resolver-binding-linux-x64-musl": "1.11.1",
-        "@unrs/resolver-binding-wasm32-wasi": "1.11.1",
-        "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1",
-        "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1",
-        "@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
-      }
-    },
-    "node_modules/update-browserslist-db": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
-      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/browserslist"
-        },
-        {
-          "type": "tidelift",
-          "url": "https://tidelift.com/funding/github/npm/browserslist"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/ai"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "escalade": "^3.2.0",
-        "picocolors": "^1.1.1"
-      },
-      "bin": {
-        "update-browserslist-db": "cli.js"
-      },
-      "peerDependencies": {
-        "browserslist": ">= 4.21.0"
-      }
-    },
-    "node_modules/uri-js": {
-      "version": "4.4.1",
-      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
-      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
-      "dev": true,
-      "license": "BSD-2-Clause",
-      "dependencies": {
-        "punycode": "^2.1.0"
-      }
-    },
-    "node_modules/use-intl": {
-      "version": "4.8.0",
-      "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.8.0.tgz",
-      "integrity": "sha512-IH56txyiaW26QQzneQf/0PWTa1Os3BMZvwbyDiS8cBjl6mm8dlhlKsgSU6TiSZjV6ZhMv763584jNBEyQV8vtQ==",
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://github.com/sponsors/amannn"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "@formatjs/fast-memoize": "^3.1.0",
-        "@schummar/icu-type-parser": "1.21.5",
-        "icu-minify": "^4.8.0",
-        "intl-messageformat": "^11.1.0"
-      },
-      "peerDependencies": {
-        "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0"
-      }
-    },
-    "node_modules/use-sync-external-store": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
-      "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
-      "license": "MIT",
-      "peerDependencies": {
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
-      }
-    },
-    "node_modules/utrie": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
-      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "base64-arraybuffer": "^1.0.2"
-      }
-    },
-    "node_modules/void-elements": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
-      "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/which": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "isexe": "^2.0.0"
-      },
-      "bin": {
-        "node-which": "bin/node-which"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/which-boxed-primitive": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
-      "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-bigint": "^1.1.0",
-        "is-boolean-object": "^1.2.1",
-        "is-number-object": "^1.1.1",
-        "is-string": "^1.1.1",
-        "is-symbol": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/which-builtin-type": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
-      "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "call-bound": "^1.0.2",
-        "function.prototype.name": "^1.1.6",
-        "has-tostringtag": "^1.0.2",
-        "is-async-function": "^2.0.0",
-        "is-date-object": "^1.1.0",
-        "is-finalizationregistry": "^1.1.0",
-        "is-generator-function": "^1.0.10",
-        "is-regex": "^1.2.1",
-        "is-weakref": "^1.0.2",
-        "isarray": "^2.0.5",
-        "which-boxed-primitive": "^1.1.0",
-        "which-collection": "^1.0.2",
-        "which-typed-array": "^1.1.16"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/which-collection": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
-      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "is-map": "^2.0.3",
-        "is-set": "^2.0.3",
-        "is-weakmap": "^2.0.2",
-        "is-weakset": "^2.0.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/which-typed-array": {
-      "version": "1.1.20",
-      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
-      "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "available-typed-arrays": "^1.0.7",
-        "call-bind": "^1.0.8",
-        "call-bound": "^1.0.4",
-        "for-each": "^0.3.5",
-        "get-proto": "^1.0.1",
-        "gopd": "^1.2.0",
-        "has-tostringtag": "^1.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/word-wrap": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
-      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/yocto-queue": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    }
-  }
-}
Index: ckage.json
===================================================================
--- package.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,45 +1,0 @@
-{
-  "name": "iknow-remaster",
-  "version": "0.1.0",
-  "private": true,
-  "scripts": {
-    "dev": "next dev",
-    "build": "next build",
-    "start": "next start",
-    "lint": "eslint"
-  },
-  "dependencies": {
-    "@fortawesome/fontawesome-svg-core": "^7.0.1",
-    "@fortawesome/free-brands-svg-icons": "^7.0.1",
-    "@fortawesome/free-regular-svg-icons": "^7.0.1",
-    "@fortawesome/free-solid-svg-icons": "^7.0.1",
-    "@fortawesome/react-fontawesome": "^3.0.2",
-    "class-variance-authority": "^0.7.1",
-    "clsx": "^2.1.1",
-    "i18next": "^25.8.0",
-    "jspdf": "^4.1.0",
-    "jspdf-autotable": "^5.0.7",
-    "lucide-react": "^0.544.0",
-    "next": "^16.1.6",
-    "next-intl": "^4.8.0",
-    "next-themes": "^0.4.6",
-    "react": "^19.2.4",
-    "react-dom": "^19.2.4",
-    "react-i18next": "^16.5.4",
-    "tailwind-merge": "^3.3.1"
-  },
-  "devDependencies": {
-    "@eslint/eslintrc": "^3",
-    "@tailwindcss/postcss": "^4",
-    "@types/node": "^20",
-    "@types/react": "^19",
-    "@types/react-dom": "^19",
-    "autoprefixer": "^10.4.21",
-    "eslint": "^9",
-    "eslint-config-next": "15.5.4",
-    "postcss": "^8.5.6",
-    "tailwindcss": "^4.1.13",
-    "tw-animate-css": "^1.4.0",
-    "typescript": "^5"
-  }
-}
Index: stcss.config.mjs
===================================================================
--- postcss.config.mjs	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,5 +1,0 @@
-const config = {
-  plugins: ["@tailwindcss/postcss"],
-};
-
-export default config;
Index: blic/file.svg
===================================================================
--- public/file.svg	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,1 +1,0 @@
-<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
Index: blic/globe.svg
===================================================================
--- public/globe.svg	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,1 +1,0 @@
-<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
Index: blic/next.svg
===================================================================
--- public/next.svg	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,1 +1,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
Index: blic/vercel.svg
===================================================================
--- public/vercel.svg	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,1 +1,0 @@
-<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
Index: blic/window.svg
===================================================================
--- public/window.svg	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,1 +1,0 @@
-<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
Index: render.yaml
===================================================================
--- render.yaml	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ render.yaml	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,18 @@
+services:
+  - type: web
+    name: iknow-api
+    env: docker
+    region: frankfurt
+    plan: free
+    dockerfilePath: ./Dockerfile
+    dockerContext: .
+    envVars:
+      - key: ASPNETCORE_ENVIRONMENT
+        value: Production
+      - key: AllowedOrigins__0
+        value: https://your-frontend-domain.com
+      - key: ConnectionStrings__DefaultConnection
+        sync: false
+      - key: Jwt__Key
+        generateValue: true
+        sync: false
Index: sql/data_load.sql
===================================================================
--- sql/data_load.sql	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ sql/data_load.sql	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,164 @@
+SET search_path TO project;
+
+TRUNCATE TABLE
+    professour_subjects,
+    dependency_subject,
+    major_subjects,
+    payment,
+    token,
+    user_documents,
+    documents,
+    passed_subjects,
+    semesters_subjects,
+    enrolled_semesters,
+    subjects,
+    active_semesters,
+    major,
+    contact,
+    high_school,
+    users
+RESTART IDENTITY CASCADE;
+
+INSERT INTO users (id, name, embg, surname, "index", bday, email, password, role, quota, enrollment_year) VALUES
+(1, 'Stefan',  '0101999450001', 'Saveski',     '233149', '1999-01-01', 'stefan.saveski@students.finki.ukim.mk',    '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'student', 'drzavna',  2023),
+(2, 'Boris',   '0202999450002', 'Gjorgjievski','233188', '1999-02-02', 'boris.gjorgjievski@students.finki.ukim.mk','$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'student', 'privatna', 2023),
+(3, 'Ana',     '0303000450003', 'Petrova',     '233200', '2000-03-03', 'ana.petrova@students.finki.ukim.mk',       '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'student', 'drzavna',  2023);
+
+INSERT INTO users (id, name, embg, surname, "index", bday, email, password, role, quota, enrollment_year) VALUES
+(4, 'Vangel',  '0404198045004', 'Ajanovski',   NULL,     '1980-04-04', 'vangel.ajanovski@finki.ukim.mk',           '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'prof',    NULL, NULL),
+(5, 'Marija',  '0505198545005', 'Ilievska',    NULL,     '1985-05-05', 'marija.ilievska@finki.ukim.mk',            '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'prof',    NULL, NULL);
+
+INSERT INTO users (id, name, embg, surname, "index", bday, email, password, role, quota, enrollment_year) VALUES
+(6, 'Igor',    '0606197545006', 'Adminovski',  NULL,     '1975-06-06', 'igor.adminovski@finki.ukim.mk',            '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'admin',   NULL, NULL);
+
+INSERT INTO users (id, name, embg, surname, "index", bday, email, password, role, quota, enrollment_year) VALUES
+(7, 'Riste',   '0707197845007', 'Stojanov',    NULL,     '1978-07-07', 'riste.stojanov@finki.ukim.mk',             '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'prof',    NULL, NULL),
+(8, 'Katerina','0808198245008', 'Zdravkova',   NULL,     '1982-08-08', 'katerina.zdravkova@finki.ukim.mk',         '$2a$11$S9QIoRlV/rmkif7CKBjryuHwfLo1wTsXckX9oTduqrdyNWInCqR0S', 'prof',    NULL, NULL);
+
+INSERT INTO high_school (id, user_id, gpa, type) VALUES
+(1, 1, 4.85, 'gimnazija'),
+(2, 2, 4.60, 'strucen'),
+(3, 3, 4.95, 'gimnazija');
+
+INSERT INTO contact (id, user_id, city, municipality, address, number, microsoft_email) VALUES
+(1, 1, 'Skopje', 'Centar', 'Bul. Partizanski Odredi 15', '070111111', 'stefan.saveski@live.finki.ukim.mk'),
+(2, 2, 'Skopje', 'Karpos', 'Ul. Ivan Milutinovic 22',    '071222222', 'boris.gjorgjievski@live.finki.ukim.mk'),
+(3, 3, 'Tetovo', 'Tetovo', 'Ul. Ilindenska 5',           '072333333', NULL);
+
+INSERT INTO major (id, name) VALUES
+(1, 'Software Engineering and Information Systems'),
+(2, 'Computer Science and Engineering');
+
+INSERT INTO active_semesters (id, year, type) VALUES
+(1, 2024, 'winter'),
+(2, 2025, 'summer'),
+(3, 2025, 'winter'),
+(4, 2026, 'summer'),
+(5, 2026, 'winter');
+
+INSERT INTO subjects (id, name, code, awarded_credits, dependency_credit) VALUES
+(1,  'Structured Programming',         'F18L1S001', 6, 0),
+(2,  'Object Oriented Programming',    'F18L1S002', 6, 6),
+(3,  'Databases',                      'F18L2S010', 6, 6),
+(4,  'Operating Systems',              'F18L2S011', 6, 0),
+(5,  'Web Programming',                'F18L3S020', 6, 12),
+(6,  'Algorithms and Data Structures', 'F18L2S012', 6, 6),
+(7,  'Computer Networks',              'F18L2S013', 6, 6),
+(8,  'Software Engineering',           'F18L3S021', 6, 12),
+(9,  'Discrete Mathematics',           'F18L1S003', 6, 0),
+(10, 'Calculus',                       'F18L1S004', 6, 0),
+(11, 'Linear Algebra',                 'F18L1S005', 6, 0),
+(12, 'Computer Architecture',          'F18L1S006', 6, 0),
+(13, 'Artificial Intelligence',        'F18L3S022', 6, 12),
+(14, 'Machine Learning',               'F18L4S030', 6, 18),
+(15, 'Information Security',           'F18L3S023', 6, 12),
+(16, 'Mobile Platforms',               'F18L3S024', 6, 12),
+(17, 'Distributed Systems',            'F18L4S031', 6, 18),
+(18, 'Human-Computer Interaction',     'F18L2S014', 6, 6),
+(19, 'Probability and Statistics',     'F18L2S015', 6, 6),
+(20, 'Compiler Design',                'F18L4S032', 6, 18);
+
+INSERT INTO enrolled_semesters (id, user_id, quota, major_id, note, student_comment, last_change, completed, semester_id) VALUES
+(1, 1, 'drzavna',  1, NULL, 'prva godina',  '2024-10-01 10:00:00', '2025-02-01 12:00:00', 1),
+(2, 1, 'drzavna',  1, NULL, NULL,           '2025-03-01 10:00:00', NULL,                  2),
+(3, 2, 'privatna', 1, NULL, NULL,           '2024-10-05 09:30:00', '2025-02-03 11:00:00', 1),
+(4, 3, 'drzavna',  2, NULL, NULL,           '2024-10-02 08:15:00', NULL,                  1);
+
+INSERT INTO semesters_subjects (id, enrolled_semesters_id, subjects_id, professor_id, signature) VALUES
+(1, 1, 1, 4, TRUE),
+(2, 1, 4, 5, TRUE),
+(3, 2, 2, 4, FALSE),
+(4, 3, 1, 4, TRUE),
+(5, 4, 1, 4, TRUE),
+(6, 4, 3, 5, FALSE);
+
+INSERT INTO passed_subjects (id, enrolled_id, grade, date_passed) VALUES
+(1, 1, '10', '2025-01-25 14:00:00'),
+(2, 2, '8',  '2025-01-30 11:30:00'),
+(3, 4, '9',  '2025-01-28 09:45:00'),
+(4, 5, '7',  '2025-01-29 13:15:00');
+
+INSERT INTO documents (id, type, body, cost) VALUES
+(1, 'Uverenie za polozeni ispiti', 'Sodrzina na uverenie za polozeni ispiti...', 100),
+(2, 'Potvrda za redoven student',  'Sodrzina na potvrda za redoven student...', 50),
+(3, 'Diploma',                     'Sodrzina na diploma...',                     500);
+
+INSERT INTO user_documents (user_id, document_id) VALUES
+(1, 1),
+(1, 2),
+(2, 2),
+(3, 1);
+
+INSERT INTO token (id, user_id, token, expires_at, is_valid) VALUES
+(1, 1, 'tok_abc123_stefan', '2026-08-01 00:00:00', TRUE),
+(2, 2, 'tok_def456_boris',  '2026-08-01 00:00:00', TRUE),
+(3, 1, 'tok_old789_stefan', '2026-01-01 00:00:00', FALSE);
+
+INSERT INTO payment (id, user_id, enrollment_id, amount) VALUES
+(1, 1, 1, 200),
+(2, 1, 2, 200),
+(3, 2, 3, 400),
+(4, 3, 4, 200);
+
+INSERT INTO major_subjects (major_id, subject_id, mandatory_semester) VALUES
+(1, 1, 1), (1, 9, 1), (1, 10, 1), (1, 11, 1), (1, 12, 1),
+(1, 2, 2), (1, 6, 2), (1, 18, 2), (1, 19, 2),
+(1, 3, 3), (1, 4, 3), (1, 7, 3),
+(1, 5, 4), (1, 8, 4), (1, 13, 4), (1, 15, 4), (1, 16, 4),
+(1, 14, 5), (1, 17, 5),
+(2, 1, 1), (2, 9, 1), (2, 10, 1), (2, 11, 1), (2, 12, 1),
+(2, 2, 2), (2, 6, 2), (2, 19, 2),
+(2, 3, 3), (2, 4, 3), (2, 7, 3), (2, 18, 3),
+(2, 5, 4), (2, 13, 4), (2, 15, 4),
+(2, 14, 5), (2, 17, 5), (2, 20, 5);
+
+INSERT INTO dependency_subject (subject_id, dependency_id) VALUES
+(2, 1),
+(5, 2),
+(3, 1);
+
+INSERT INTO professour_subjects (prof_id, active_semester_id, subject_id)
+SELECT teacher.id, sem.id, subj.id
+FROM subjects subj
+CROSS JOIN active_semesters sem
+CROSS JOIN LATERAL (
+    SELECT u.id
+    FROM users u
+    WHERE u.role = 'prof'
+    ORDER BY u.id
+    OFFSET subj.id % (SELECT count(*) FROM users WHERE role = 'prof')
+    LIMIT 1
+) AS teacher;
+
+SELECT setval(pg_get_serial_sequence('users',              'id'), (SELECT max(id) FROM users));
+SELECT setval(pg_get_serial_sequence('high_school',        'id'), (SELECT max(id) FROM high_school));
+SELECT setval(pg_get_serial_sequence('contact',            'id'), (SELECT max(id) FROM contact));
+SELECT setval(pg_get_serial_sequence('major',              'id'), (SELECT max(id) FROM major));
+SELECT setval(pg_get_serial_sequence('active_semesters',   'id'), (SELECT max(id) FROM active_semesters));
+SELECT setval(pg_get_serial_sequence('subjects',           'id'), (SELECT max(id) FROM subjects));
+SELECT setval(pg_get_serial_sequence('enrolled_semesters', 'id'), (SELECT max(id) FROM enrolled_semesters));
+SELECT setval(pg_get_serial_sequence('semesters_subjects', 'id'), (SELECT max(id) FROM semesters_subjects));
+SELECT setval(pg_get_serial_sequence('passed_subjects',    'id'), (SELECT max(id) FROM passed_subjects));
+SELECT setval(pg_get_serial_sequence('documents',          'id'), (SELECT max(id) FROM documents));
+SELECT setval(pg_get_serial_sequence('token',              'id'), (SELECT max(id) FROM token));
+SELECT setval(pg_get_serial_sequence('payment',            'id'), (SELECT max(id) FROM payment));
Index: sql/iknow.dbml
===================================================================
--- sql/iknow.dbml	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ sql/iknow.dbml	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,207 @@
+// IKnow / FINKI - dbdiagram.io (DBML) source
+// Generated from schema_creation.sql, which is the source of truth.
+// Paste into https://dbdiagram.io to render the relational diagram.
+
+Enum project.user_role {
+  student
+  prof
+  admin
+}
+
+Enum project.hs_type {
+  strucen
+  gimnazija
+}
+
+Enum project.quota_type {
+  privatna
+  drzavna
+  stipendija
+}
+
+Enum project.semester_type {
+  summer
+  winter
+}
+
+Enum project.grade_type {
+  "6"
+  "7"
+  "8"
+  "9"
+  "10"
+}
+
+Table project.users {
+  id integer [pk, increment]
+  name varchar(100) [not null]
+  embg varchar(13)
+  surname varchar(100) [not null]
+  index varchar(20)
+  bday timestamp
+  email varchar(150) [not null, unique]
+  password varchar(255) [not null]
+  role project.user_role [not null]
+  quota project.quota_type
+  enrollment_year integer
+  created_at timestamp [not null, default: `now()`]
+}
+
+Table project.high_school {
+  id integer [pk, increment]
+  user_id integer [not null, unique]
+  gpa real [not null]
+  type project.hs_type [not null]
+}
+
+Table project.contact {
+  id integer [pk, increment]
+  user_id integer [not null, unique]
+  city varchar(100) [not null]
+  municipality varchar(100) [not null]
+  address varchar(150) [not null]
+  number varchar(20) [not null]
+  microsoft_email varchar(150)
+}
+
+Table project.major {
+  id integer [pk, increment]
+  name varchar(150) [not null]
+}
+
+Table project.active_semesters {
+  id integer [pk, increment]
+  year integer [not null]
+  type project.semester_type [not null]
+
+  indexes {
+    (year, type) [unique]
+  }
+}
+
+Table project.subjects {
+  id integer [pk, increment]
+  name varchar(150) [not null, unique]
+  code varchar(30) [not null, unique]
+  awarded_credits integer [not null]
+  dependency_credit integer
+}
+
+Table project.enrolled_semesters {
+  id integer [pk, increment]
+  user_id integer [not null]
+  quota project.quota_type [not null]
+  major_id integer [not null]
+  note varchar(255)
+  student_comment varchar(255)
+  created_at timestamp [not null, default: `now()`]
+  last_change timestamp
+  completed timestamp
+  semester_id integer [not null]
+
+  indexes {
+    (user_id, semester_id) [unique]
+  }
+}
+
+Table project.semesters_subjects {
+  id integer [pk, increment]
+  enrolled_semesters_id integer [not null]
+  subjects_id integer [not null]
+  professor_id integer [not null]
+  signature boolean [not null, default: false]
+
+  indexes {
+    (enrolled_semesters_id, subjects_id) [unique]
+  }
+}
+
+Table project.passed_subjects {
+  id integer [pk, increment]
+  enrolled_id integer [not null, unique]
+  grade project.grade_type [not null]
+  date_passed timestamp [not null]
+}
+
+Table project.documents {
+  id integer [pk, increment]
+  type varchar(100) [not null]
+  body text [not null]
+  cost integer [not null]
+}
+
+Table project.user_documents {
+  user_id integer [not null]
+  document_id integer [not null]
+
+  indexes {
+    (user_id, document_id) [pk]
+  }
+}
+
+Table project.token {
+  id integer [pk, increment]
+  user_id integer [not null]
+  token varchar(255) [not null]
+  expires_at timestamp [not null]
+  is_valid boolean [not null, default: true]
+}
+
+Table project.payment {
+  id integer [pk, increment]
+  user_id integer [not null]
+  enrollment_id integer [not null]
+  amount integer [not null]
+}
+
+Table project.major_subjects {
+  major_id integer [not null]
+  subject_id integer [not null]
+  mandatory_semester integer [not null]
+
+  indexes {
+    (major_id, subject_id) [pk]
+  }
+}
+
+Table project.dependency_subject {
+  subject_id integer [not null]
+  dependency_id integer [not null]
+
+  indexes {
+    (subject_id, dependency_id) [pk]
+  }
+}
+
+Table project.professour_subjects {
+  prof_id integer [not null]
+  active_semester_id integer [not null]
+  subject_id integer [not null]
+
+  indexes {
+    (prof_id, active_semester_id, subject_id) [pk]
+  }
+}
+
+// ---------- Relationships ----------
+Ref: project.high_school.user_id - project.users.id                  // has_hs (1:1)
+Ref: project.contact.user_id - project.users.id                      // has_contact (1:1)
+Ref: project.token.user_id > project.users.id                        // has_token
+Ref: project.payment.user_id > project.users.id                      // pays
+Ref: project.payment.enrollment_id > project.enrolled_semesters.id   // for_enrollment
+Ref: project.enrolled_semesters.user_id > project.users.id           // submits
+Ref: project.enrolled_semesters.major_id > project.major.id          // for_major
+Ref: project.enrolled_semesters.semester_id > project.active_semesters.id // during
+Ref: project.semesters_subjects.enrolled_semesters_id > project.enrolled_semesters.id // contains
+Ref: project.semesters_subjects.subjects_id > project.subjects.id    // taken_in
+Ref: project.semesters_subjects.professor_id > project.users.id      // teaches
+Ref: project.passed_subjects.enrolled_id - project.semesters_subjects.id // results_in (1:1)
+Ref: project.user_documents.user_id > project.users.id               // owns
+Ref: project.user_documents.document_id > project.documents.id       // owns
+Ref: project.major_subjects.major_id > project.major.id              // includes
+Ref: project.major_subjects.subject_id > project.subjects.id         // includes
+Ref: project.dependency_subject.subject_id > project.subjects.id     // requires (dependent)
+Ref: project.dependency_subject.dependency_id > project.subjects.id  // requires (prerequisite)
+Ref: project.professour_subjects.prof_id > project.users.id          // teaches_subject
+Ref: project.professour_subjects.active_semester_id > project.active_semesters.id // teaches_subject
+Ref: project.professour_subjects.subject_id > project.subjects.id    // teaches_subject
Index: sql/schema.md
===================================================================
--- sql/schema.md	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ sql/schema.md	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,185 @@
+# Schema diagram
+
+Generated from [`schema_creation.sql`](schema_creation.sql), which is the source of truth. If you change
+a table there, change it here too.
+
+Renders inline on GitHub and in the VS Code markdown preview (Ctrl+Shift+V) -
+no extension or tooling needed. Relationship labels use the names from the
+conceptual ER model.
+
+```mermaid
+erDiagram
+    users {
+        integer id PK
+        varchar name
+        varchar embg
+        varchar surname
+        varchar index
+        timestamp bday
+        varchar email UK
+        varchar password
+        user_role role
+        quota_type quota
+        integer enrollment_year
+        timestamp created_at
+    }
+
+    high_school {
+        integer id PK
+        integer user_id FK,UK
+        real gpa
+        hs_type type
+    }
+
+    contact {
+        integer id PK
+        integer user_id FK,UK
+        varchar city
+        varchar municipality
+        varchar address
+        varchar number
+        varchar microsoft_email
+    }
+
+    major {
+        integer id PK
+        varchar name
+    }
+
+    active_semesters {
+        integer id PK
+        integer year UK
+        semester_type type UK
+    }
+
+    subjects {
+        integer id PK
+        varchar name UK
+        varchar code UK
+        integer awarded_credits
+        integer dependency_credit
+    }
+
+    enrolled_semesters {
+        integer id PK
+        integer user_id FK,UK
+        quota_type quota
+        integer major_id FK
+        varchar note
+        varchar student_comment
+        timestamp created_at
+        timestamp last_change
+        timestamp completed
+        integer semester_id FK,UK
+    }
+
+    semesters_subjects {
+        integer id PK
+        integer enrolled_semesters_id FK,UK
+        integer subjects_id FK,UK
+        integer professor_id FK
+        boolean signature
+    }
+
+    passed_subjects {
+        integer id PK
+        integer enrolled_id FK,UK
+        grade_type grade
+        timestamp date_passed
+    }
+
+    documents {
+        integer id PK
+        varchar type
+        text body
+        integer cost
+    }
+
+    user_documents {
+        integer user_id PK,FK
+        integer document_id PK,FK
+    }
+
+    token {
+        integer id PK
+        integer user_id FK
+        varchar token
+        timestamp expires_at
+        boolean is_valid
+    }
+
+    payment {
+        integer id PK
+        integer user_id FK
+        integer enrollment_id FK
+        integer amount
+    }
+
+    major_subjects {
+        integer major_id PK,FK
+        integer subject_id PK,FK
+        integer mandatory_semester
+    }
+
+    dependency_subject {
+        integer subject_id PK,FK
+        integer dependency_id PK,FK
+    }
+
+    professour_subjects {
+        integer prof_id PK,FK
+        integer active_semester_id PK,FK
+        integer subject_id PK,FK
+    }
+
+    users               ||--o| high_school        : has_hs
+    users               ||--o| contact            : has_contact
+    users               ||--o{ token              : has_token
+    users               ||--o{ payment            : pays
+    users               ||--o{ enrolled_semesters : submits
+    users               ||--o{ user_documents     : owns
+    documents           ||--o{ user_documents     : owned_by
+    users               ||--o{ semesters_subjects : teaches
+    users               ||--o{ professour_subjects : teaches_subject
+
+    major               ||--o{ enrolled_semesters : for_major
+    active_semesters    ||--o{ enrolled_semesters : during
+    enrolled_semesters  ||--o{ semesters_subjects : contains
+    enrolled_semesters  ||--o{ payment            : for_enrollment
+
+    subjects            ||--o{ semesters_subjects : taken_in
+    semesters_subjects  ||--o| passed_subjects    : results_in
+
+    major               ||--o{ major_subjects     : includes
+    subjects            ||--o{ major_subjects     : included_in
+
+    subjects            ||--o{ dependency_subject : requires
+    subjects            ||--o{ dependency_subject : prerequisite_for
+
+    active_semesters    ||--o{ professour_subjects : taught_in
+    subjects            ||--o{ professour_subjects : taught_as
+```
+
+## Enum types
+
+| Type | Labels |
+|------|--------|
+| `user_role` | `student`, `prof`, `admin` |
+| `hs_type` | `strucen`, `gimnazija` |
+| `quota_type` | `privatna`, `drzavna`, `stipendija` |
+| `semester_type` | `summer`, `winter` |
+| `grade_type` | `6`, `7`, `8`, `9`, `10` |
+
+## Notes
+
+- `UK` on `enrolled_semesters.user_id` / `semester_id` is the composite
+  `UNIQUE (user_id, semester_id)` - one enrolment per student per semester.
+  Same for `semesters_subjects (enrolled_semesters_id, subjects_id)` and
+  `active_semesters (year, type)`.
+- `users` appears twice around `semesters_subjects`: once as the student, via
+  `enrolled_semesters.user_id`, and once as `professor_id`. The ER model links
+  the student through the enrolment, not directly.
+- `dependency_subject` is `subjects` related to itself: `subject_id` is the
+  dependent subject and `dependency_id` the prerequisite, with a `CHECK` that
+  they differ.
+- `professour_subjects` keeps the spelling used by the table in `schema_creation.sql`.
Index: sql/schema_creation.sql
===================================================================
--- sql/schema_creation.sql	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
+++ sql/schema_creation.sql	(revision b8093a091d45f33bab33deb8ff2fffc4734972c0)
@@ -0,0 +1,141 @@
+DROP SCHEMA IF EXISTS project CASCADE;
+CREATE SCHEMA project;
+
+SET search_path TO project;
+
+CREATE TYPE user_role     AS ENUM ('student', 'prof', 'admin');
+CREATE TYPE hs_type       AS ENUM ('strucen', 'gimnazija');
+CREATE TYPE quota_type    AS ENUM ('privatna', 'drzavna', 'stipendija');
+CREATE TYPE semester_type AS ENUM ('summer', 'winter');
+CREATE TYPE grade_type    AS ENUM ('6', '7', '8', '9', '10');
+
+CREATE TABLE users (
+    id               INTEGER      GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+    name             VARCHAR(100) NOT NULL,
+    embg             VARCHAR(13),
+    surname          VARCHAR(100) NOT NULL,
+    "index"          VARCHAR(20),
+    bday             TIMESTAMP,
+    email            VARCHAR(150) NOT NULL UNIQUE,
+    password         VARCHAR(255) NOT NULL,
+    role             user_role    NOT NULL,
+    quota            quota_type,
+    enrollment_year  INTEGER,
+    created_at       TIMESTAMP    NOT NULL DEFAULT now()
+);
+
+CREATE TABLE high_school (
+    id       INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    user_id  INTEGER NOT NULL UNIQUE REFERENCES users (id),
+    gpa      REAL    NOT NULL,
+    type     hs_type NOT NULL
+);
+
+CREATE TABLE contact (
+    id               INTEGER      PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    user_id          INTEGER      NOT NULL UNIQUE REFERENCES users (id),
+    city             VARCHAR(100) NOT NULL,
+    municipality     VARCHAR(100) NOT NULL,
+    address          VARCHAR(150) NOT NULL,
+    number           VARCHAR(20)  NOT NULL,
+    microsoft_email  VARCHAR(150)
+);
+
+CREATE TABLE major (
+    id    INTEGER      PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    name  VARCHAR(150) NOT NULL
+);
+
+CREATE TABLE active_semesters (
+    id     INTEGER       PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    year   INTEGER       NOT NULL,
+    type   semester_type NOT NULL,
+    UNIQUE (year, type)
+);
+
+CREATE TABLE subjects (
+    id                 INTEGER      PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    name               VARCHAR(150) NOT NULL UNIQUE,
+    code               VARCHAR(30)  NOT NULL UNIQUE,
+    awarded_credits    INTEGER      NOT NULL,
+    dependency_credit  INTEGER
+);
+
+CREATE TABLE enrolled_semesters (
+    id               INTEGER    PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    user_id          INTEGER    NOT NULL REFERENCES users (id),
+    quota            quota_type NOT NULL,
+    major_id         INTEGER    NOT NULL REFERENCES major (id),
+    note             VARCHAR(255),
+    student_comment  VARCHAR(255),
+    created_at       TIMESTAMP  NOT NULL DEFAULT now(),
+    last_change      TIMESTAMP,
+    completed        TIMESTAMP,
+    semester_id      INTEGER    NOT NULL REFERENCES active_semesters (id),
+    UNIQUE (user_id, semester_id)
+);
+
+CREATE TABLE semesters_subjects (
+    id                     INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    enrolled_semesters_id  INTEGER NOT NULL REFERENCES enrolled_semesters (id),
+    subjects_id            INTEGER NOT NULL REFERENCES subjects (id),
+    professor_id           INTEGER NOT NULL REFERENCES users (id),
+    signature              BOOLEAN NOT NULL DEFAULT FALSE,
+    UNIQUE (enrolled_semesters_id, subjects_id)
+);
+
+CREATE TABLE passed_subjects (
+    id           INTEGER    PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    enrolled_id  INTEGER    NOT NULL UNIQUE REFERENCES semesters_subjects (id),
+    grade        grade_type NOT NULL,
+    date_passed  TIMESTAMP  NOT NULL
+);
+
+CREATE TABLE documents (
+    id     INTEGER      PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    type   VARCHAR(100) NOT NULL,
+    body   TEXT         NOT NULL,
+    cost   INTEGER      NOT NULL
+);
+
+CREATE TABLE user_documents (
+    user_id      INTEGER NOT NULL REFERENCES users (id),
+    document_id  INTEGER NOT NULL REFERENCES documents (id),
+    PRIMARY KEY (user_id, document_id)
+);
+
+CREATE TABLE token (
+    id          INTEGER      PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    user_id     INTEGER      NOT NULL REFERENCES users (id),
+    token       VARCHAR(255) NOT NULL,
+    expires_at  TIMESTAMP    NOT NULL,
+    is_valid    BOOLEAN      NOT NULL DEFAULT TRUE
+);
+
+CREATE TABLE payment (
+    id             INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
+    user_id        INTEGER NOT NULL REFERENCES users (id),
+    enrollment_id  INTEGER NOT NULL REFERENCES enrolled_semesters (id),
+    amount         INTEGER NOT NULL
+);
+
+CREATE TABLE major_subjects (
+    major_id            INTEGER NOT NULL REFERENCES major (id),
+    subject_id          INTEGER NOT NULL REFERENCES subjects (id),
+    mandatory_semester  INTEGER NOT NULL,
+    PRIMARY KEY (major_id, subject_id)
+);
+
+CREATE TABLE dependency_subject (
+    subject_id     INTEGER NOT NULL REFERENCES subjects (id),
+    dependency_id  INTEGER NOT NULL REFERENCES subjects (id),
+    PRIMARY KEY (subject_id, dependency_id),
+    CHECK (subject_id <> dependency_id)
+);
+
+CREATE TABLE professour_subjects (
+    prof_id            INTEGER NOT NULL REFERENCES users (id),
+    active_semester_id INTEGER NOT NULL REFERENCES active_semesters (id),
+    subject_id         INTEGER NOT NULL REFERENCES subjects (id),
+    PRIMARY KEY (prof_id, active_semester_id, subject_id)
+);
Index: c/app/[locale]/layout.tsx
===================================================================
--- src/app/[locale]/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,5 +1,0 @@
-import React from 'react';
-
-export default function LocaleLayout({ children }: { children: React.ReactNode }) {
-	return <>{children}</>;
-}
Index: c/app/admin/layout.tsx
===================================================================
--- src/app/admin/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,27 +1,0 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
-import "../globals.css";
-import "@fortawesome/fontawesome-svg-core/styles.css";
-import { config } from "@fortawesome/fontawesome-svg-core";
-import Header from "@/components/header";
-import AdminNavbar from "@/components/admin-navbar";
-
-config.autoAddCss = false;
-
-const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
-const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
-
-export const metadata: Metadata = {
-  title: "IKnow - Admin Portal",
-  description: "Administration of subjects, semesters and teaching assignments",
-};
-
-export default function AdminLayout({ children }: Readonly<{ children: React.ReactNode }>) {
-  return (
-    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
-      <Header />
-      <AdminNavbar />
-      {children}
-    </div>
-  );
-}
Index: c/app/admin/page.tsx
===================================================================
--- src/app/admin/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,5 +1,0 @@
-import { redirect } from "next/navigation";
-
-export default function AdminIndex() {
-  redirect("/admin/subjects");
-}
Index: c/app/admin/schedule/page.tsx
===================================================================
--- src/app/admin/schedule/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,224 +1,0 @@
-"use client";
-
-import { useCallback, useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { adminGet, adminSend, type AdminSemester, type Schedule } from "@/lib/admin-api";
-
-export default function AdminSchedulePage() {
-  const { t } = useTranslation();
-
-  const [semesters, setSemesters] = useState<AdminSemester[]>([]);
-  const [semesterId, setSemesterId] = useState<number | null>(null);
-  const [schedule, setSchedule] = useState<Schedule | null>(null);
-
-  const [loading, setLoading] = useState(true);
-  const [busy, setBusy] = useState(false);
-  const [error, setError] = useState<string | null>(null);
-  const [notice, setNotice] = useState<string | null>(null);
-
-  const [subjectId, setSubjectId] = useState<number | "">("");
-  const [professorId, setProfessorId] = useState<number | "">("");
-
-  useEffect(() => {
-    (async () => {
-      try {
-        const list = await adminGet<AdminSemester[]>("/api/admin/semesters");
-        setSemesters(list);
-        setSemesterId(list[0]?.id ?? null);
-      } catch (e) {
-        setError(e instanceof Error ? e.message : String(e));
-      } finally {
-        setLoading(false);
-      }
-    })();
-  }, []);
-
-  const loadSchedule = useCallback(async (id: number) => {
-    setLoading(true);
-    setError(null);
-    try {
-      setSchedule(await adminGet<Schedule>(`/api/admin/schedule/${id}`));
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setLoading(false);
-    }
-  }, []);
-
-  useEffect(() => {
-    if (semesterId !== null) void loadSchedule(semesterId);
-  }, [semesterId, loadSchedule]);
-
-  async function run(action: () => Promise<{ message?: string }>) {
-    setBusy(true);
-    setError(null);
-    setNotice(null);
-    try {
-      const result = await action();
-      setNotice(result.message ?? null);
-      if (semesterId !== null) await loadSchedule(semesterId);
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setBusy(false);
-    }
-  }
-
-  return (
-    <div className="min-h-screen pb-8">
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <h1 className="text-3xl font-bold mb-2">{t("admin_schedule")}</h1>
-        <p className="text-lg opacity-90">{t("admin_schedule_intro")}</p>
-      </div>
-
-      {error && (
-        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>
-      )}
-      {notice && (
-        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">{notice}</div>
-      )}
-
-      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
-        <div className="flex flex-wrap items-end gap-4">
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("semester")}</span>
-            <select
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={semesterId ?? ""}
-              onChange={(e) => setSemesterId(Number(e.target.value))}
-            >
-              {semesters.map((s) => (
-                <option key={s.id} value={s.id}>{s.name}</option>
-              ))}
-            </select>
-          </label>
-
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("subject")}</span>
-            <select
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={subjectId}
-              onChange={(e) => setSubjectId(e.target.value === "" ? "" : Number(e.target.value))}
-            >
-              <option value="">{t("admin_pick_subject")}</option>
-              {schedule?.allSubjects.map((s) => (
-                <option key={s.id} value={s.id}>{s.code} — {s.name}</option>
-              ))}
-            </select>
-          </label>
-
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_professor")}</span>
-            <select
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={professorId}
-              onChange={(e) => setProfessorId(e.target.value === "" ? "" : Number(e.target.value))}
-            >
-              <option value="">{t("admin_pick_professor")}</option>
-              {schedule?.professors.map((p) => (
-                <option key={p.id} value={p.id}>{p.name}</option>
-              ))}
-            </select>
-          </label>
-
-          <button
-            className="rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
-            disabled={busy || subjectId === "" || professorId === "" || semesterId === null}
-            onClick={() =>
-              void run(() =>
-                adminSend("/api/admin/schedule", "POST", {
-                  ProfessorId: professorId,
-                  SemesterId: semesterId,
-                  SubjectId: subjectId,
-                }),
-              )
-            }
-          >
-            {t("admin_assign")}
-          </button>
-        </div>
-      </div>
-
-      {schedule && schedule.uncoveredSubjects.length > 0 && (
-        <div className="mb-6 rounded-lg border border-yellow-200 bg-yellow-50 px-4 py-3 text-sm text-yellow-900">
-          <strong>{t("admin_uncovered_count", { count: schedule.uncoveredSubjects.length })}</strong>
-          <span className="ml-2">{t("admin_uncovered_hint")}</span>
-          <div className="mt-2 font-mono text-xs">
-            {schedule.uncoveredSubjects.map((u) => u.code).join(", ")}
-          </div>
-        </div>
-      )}
-
-      <div className="grid gap-6 lg:grid-cols-3">
-        <div className="lg:col-span-2 bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-          <div className="bg-primary text-white px-6 py-4">
-            <h2 className="text-xl font-bold">
-              {t("admin_assignments")} {schedule ? `— ${schedule.semesterName}` : ""}
-            </h2>
-          </div>
-          <div className="overflow-x-auto">
-            <table className="w-full">
-              <thead className="bg-accent">
-                <tr>
-                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_code")}</th>
-                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("subject")}</th>
-                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_professor")}</th>
-                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
-                </tr>
-              </thead>
-              <tbody>
-                {loading ? (
-                  <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("loading")}</td></tr>
-                ) : !schedule || schedule.assignments.length === 0 ? (
-                  <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("admin_no_assignments")}</td></tr>
-                ) : (
-                  schedule.assignments.map((a) => (
-                    <tr key={`${a.subjectId}-${a.professorId}`} className="hover:bg-accent">
-                      <td className="px-4 py-3 border-b font-mono text-card-foreground">{a.subjectCode}</td>
-                      <td className="px-4 py-3 border-b text-card-foreground">{a.subjectName}</td>
-                      <td className="px-4 py-3 border-b text-card-foreground">{a.professorName}</td>
-                      <td className="px-4 py-3 border-b">
-                        <button
-                          className="rounded-lg bg-gray-800 px-3 py-1.5 text-sm text-white disabled:opacity-50"
-                          disabled={busy}
-                          onClick={() =>
-                            void run(() =>
-                              adminSend("/api/admin/schedule", "DELETE", {
-                                ProfessorId: a.professorId,
-                                SemesterId: schedule.semesterId,
-                                SubjectId: a.subjectId,
-                              }),
-                            )
-                          }
-                        >
-                          {t("admin_remove")}
-                        </button>
-                      </td>
-                    </tr>
-                  ))
-                )}
-              </tbody>
-            </table>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-          <div className="bg-primary text-white px-6 py-4">
-            <h2 className="text-xl font-bold">{t("admin_load")}</h2>
-          </div>
-          <ul className="divide-y divide-border">
-            {schedule?.load.map((l) => (
-              <li key={l.professorId} className="flex items-center justify-between px-4 py-3">
-                <span className="text-card-foreground">{l.professorName}</span>
-                <span className="rounded-full bg-accent px-2 py-0.5 text-sm text-muted-foreground">{l.subjects}</span>
-              </li>
-            ))}
-            {!schedule?.load.length && (
-              <li className="px-4 py-3 text-muted-foreground">{t("admin_no_professors")}</li>
-            )}
-          </ul>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/admin/semesters/page.tsx
===================================================================
--- src/app/admin/semesters/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,173 +1,0 @@
-"use client";
-
-import { useCallback, useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { adminGet, adminSend, type AdminSemester } from "@/lib/admin-api";
-
-export default function AdminSemestersPage() {
-  const { t } = useTranslation();
-
-  const [semesters, setSemesters] = useState<AdminSemester[]>([]);
-  const [loading, setLoading] = useState(true);
-  const [busy, setBusy] = useState(false);
-  const [error, setError] = useState<string | null>(null);
-  const [notice, setNotice] = useState<string | null>(null);
-
-  const [year, setYear] = useState(new Date().getFullYear());
-  const [type, setType] = useState<"winter" | "summer">("winter");
-  const [expandedId, setExpandedId] = useState<number | null>(null);
-
-  const refresh = useCallback(async () => {
-    setLoading(true);
-    setError(null);
-    try {
-      setSemesters(await adminGet<AdminSemester[]>("/api/admin/semesters"));
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setLoading(false);
-    }
-  }, []);
-
-  useEffect(() => {
-    void refresh();
-  }, [refresh]);
-
-  async function create() {
-    setBusy(true);
-    setError(null);
-    setNotice(null);
-    try {
-      const result = await adminSend("/api/admin/semesters", "POST", { Year: year, Type: type });
-      setNotice(result.message ?? null);
-      await refresh();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setBusy(false);
-    }
-  }
-
-  return (
-    <div className="min-h-screen pb-8">
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <h1 className="text-3xl font-bold mb-2">{t("admin_semesters")}</h1>
-        <p className="text-lg opacity-90">{t("admin_semesters_intro")}</p>
-      </div>
-
-      {error && (
-        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>
-      )}
-      {notice && (
-        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">{notice}</div>
-      )}
-
-      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
-        <h2 className="text-xl font-semibold mb-4 text-card-foreground">{t("admin_new_semester")}</h2>
-        <div className="flex flex-wrap items-end gap-4">
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_year")}</span>
-            <input
-              type="number"
-              min={2000}
-              max={2100}
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={year}
-              onChange={(e) => setYear(Number(e.target.value))}
-            />
-          </label>
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_type")}</span>
-            <select
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={type}
-              onChange={(e) => setType(e.target.value as "winter" | "summer")}
-            >
-              <option value="winter">{t("admin_winter")}</option>
-              <option value="summer">{t("admin_summer")}</option>
-            </select>
-          </label>
-          <button
-            disabled={busy}
-            className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
-            onClick={() => void create()}
-          >
-            {t("admin_open_semester")}
-          </button>
-        </div>
-      </div>
-
-      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-        <div className="bg-primary text-white px-6 py-4">
-          <h2 className="text-xl font-bold">{t("admin_open_semesters")}</h2>
-        </div>
-        <div className="overflow-x-auto">
-          <table className="w-full">
-            <thead className="bg-accent">
-              <tr>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("semester")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_enrolments")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_coverage")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
-              </tr>
-            </thead>
-            <tbody>
-              {loading ? (
-                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("loading")}</td></tr>
-              ) : semesters.length === 0 ? (
-                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("admin_no_semesters")}</td></tr>
-              ) : (
-                semesters.map((s) => {
-                  const uncovered = s.uncoveredSubjects.length;
-                  return (
-                    <>
-                      <tr key={s.id} className="hover:bg-accent">
-                        <td className="px-4 py-3 border-b text-card-foreground">{s.name}</td>
-                        <td className="px-4 py-3 border-b text-card-foreground">{s.enrolmentCount}</td>
-                        <td className="px-4 py-3 border-b">
-                          {uncovered === 0 ? (
-                            <span className="rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-800">
-                              {t("admin_fully_covered")}
-                            </span>
-                          ) : (
-                            <span className="rounded-full bg-yellow-100 px-2 py-0.5 text-xs text-yellow-900">
-                              {t("admin_uncovered_count", { count: uncovered })}
-                            </span>
-                          )}
-                        </td>
-                        <td className="px-4 py-3 border-b">
-                          {uncovered > 0 && (
-                            <button
-                              className="rounded-lg border border-border px-3 py-1.5 text-sm"
-                              onClick={() => setExpandedId(expandedId === s.id ? null : s.id)}
-                            >
-                              {expandedId === s.id ? t("admin_close") : t("admin_show_uncovered")}
-                            </button>
-                          )}
-                        </td>
-                      </tr>
-                      {expandedId === s.id && uncovered > 0 && (
-                        <tr key={`${s.id}-detail`}>
-                          <td colSpan={4} className="border-b bg-accent/40 px-4 py-4 text-sm">
-                            <p className="mb-2 text-muted-foreground">{t("admin_uncovered_hint")}</p>
-                            <ul className="grid gap-1 sm:grid-cols-2 lg:grid-cols-3">
-                              {s.uncoveredSubjects.map((u) => (
-                                <li key={u.id} className="text-card-foreground">
-                                  <span className="font-mono">{u.code}</span> — {u.name}
-                                </li>
-                              ))}
-                            </ul>
-                          </td>
-                        </tr>
-                      )}
-                    </>
-                  );
-                })
-              )}
-            </tbody>
-          </table>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/admin/subjects/page.tsx
===================================================================
--- src/app/admin/subjects/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,409 +1,0 @@
-"use client";
-
-import { useCallback, useEffect, useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import {
-  adminGet,
-  adminSend,
-  type AdminSubject,
-  type SubjectRef,
-} from "@/lib/admin-api";
-
-const EMPTY_FORM = { name: "", code: "", awardedCredits: 6, dependencyCredit: 0 };
-
-export default function AdminSubjectsPage() {
-  const { t } = useTranslation();
-
-  const [subjects, setSubjects] = useState<AdminSubject[]>([]);
-  const [majors, setMajors] = useState<SubjectRef[]>([]);
-  const [loading, setLoading] = useState(true);
-  const [busy, setBusy] = useState(false);
-  const [error, setError] = useState<string | null>(null);
-  const [notice, setNotice] = useState<string | null>(null);
-
-  const [form, setForm] = useState(EMPTY_FORM);
-  const [editingId, setEditingId] = useState<number | null>(null);
-  const [expandedId, setExpandedId] = useState<number | null>(null);
-  const [query, setQuery] = useState("");
-
-  const refresh = useCallback(async () => {
-    setLoading(true);
-    setError(null);
-    try {
-      const [s, m] = await Promise.all([
-        adminGet<AdminSubject[]>("/api/admin/subjects"),
-        adminGet<SubjectRef[]>("/api/admin/majors"),
-      ]);
-      setSubjects(s);
-      setMajors(m);
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setLoading(false);
-    }
-  }, []);
-
-  useEffect(() => {
-    void refresh();
-  }, [refresh]);
-
-  async function run(action: () => Promise<{ message?: string }>) {
-    setBusy(true);
-    setError(null);
-    setNotice(null);
-    try {
-      const result = await action();
-      setNotice(result.message ?? null);
-      await refresh();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setBusy(false);
-    }
-  }
-
-  const filtered = useMemo(() => {
-    const q = query.trim().toLowerCase();
-    if (!q) return subjects;
-    return subjects.filter(
-      (s) =>
-        (s.name ?? "").toLowerCase().includes(q) ||
-        (s.code ?? "").toLowerCase().includes(q),
-    );
-  }, [subjects, query]);
-
-  function startEdit(s: AdminSubject) {
-    setEditingId(s.id);
-    setForm({
-      name: s.name ?? "",
-      code: s.code ?? "",
-      awardedCredits: s.awardedCredits,
-      dependencyCredit: s.dependencyCredit ?? 0,
-    });
-    window.scrollTo({ top: 0, behavior: "smooth" });
-  }
-
-  function cancelEdit() {
-    setEditingId(null);
-    setForm(EMPTY_FORM);
-  }
-
-  return (
-    <div className="min-h-screen pb-8">
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <h1 className="text-3xl font-bold mb-2">{t("admin_subjects")}</h1>
-        <p className="text-lg opacity-90">{t("admin_subjects_intro")}</p>
-      </div>
-
-      {error && (
-        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
-          {error}
-        </div>
-      )}
-      {notice && (
-        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">
-          {notice}
-        </div>
-      )}
-
-      {/* create / edit */}
-      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
-        <h2 className="text-xl font-semibold mb-4 text-card-foreground">
-          {editingId === null ? t("admin_new_subject") : t("admin_edit_subject")}
-        </h2>
-        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_subject_name")}</span>
-            <input
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={form.name}
-              onChange={(e) => setForm({ ...form, name: e.target.value })}
-            />
-          </label>
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_subject_code")}</span>
-            <input
-              className="rounded-lg border border-border bg-background px-3 py-2 font-mono"
-              value={form.code}
-              onChange={(e) => setForm({ ...form, code: e.target.value })}
-            />
-          </label>
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_credits")}</span>
-            <input
-              type="number"
-              min={1}
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={form.awardedCredits}
-              onChange={(e) => setForm({ ...form, awardedCredits: Number(e.target.value) })}
-            />
-          </label>
-          <label className="flex flex-col">
-            <span className="text-sm text-muted-foreground">{t("admin_dependency_credit")}</span>
-            <input
-              type="number"
-              min={0}
-              className="rounded-lg border border-border bg-background px-3 py-2"
-              value={form.dependencyCredit}
-              onChange={(e) => setForm({ ...form, dependencyCredit: Number(e.target.value) })}
-            />
-          </label>
-        </div>
-        <div className="mt-4 flex gap-3">
-          <button
-            disabled={busy}
-            className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
-            onClick={() =>
-              void run(async () => {
-                const body = {
-                  Name: form.name,
-                  Code: form.code,
-                  AwardedCredits: form.awardedCredits,
-                  DependencyCredit: form.dependencyCredit,
-                };
-                const result =
-                  editingId === null
-                    ? await adminSend("/api/admin/subjects", "POST", body)
-                    : await adminSend(`/api/admin/subjects/${editingId}`, "PUT", body);
-                cancelEdit();
-                return result;
-              })
-            }
-          >
-            {editingId === null ? t("admin_create") : t("admin_save")}
-          </button>
-          {editingId !== null && (
-            <button
-              className="rounded-lg border border-border px-4 py-2 text-sm font-medium"
-              onClick={cancelEdit}
-              disabled={busy}
-            >
-              {t("cancel")}
-            </button>
-          )}
-        </div>
-      </div>
-
-      {/* list */}
-      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-        <div className="flex items-center justify-between gap-4 bg-primary text-white px-6 py-4">
-          <h2 className="text-xl font-bold">
-            {t("admin_subjects")} ({filtered.length})
-          </h2>
-          <input
-            className="rounded-lg px-3 py-2 text-card-foreground bg-background"
-            placeholder={t("admin_search_subject")}
-            value={query}
-            onChange={(e) => setQuery(e.target.value)}
-          />
-        </div>
-
-        <div className="overflow-x-auto">
-          <table className="w-full">
-            <thead className="bg-accent">
-              <tr>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_code")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_name")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_credits")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_majors")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_prerequisites")}</th>
-                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
-              </tr>
-            </thead>
-            <tbody>
-              {loading ? (
-                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={6}>{t("loading")}</td></tr>
-              ) : filtered.length === 0 ? (
-                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={6}>{t("admin_no_subjects")}</td></tr>
-              ) : (
-                filtered.map((s) => (
-                  <ExpandableRow
-                    key={s.id}
-                    subject={s}
-                    majors={majors}
-                    subjects={subjects}
-                    busy={busy}
-                    expanded={expandedId === s.id}
-                    onToggle={() => setExpandedId(expandedId === s.id ? null : s.id)}
-                    onEdit={() => startEdit(s)}
-                    run={run}
-                  />
-                ))
-              )}
-            </tbody>
-          </table>
-        </div>
-      </div>
-    </div>
-  );
-}
-
-function ExpandableRow({
-  subject,
-  majors,
-  subjects,
-  busy,
-  expanded,
-  onToggle,
-  onEdit,
-  run,
-}: {
-  subject: AdminSubject;
-  majors: SubjectRef[];
-  subjects: AdminSubject[];
-  busy: boolean;
-  expanded: boolean;
-  onToggle: () => void;
-  onEdit: () => void;
-  run: (action: () => Promise<{ message?: string }>) => Promise<void>;
-}) {
-  const { t } = useTranslation();
-  const [majorId, setMajorId] = useState<number | "">("");
-  const [semester, setSemester] = useState(1);
-  const [prereqId, setPrereqId] = useState<number | "">("");
-
-  // A subject already taken by students cannot be deleted; the FK forbids it.
-  const deletable = subject.enrolledCount === 0;
-
-  return (
-    <>
-      <tr className="hover:bg-accent">
-        <td className="px-4 py-3 border-b font-mono text-card-foreground">{subject.code}</td>
-        <td className="px-4 py-3 border-b text-card-foreground">{subject.name}</td>
-        <td className="px-4 py-3 border-b text-card-foreground">{subject.awardedCredits}</td>
-        <td className="px-4 py-3 border-b text-sm text-muted-foreground">
-          {subject.majors.length === 0 ? "—" : subject.majors.map((m) => `${m.majorName} (${m.mandatorySemester})`).join(", ")}
-        </td>
-        <td className="px-4 py-3 border-b text-sm text-muted-foreground">
-          {subject.prerequisites.length === 0 ? "—" : subject.prerequisites.map((p) => p.code).join(", ")}
-        </td>
-        <td className="px-4 py-3 border-b">
-          <div className="flex flex-wrap gap-2">
-            <button className="rounded-lg border border-border px-3 py-1.5 text-sm" onClick={onToggle}>
-              {expanded ? t("admin_close") : t("admin_manage")}
-            </button>
-            <button className="rounded-lg bg-blue-600 px-3 py-1.5 text-sm text-white disabled:opacity-50" onClick={onEdit} disabled={busy}>
-              {t("edit_grade") === "Измени оценка" ? "Измени" : "Edit"}
-            </button>
-            <button
-              className="rounded-lg bg-gray-800 px-3 py-1.5 text-sm text-white disabled:opacity-40"
-              disabled={busy || !deletable}
-              title={deletable ? undefined : t("admin_delete_blocked", { count: subject.enrolledCount })}
-              onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}`, "DELETE"))}
-            >
-              {t("admin_delete")}
-            </button>
-          </div>
-        </td>
-      </tr>
-
-      {expanded && (
-        <tr>
-          <td colSpan={6} className="border-b bg-accent/40 px-4 py-4">
-            <div className="grid gap-6 lg:grid-cols-2">
-              {/* majors */}
-              <div>
-                <h3 className="font-semibold text-card-foreground mb-2">{t("admin_majors")}</h3>
-                <ul className="mb-3 space-y-1 text-sm">
-                  {subject.majors.map((m) => (
-                    <li key={m.majorId} className="flex items-center justify-between gap-2">
-                      <span>{m.majorName} — {t("enroll_semester_short")} {m.mandatorySemester}</span>
-                      <button
-                        className="text-red-700 hover:underline"
-                        disabled={busy}
-                        onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}/majors/${m.majorId}`, "DELETE"))}
-                      >
-                        {t("admin_remove")}
-                      </button>
-                    </li>
-                  ))}
-                  {subject.majors.length === 0 && <li className="text-muted-foreground">—</li>}
-                </ul>
-                <div className="flex flex-wrap gap-2">
-                  <select
-                    className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
-                    value={majorId}
-                    onChange={(e) => setMajorId(e.target.value === "" ? "" : Number(e.target.value))}
-                  >
-                    <option value="">{t("admin_pick_major")}</option>
-                    {majors.map((m) => (
-                      <option key={m.id} value={m.id}>{m.name}</option>
-                    ))}
-                  </select>
-                  <input
-                    type="number"
-                    min={1}
-                    className="w-24 rounded-lg border border-border bg-background px-3 py-2 text-sm"
-                    value={semester}
-                    onChange={(e) => setSemester(Number(e.target.value))}
-                  />
-                  <button
-                    className="rounded-lg bg-green-600 px-3 py-2 text-sm text-white disabled:opacity-50"
-                    disabled={busy || majorId === ""}
-                    onClick={() =>
-                      void run(() =>
-                        adminSend(`/api/admin/subjects/${subject.id}/majors`, "POST", {
-                          MajorId: majorId,
-                          MandatorySemester: semester,
-                        }),
-                      )
-                    }
-                  >
-                    {t("admin_add")}
-                  </button>
-                </div>
-              </div>
-
-              {/* prerequisites */}
-              <div>
-                <h3 className="font-semibold text-card-foreground mb-2">{t("admin_prerequisites")}</h3>
-                <ul className="mb-3 space-y-1 text-sm">
-                  {subject.prerequisites.map((p) => (
-                    <li key={p.id} className="flex items-center justify-between gap-2">
-                      <span>{p.code} — {p.name}</span>
-                      <button
-                        className="text-red-700 hover:underline"
-                        disabled={busy}
-                        onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}/prerequisites/${p.id}`, "DELETE"))}
-                      >
-                        {t("admin_remove")}
-                      </button>
-                    </li>
-                  ))}
-                  {subject.prerequisites.length === 0 && <li className="text-muted-foreground">—</li>}
-                </ul>
-                <div className="flex flex-wrap gap-2">
-                  <select
-                    className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
-                    value={prereqId}
-                    onChange={(e) => setPrereqId(e.target.value === "" ? "" : Number(e.target.value))}
-                  >
-                    <option value="">{t("admin_pick_prerequisite")}</option>
-                    {subjects
-                      .filter((other) => other.id !== subject.id)
-                      .map((other) => (
-                        <option key={other.id} value={other.id}>{other.code} — {other.name}</option>
-                      ))}
-                  </select>
-                  <button
-                    className="rounded-lg bg-green-600 px-3 py-2 text-sm text-white disabled:opacity-50"
-                    disabled={busy || prereqId === ""}
-                    onClick={() =>
-                      void run(() =>
-                        adminSend(`/api/admin/subjects/${subject.id}/prerequisites`, "POST", {
-                          DependencyId: prereqId,
-                        }),
-                      )
-                    }
-                  >
-                    {t("admin_add")}
-                  </button>
-                </div>
-              </div>
-            </div>
-          </td>
-        </tr>
-      )}
-    </>
-  );
-}
Index: c/app/globals.css
===================================================================
--- src/app/globals.css	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,122 +1,0 @@
-@import "tailwindcss";
-@import "tw-animate-css";
-
-@custom-variant dark (&:is(.dark *));
-
-@theme inline {
-  --color-background: var(--background);
-  --color-foreground: var(--foreground);
-  --font-sans: var(--font-geist-sans);
-  --font-mono: var(--font-geist-mono);
-  --color-sidebar-ring: var(--sidebar-ring);
-  --color-sidebar-border: var(--sidebar-border);
-  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
-  --color-sidebar-accent: var(--sidebar-accent);
-  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
-  --color-sidebar-primary: var(--sidebar-primary);
-  --color-sidebar-foreground: var(--sidebar-foreground);
-  --color-sidebar: var(--sidebar);
-  --color-chart-5: var(--chart-5);
-  --color-chart-4: var(--chart-4);
-  --color-chart-3: var(--chart-3);
-  --color-chart-2: var(--chart-2);
-  --color-chart-1: var(--chart-1);
-  --color-ring: var(--ring);
-  --color-input: var(--input);
-  --color-border: var(--border);
-  --color-destructive: var(--destructive);
-  --color-accent-foreground: var(--accent-foreground);
-  --color-accent: var(--accent);
-  --color-muted-foreground: var(--muted-foreground);
-  --color-muted: var(--muted);
-  --color-secondary-foreground: var(--secondary-foreground);
-  --color-secondary: var(--secondary);
-  --color-primary-foreground: var(--primary-foreground);
-  --color-primary: var(--primary);
-  --color-popover-foreground: var(--popover-foreground);
-  --color-popover: var(--popover);
-  --color-card-foreground: var(--card-foreground);
-  --color-card: var(--card);
-  --radius-sm: calc(var(--radius) - 4px);
-  --radius-md: calc(var(--radius) - 2px);
-  --radius-lg: var(--radius);
-  --radius-xl: calc(var(--radius) + 4px);
-}
-
-:root {
-  --radius: 0.625rem;
-  --background: #F4FAFF;
-  --foreground: oklch(0.145 0 0);
-  --card: oklch(1 0 0);
-  --card-foreground: oklch(0.145 0 0);
-  --popover: oklch(1 0 0);
-  --popover-foreground: oklch(0.145 0 0);
-  --primary: #0272D1;
-  --primary-foreground: oklch(0.985 0 0);
-  --secondary: oklch(0.97 0 0);
-  --secondary-foreground: oklch(0.205 0 0);
-  --muted: oklch(0.97 0 0);
-  --muted-foreground: oklch(0.556 0 0);
-  --accent: oklch(0.97 0 0);
-  --accent-foreground: oklch(0.205 0 0);
-  --destructive: oklch(0.577 0.245 27.325);
-  --border: oklch(0.922 0 0);
-  --input: oklch(0.922 0 0);
-  --ring: oklch(0.708 0 0);
-  --chart-1: oklch(0.646 0.222 41.116);
-  --chart-2: oklch(0.6 0.118 184.704);
-  --chart-3: oklch(0.398 0.07 227.392);
-  --chart-4: oklch(0.828 0.189 84.429);
-  --chart-5: oklch(0.769 0.188 70.08);
-  --sidebar: oklch(0.985 0 0);
-  --sidebar-foreground: oklch(0.145 0 0);
-  --sidebar-primary: oklch(0.205 0 0);
-  --sidebar-primary-foreground: oklch(0.985 0 0);
-  --sidebar-accent: oklch(0.97 0 0);
-  --sidebar-accent-foreground: oklch(0.205 0 0);
-  --sidebar-border: oklch(0.922 0 0);
-  --sidebar-ring: oklch(0.708 0 0);
-}
-
-.dark {
-  --background: oklch(0.15 0.01 240);
-  --foreground: oklch(0.95 0.01 240);
-  --card: oklch(0.18 0.01 240);
-  --card-foreground: oklch(0.95 0.01 240);
-  --popover: oklch(0.18 0.01 240);
-  --popover-foreground: oklch(0.95 0.01 240);
-  --primary: #3b82f6;
-  --primary-foreground: oklch(0.98 0 0);
-  --secondary: oklch(0.25 0.01 240);
-  --secondary-foreground: oklch(0.95 0.01 240);
-  --muted: oklch(0.25 0.01 240);
-  --muted-foreground: oklch(0.65 0.01 240);
-  --accent: oklch(0.25 0.01 240);
-  --accent-foreground: oklch(0.95 0.01 240);
-  --destructive: oklch(0.6 0.22 25);
-  --border: oklch(0.3 0.01 240);
-  --input: oklch(0.25 0.01 240);
-  --ring: oklch(0.5 0.15 240);
-  --chart-1: oklch(0.6 0.2 270);
-  --chart-2: oklch(0.65 0.18 180);
-  --chart-3: oklch(0.7 0.19 90);
-  --chart-4: oklch(0.6 0.24 310);
-  --chart-5: oklch(0.65 0.22 30);
-  --sidebar: oklch(0.18 0.01 240);
-  --sidebar-foreground: oklch(0.95 0.01 240);
-  --sidebar-primary: oklch(0.5 0.2 260);
-  --sidebar-primary-foreground: oklch(0.98 0 0);
-  --sidebar-accent: oklch(0.25 0.01 240);
-  --sidebar-accent-foreground: oklch(0.95 0.01 240);
-  --sidebar-border: oklch(0.3 0.01 240);
-  --sidebar-ring: oklch(0.5 0.15 240);
-}
-
-@layer base {
-  * {
-    @apply border-border outline-ring/50;
-  }
-  body {
-    @apply text-foreground bg-background;
-  }
-}
Index: c/app/layout.tsx
===================================================================
--- src/app/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,44 +1,0 @@
-"use client";
-import { Geist, Geist_Mono } from "next/font/google";
-import "./globals.css";
-import '@fortawesome/fontawesome-svg-core/styles.css';
-import { config } from '@fortawesome/fontawesome-svg-core';
-import { I18nextProvider } from 'react-i18next';
-import i18n from '../i18n';
-import { ThemeProvider } from '../components/theme-provider';
-import { ThemeToggle } from '../components/theme-toggle';
-import ContactBubble from '../components/contact-bubble';
-
-config.autoAddCss = false;
-
-const geistSans = Geist({
-  variable: "--font-geist-sans",
-  subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
-  variable: "--font-geist-mono",
-  subsets: ["latin"],
-});
-
-export default function RootLayout({
-  children,
-}: Readonly<{
-  children: React.ReactNode;
-}>) {
-  return (
-    <html lang="en" suppressHydrationWarning>
-      <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
-        <ThemeProvider attribute="class" defaultTheme="light" enableSystem>
-          <I18nextProvider i18n={i18n}>
-            <div className="fixed top-4 right-4 z-50">
-              <ThemeToggle />
-            </div>
-            <div className="mx-auto max-w-6xl px-4">{children}</div>
-            <ContactBubble />
-          </I18nextProvider>
-        </ThemeProvider>
-      </body>
-    </html>
-  );
-}
Index: c/app/page.tsx
===================================================================
--- src/app/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,242 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { 
-  faUser, 
-  faLock, 
-  faEye, 
-  faEyeSlash,
-  faSignInAlt,
-  faGraduationCap
-} from '@fortawesome/free-solid-svg-icons';
-import { useState } from 'react';
-import { login } from '@/lib/auth';
-import { useTranslation } from 'react-i18next';
-import LanguageSwitcher from '@/components/LanguageSwitcher';
-
-export default function LoginPage() {
-  const { t } = useTranslation();
-  const [showPassword, setShowPassword] = useState(false);
-  const [isSubmitting, setIsSubmitting] = useState(false);
-  const [errorMessage, setErrorMessage] = useState<string | null>(null);
-  const [formData, setFormData] = useState({
-    email: '',
-    password: ''
-  });
-
-  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-    const { name, value } = e.target;
-    setFormData(prev => ({
-      ...prev,
-      [name]: value
-    }));
-  };
-
-  const handleSubmit = async (e: React.FormEvent) => {
-    e.preventDefault();
-    setErrorMessage(null);
-    setIsSubmitting(true);
-    try {
-      const session = await login({ email: formData.email, password: formData.password });
-      // Admins previously fell through to /students, where they have no
-      // enrolments and every page renders empty.
-      const home =
-        session.role === 'Professor' ? '/professor'
-        : session.role === 'Admin'   ? '/admin'
-        : '/students';
-      window.location.href = home;
-    } catch (err) {
-      setErrorMessage(err instanceof Error ? err.message : 'Login failed.');
-    } finally {
-      setIsSubmitting(false);
-    }
-  };
-
-  return (
-    <div className="container mx-auto px-4">
-      <div className="min-h-screen ">
-        {/* Login Form */}
-        <div className="flex items-center justify-center min-h-[calc(100vh-160px)] p-4">
-          <div className="w-full max-w-5xl">
-            <div className="grid grid-cols-1 gap-6 lg:grid-cols-[24rem_28rem_24rem] lg:items-start lg:justify-center">
-              {/* Sticky Notes */}
-              <div className="w-full flex flex-col gap-4">
-                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
-                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_student_title')}</div>
-                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
-                    {t('login_student_example')}
-                  </div>
-                  <div className="mt-3 text-xs text-blue-600 font-medium">
-                    {t('login_demo_note')}
-                  </div>
-                </div>
-
-                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
-                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_professor_title')}</div>
-                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
-                    {t('login_professor_example')}
-                  </div>
-                  <div className="mt-3 text-xs text-blue-600 font-medium">
-                    {t('login_demo_note')}
-                  </div>
-                </div>
-
-                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
-                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_admin_title')}</div>
-                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
-                    {t('login_admin_example')}
-                  </div>
-                  <div className="mt-3 text-xs text-blue-600 font-medium">
-                    {t('login_demo_note')}
-                  </div>
-                </div>
-              </div>
-
-              {/* Login Card Column */}
-              <div className="w-full max-w-md lg:max-w-none lg:w-[28rem] mx-auto">
-                {/* Login Card */}
-                <div className="bg-card rounded-2xl shadow-xl border border-border overflow-hidden">
-                {/* Header */}
-                <div className="bg-primary text-white px-8 py-6 text-center">
-              <div className="mb-4">
-                <div className="inline-flex items-center justify-center w-16 h-16 bg-white rounded-full shadow-lg">
-                  <FontAwesomeIcon icon={faUser} className="text-2xl text-[#0272D1]" />
-                </div>
-              </div>
-              <h1 className="text-2xl font-bold mb-2">{t('login_welcome')}</h1>
-              <p className="text-blue-100 text-sm">
-                {t('login_subtitle')}
-              </p>
-            </div>
-
-            {/* Form */}
-            <div className="p-8">
-              {/* Language Switcher above email field, centered */}
-              <div className="flex justify-center mb-6">
-                <LanguageSwitcher />
-              </div>
-              <form onSubmit={handleSubmit} className="space-y-6">
-                {/* Email Field */}
-                <div>
-                  <label htmlFor="email" className="block text-sm font-medium text-muted-foreground mb-2">
-                    {t('login_email_label')}
-                  </label>
-                  <div className="relative">
-                    <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
-                      <FontAwesomeIcon icon={faUser} className="h-4 w-4 text-muted-foreground" />
-                    </div>
-                    <input
-                      id="email"
-                      name="email"
-                      type="email"
-                      required
-                      value={formData.email}
-                      onChange={handleInputChange}
-                      className="w-full pl-10 pr-4 py-3 border border-input rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors"
-                      placeholder={t('login_email_placeholder')}
-                    />
-                  </div>
-                </div>
-
-                {/* Password Field */}
-                <div>
-                  <label htmlFor="password" className="block text-sm font-medium text-muted-foreground mb-2">
-                    {t('login_password_label')}
-                  </label>
-                  <div className="relative">
-                    <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
-                      <FontAwesomeIcon icon={faLock} className="h-4 w-4 text-muted-foreground" />
-                    </div>
-                    <input
-                      id="password"
-                      name="password"
-                      type={showPassword ? "text" : "password"}
-                      required
-                      value={formData.password}
-                      onChange={handleInputChange}
-                      className="w-full pl-10 pr-12 py-3 border border-input rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary transition-colors"
-                      placeholder={t('login_password_placeholder')}
-                    />
-                    <button
-                      type="button"
-                      onClick={() => setShowPassword(!showPassword)}
-                      className="absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground transition-colors"
-                    >
-                      <FontAwesomeIcon 
-                        icon={showPassword ? faEyeSlash : faEye} 
-                        className="h-4 w-4" 
-                      />
-                    </button>
-                  </div>
-                </div>
-
-                {/* Remember Me & Forgot Password */}
-                <div className="flex items-center justify-between">
-                  <div className="flex items-center">
-                    <input
-                      id="remember"
-                      name="remember"
-                      type="checkbox"
-                      className="h-4 w-4 text-primary focus:ring-primary border-input rounded"
-                    />
-                    <label htmlFor="remember" className="ml-2 block text-sm text-muted-foreground">
-                      {t('login_remember_me')}
-                    </label>
-                  </div>
-                  <button
-                    type="button"
-                    className="text-sm text-primary hover:text-blue-700 font-medium transition-colors"
-                  >
-                    {t('login_forgot_password')}
-                  </button>
-                </div>
-
-                {errorMessage && (
-                  <div className="rounded-lg border border-destructive/20 bg-destructive/10 px-4 py-3 text-sm text-destructive">
-                    {t(errorMessage) || errorMessage}
-                  </div>
-                )}
-
-                {/* Submit Button */}
-                <button
-                  type="submit"
-                  disabled={isSubmitting}
-                  className="w-full bg-primary hover:bg-blue-700 disabled:opacity-60 disabled:hover:bg-primary text-white font-medium py-3 px-4 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
-                >
-                  <FontAwesomeIcon icon={faSignInAlt} className="h-4 w-4" />
-                  {isSubmitting ? t('login_button_loading') : t('login_button')}
-                </button>
-              </form>
-            </div>
-
-            {/* Footer */}
-            <div className="bg-accent px-8 py-4 border-t border-border">
-              <p className="text-center text-sm text-muted-foreground">
-                {t('login_no_account')}{' '}
-                <button className="text-primary hover:text-blue-700 font-medium transition-colors">
-                  {t('login_contact_admin')}
-                </button>
-              </p>
-            </div>
-                </div>
-
-                {/* Additional Info */}
-                <div className="mt-6 text-center">
-                  <div className="inline-flex items-center gap-2 px-4 py-2 bg-card bg-opacity-80 rounded-lg shadow-sm">
-                    <FontAwesomeIcon icon={faGraduationCap} className="text-primary" />
-                    <span className="text-sm text-muted-foreground">
-                      {t('login_footer')}
-                    </span>
-                  </div>
-                </div>
-              </div>
-
-              {/* Right spacer column (keeps login centered) */}
-              <div className="hidden lg:block" />
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/professor/layout.tsx
===================================================================
--- src/app/professor/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,38 +1,0 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
-import "../globals.css";
-import "@fortawesome/fontawesome-svg-core/styles.css";
-import { config } from "@fortawesome/fontawesome-svg-core";
-import Header from "@/components/header";
-import ProfessorNavbar from "@/components/professor-navbar";
-
-config.autoAddCss = false;
-
-const geistSans = Geist({
-  variable: "--font-geist-sans",
-  subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
-  variable: "--font-geist-mono",
-  subsets: ["latin"],
-});
-
-export const metadata: Metadata = {
-  title: "IKnow - Professor Portal",
-  description: "Professor portal for managing students and grades",
-};
-
-export default function ProfessorLayout({
-  children,
-}: Readonly<{
-  children: React.ReactNode;
-}>) {
-  return (
-    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
-      <Header />
-      <ProfessorNavbar />
-      {children}
-    </div>
-  );
-}
Index: c/app/professor/page.tsx
===================================================================
--- src/app/professor/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,5 +1,0 @@
-import { redirect } from "next/navigation";
-
-export default function ProfessorHome() {
-  redirect("/professor/students");
-}
Index: c/app/professor/profile/page.tsx
===================================================================
--- src/app/professor/profile/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,287 +1,0 @@
-"use client";
-
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import {
-  faUser,
-  faIdCard,
-  faAddressCard,
-  faCalendarAlt,
-  faFlag,
-  faVenus,
-  faMars,
-  faEnvelope,
-  faPhone,
-  faMapMarkerAlt,
-  faPassport,
-} from "@fortawesome/free-solid-svg-icons";
-import { useEffect, useState } from "react";
-import { getAccessToken } from "@/lib/auth";
-import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
-import { useTranslation } from 'react-i18next';
-import { apiUrl } from '@/lib/api';
-
-type PersonalInfo = {
-  firstName: string;
-  middleName: string;
-  lastName: string;
-  maidenName: string;
-  dateOfBirth: string;
-  gender: string;
-  nationality: string;
-  citizenship: string;
-  scholarship: string;
-  currentPlan: string;
-  registryNumber: string;
-  studyGroup: string;
-  notes?: string;
-  index: string;
-  embg: string;
-};
-
-type BirthInfo = {
-  placeOfBirth: string;
-  municipalityOfBirth: string;
-  country: string;
-};
-
-// Present in the API response, but intentionally not shown on professor profile.
-type PreviousEducation = {
-  type: string;
-  profession: string;
-  average: string | number;
-  language: string;
-  country: string;
-  previousUniversity: string;
-  previousFaculty: string;
-  previousStudyMode: string;
-};
-
-// Present in the API response, but intentionally not shown on professor profile.
-type EnrollmentInfo = {
-  enrollmentYear: string | number;
-  status: string;
-  cycle: string;
-  program: string;
-  quota: string;
-  secondaryEducationNumber: string;
-  previousEducationCredits: string | number;
-};
-
-type Contact = {
-  placeOfResidence: string;
-  municipalityOfResidence: string;
-  country: string;
-  address: string;
-  temporaryAddress: string;
-  phone: string;
-  mobilePhone: string;
-  passportNumber: string;
-  passportExpiryDate: string;
-  email: string;
-  microsoftEmail: string;
-};
-
-type StudentProfile = {
-  personalInfo: PersonalInfo;
-  birthInfo: BirthInfo;
-  previousEducation: PreviousEducation;
-  enrollmentInfo: EnrollmentInfo;
-  contact: Contact;
-};
-
-interface InfoRowProps {
-  label: string;
-  value: string | number;
-  icon?: IconDefinition;
-}
-
-const InfoRow = ({ label, value, icon }: InfoRowProps) => {
-  const { t } = useTranslation();
-  return (
-    <div className="flex justify-between items-center py-3 border-b border-border last:border-b-0">
-      <div className="flex items-center gap-2 text-muted-foreground font-medium">
-        {icon && <FontAwesomeIcon icon={icon} className="w-4 h-4" />}
-        <span>{t(label)}:</span>
-      </div>
-      <div className="text-card-foreground font-semibold text-right max-w-xs break-words">
-        {value || t('n_a')}
-      </div>
-    </div>
-  );
-};
-
-interface SectionProps {
-  title: string;
-  icon: IconDefinition;
-  children: React.ReactNode;
-}
-
-const Section = ({ title, icon, children }: SectionProps) => {
-  const { t } = useTranslation();
-  return (
-    <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-      <div className="bg-primary text-white px-6 py-4">
-        <div className="flex items-center gap-3">
-          <FontAwesomeIcon icon={icon} className="text-xl" />
-          <h2 className="text-xl font-bold">{t(title)}</h2>
-        </div>
-      </div>
-      <div className="p-6">{children}</div>
-    </div>
-  );
-};
-
-export default function ProfessorProfilePage() {
-  const [profileData, setProfileData] = useState<StudentProfile | null>(null);
-  const [isLoading, setIsLoading] = useState(true);
-  const [errorMessage, setErrorMessage] = useState<string | null>(null);
-  const { t } = useTranslation();
-
-  useEffect(() => {
-    let cancelled = false;
-
-    async function load() {
-      setIsLoading(true);
-      setErrorMessage(null);
-
-      const token = getAccessToken();
-      if (!token) {
-        setErrorMessage("Not authenticated. Please login again.");
-        setIsLoading(false);
-        return;
-      }
-
-      try {
-        const response = await fetch(apiUrl("/api/user/getUser"), {
-          method: "GET",
-          headers: {
-            Authorization: `Bearer ${token}`,
-          },
-        });
-
-        if (!response.ok) {
-          const text = await response.text().catch(() => "");
-          throw new Error(text || `Failed to load profile (${response.status})`);
-        }
-
-        const data = (await response.json()) as StudentProfile;
-        if (!cancelled) setProfileData(data);
-      } catch (err) {
-        if (!cancelled) {
-          setErrorMessage(err instanceof Error ? err.message : "Failed to load profile.");
-        }
-      } finally {
-        if (!cancelled) setIsLoading(false);
-      }
-    }
-
-    void load();
-
-    return () => {
-      cancelled = true;
-    };
-  }, []);
-
-  if (isLoading) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="bg-card rounded-xl shadow-sm border border-border p-6">{t('loading')}</div>
-      </div>
-    );
-  }
-
-  if (errorMessage || !profileData) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
-          {errorMessage ?? t('failed_to_load_profile')}
-        </div>
-      </div>
-    );
-  }
-
-  const { personalInfo, birthInfo, contact } = profileData;
-
-  return (
-    <div className="min-h-screen pb-8">
-      {/* Header */}
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex items-center gap-6">
-          <div className="relative">
-            <div className="w-20 h-20 bg-white rounded-full flex items-center justify-center border-2 border-white shadow-lg">
-              <FontAwesomeIcon icon={faUser} className="text-3xl text-[#0272D1]" />
-            </div>
-            <div className="absolute -bottom-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-2 border-white"></div>
-          </div>
-          <div>
-            <h1 className="text-3xl font-bold mb-2">
-              {personalInfo.firstName} {personalInfo.middleName} {personalInfo.lastName}
-            </h1>
-            <div className="text-lg opacity-90">
-              {t('index')}: {personalInfo.index} | {t('embg')}: {personalInfo.embg}
-            </div>
-          </div>
-        </div>
-      </div>
-
-      {/* Profile Sections */}
-      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
-        {/* Personal Information */}
-        <Section title="personal_info" icon={faIdCard}>
-          <InfoRow label="first_name" value={personalInfo.firstName} />
-          <InfoRow label="middle_name" value={personalInfo.middleName} />
-          <InfoRow label="last_name" value={personalInfo.lastName} />
-          <InfoRow label="maiden_name" value={personalInfo.maidenName} />
-          <InfoRow label="date_of_birth" value={personalInfo.dateOfBirth} icon={faCalendarAlt} />
-          <InfoRow
-            label="gender"
-            value={personalInfo.gender}
-            icon={personalInfo.gender === t('male') ? faMars : faVenus}
-          />
-          <InfoRow label="nationality" value={personalInfo.nationality} icon={faFlag} />
-          <InfoRow label="citizenship" value={personalInfo.citizenship} />
-          <InfoRow label="scholarship" value={personalInfo.scholarship} />
-          <InfoRow label="current_plan" value={personalInfo.currentPlan} />
-          <InfoRow label="registry_number" value={personalInfo.registryNumber} />
-          <InfoRow label="study_group" value={personalInfo.studyGroup} />
-          {personalInfo.notes && (
-            <div className="mt-4 p-4 bg-blue-50 rounded-lg">
-              <div className="text-sm font-medium text-blue-800 mb-1">{t('note')}:</div>
-              <div className="text-sm text-blue-700">{personalInfo.notes}</div>
-            </div>
-          )}
-        </Section>
-
-        {/* Birth Information */}
-        <Section title="birth_info" icon={faMapMarkerAlt}>
-          <InfoRow label="place_of_birth" value={birthInfo.placeOfBirth} />
-          <InfoRow label="municipality_of_birth" value={birthInfo.municipalityOfBirth} />
-          <InfoRow label="country" value={birthInfo.country} />
-        </Section>
-
-        {/* Contact Information */}
-        <div className="lg:col-span-2">
-          <Section title="contact" icon={faAddressCard}>
-            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
-              <div>
-                <InfoRow label="place_of_residence" value={contact.placeOfResidence} icon={faMapMarkerAlt} />
-                <InfoRow label="municipality_of_residence" value={contact.municipalityOfResidence} />
-                <InfoRow label="country" value={contact.country} />
-                <InfoRow label="address" value={contact.address} />
-                <InfoRow label="temporary_address" value={contact.temporaryAddress} />
-              </div>
-              <div>
-                <InfoRow label="phone" value={contact.phone} icon={faPhone} />
-                <InfoRow label="mobile_phone" value={contact.mobilePhone} icon={faPhone} />
-                <InfoRow label="passport_number" value={contact.passportNumber} icon={faPassport} />
-                <InfoRow label="passport_expiry_date" value={contact.passportExpiryDate} />
-                <InfoRow label="email" value={contact.email} icon={faEnvelope} />
-                <InfoRow label="microsoft_email" value={contact.microsoftEmail} icon={faEnvelope} />
-              </div>
-            </div>
-          </Section>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/professor/students/page.tsx
===================================================================
--- src/app/professor/students/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,315 +1,0 @@
-"use client";
-
-import { useEffect, useMemo, useState } from "react";
-import { useTranslation } from 'react-i18next';
-import { apiUrl } from '@/lib/api';
-import { getAccessToken } from '@/lib/auth';
-
-type UsersBySubject = {
-  /** users.id - what the grading endpoints expect as StudentId. */
-  id: number;
-  name?: string;
-  /** users.index - the number shown to the professor and searched on. */
-  index?: string;
-  grade: number;
-  semester?: string;
-};
-
-type SubjectsAndUsers = {
-  name?: string;
-  id?: number;
-  code?: string;
-  users: UsersBySubject[];
-};
-
-type GradePayload = {
-  StudentId: number;
-  SubjectId: number;
-  Grade: number;
-};
-
-type FlatRow = {
-  studentIdNum: number;
-  studentIndex: string;
-  studentName: string;
-  subjectId: number;
-  subjectName: string;
-  semester: string;
-  grade: number;
-};
-
-export default function ProfessorStudentsPage() {
-  const { t } = useTranslation();
-  const [subjects, setSubjects] = useState<SubjectsAndUsers[]>([]);
-  const [loading, setLoading] = useState(true);
-  const [error, setError] = useState<string | null>(null);
-
-  const [subjectFilter, setSubjectFilter] = useState<string>("all");
-  const [studentIdQuery, setStudentIdQuery] = useState<string>("");
-
-  const [gradeSelection, setGradeSelection] = useState<Record<string, number>>({});
-  const [actionBusyKey, setActionBusyKey] = useState<string | null>(null);
-
-  async function refresh() {
-    setLoading(true);
-    setError(null);
-    try {
-      const token = getAccessToken();
-      if (!token) {
-        throw new Error("You are not signed in.");
-      }
-
-      const res = await fetch(apiUrl("/api/prof/students"), {
-        cache: "no-store",
-        headers: { Authorization: `Bearer ${token}` },
-      });
-      if (!res.ok) {
-        throw new Error(`Failed to fetch students (${res.status})`);
-      }
-      const data = (await res.json()) as SubjectsAndUsers[];
-      setSubjects(data);
-
-      const nextSelections: Record<string, number> = {};
-      for (const subj of data) {
-        if (!subj.id) continue;
-        for (const u of subj.users) {
-          const key = `${subj.id}:${u.id}`;
-          // grade_type only declares 6..10, so an ungraded row starts at 6.
-          nextSelections[key] = u.grade >= 6 && u.grade <= 10 ? u.grade : 6;
-        }
-      }
-      setGradeSelection(nextSelections);
-    } catch (e) {
-      setError(e instanceof Error ? e.message : "Unknown error");
-    } finally {
-      setLoading(false);
-    }
-  }
-
-  useEffect(() => {
-    void refresh();
-  }, []);
-
-  const flatRows = useMemo<FlatRow[]>(() => {
-    const rows: FlatRow[] = [];
-    for (const subj of subjects) {
-      if (!subj.id) continue;
-      for (const u of subj.users) {
-        rows.push({
-          studentIdNum: u.id,
-          studentIndex: u.index ?? "",
-          studentName: u.name ?? "",
-          subjectId: subj.id,
-          subjectName: subj.name ?? "",
-          semester: u.semester ?? "",
-          grade: u.grade,
-        });
-      }
-    }
-    return rows;
-  }, [subjects]);
-
-  const filteredRows = useMemo(() => {
-    const q = studentIdQuery.trim();
-    return flatRows.filter((r) => {
-      if (subjectFilter !== "all" && String(r.subjectId) !== subjectFilter) return false;
-      if (q.length > 0 && !r.studentIndex.includes(q)) return false;
-      return true;
-    });
-  }, [flatRows, subjectFilter, studentIdQuery]);
-
-  async function postGrade(url: string, payload: GradePayload, busyKey: string) {
-    setActionBusyKey(busyKey);
-    setError(null);
-    try {
-      const token = getAccessToken();
-      if (!token) {
-        throw new Error("You are not signed in.");
-      }
-
-      const res = await fetch(apiUrl(url), {
-        method: "POST",
-        headers: {
-          "Content-Type": "application/json",
-          Authorization: `Bearer ${token}`,
-        },
-        body: JSON.stringify(payload),
-      });
-      const body = (await res.json()) as { ok: boolean; message?: string };
-      if (!res.ok || !body.ok) {
-        throw new Error(body.message || `Request failed (${res.status})`);
-      }
-      await refresh();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : "Unknown error");
-    } finally {
-      setActionBusyKey(null);
-    }
-  }
-
-  return (
-    <div className="bg-card rounded-xl shadow-sm border border-border p-6">
-      <div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
-
-        <div>
-          <h1 className="text-2xl font-semibold text-card-foreground">{t('prof_students_title')}</h1>
-          <p className="text-muted-foreground mt-1">
-            {t('prof_students_data_note')} <span className="font-mono">/api/prof/students</span>.
-          </p>
-        </div>
-
-        <div className="flex flex-col sm:flex-row gap-3">
-          <div className="flex flex-col">
-            <label className="text-sm text-muted-foreground">{t('filter_by_subject')}</label>
-            <select
-              className="border border-border rounded-lg px-3 py-2"
-              value={subjectFilter}
-              onChange={(e) => setSubjectFilter(e.target.value)}
-            >
-              <option value="all">{t('all_subjects')}</option>
-              {subjects
-                .filter((s) => typeof s.id === "number")
-                .map((s) => (
-                  <option key={String(s.id)} value={String(s.id)}>
-                    {s.name ?? `${t('subject')} ${s.id}`}
-                  </option>
-                ))}
-            </select>
-          </div>
-
-          <div className="flex flex-col">
-            <label className="text-sm text-muted-foreground">{t('find_student_by_id')}</label>
-            <input
-              className="border border-border rounded-lg px-3 py-2"
-              placeholder={t('student_id_placeholder')}
-              value={studentIdQuery}
-              onChange={(e) => setStudentIdQuery(e.target.value)}
-            />
-          </div>
-        </div>
-      </div>
-
-      {error && (
-        <div className="mt-4 rounded-lg border border-red-200 bg-red-50 text-red-800 px-4 py-3">
-          {error}
-        </div>
-      )}
-
-      <div className="mt-6 overflow-x-auto">
-        <table className="min-w-full border border-border rounded-lg overflow-hidden">
-          <thead className="bg-accent">
-            <tr>
-              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('student')}</th>
-              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('id')}</th>
-              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('subject')}</th>
-              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('grade')}</th>
-              <th className="text-left text-sm font-semibold text-muted-foreground px-4 py-3 border-b">{t('actions')}</th>
-            </tr>
-          </thead>
-          <tbody>
-            {loading ? (
-              <tr>
-                <td className="px-4 py-4 text-muted-foreground" colSpan={5}>
-                  {t('loading')}
-                </td>
-              </tr>
-            ) : filteredRows.length === 0 ? (
-              <tr>
-                <td className="px-4 py-4 text-muted-foreground" colSpan={5}>
-                  {t('no_students_found')}
-                </td>
-              </tr>
-            ) : (
-              filteredRows.map((r) => {
-                const key = `${r.subjectId}:${r.studentIdNum}`;
-                const selected = gradeSelection[key] ?? 6;
-                const busy = actionBusyKey === key;
-
-                return (
-                  <tr key={key} className="hover:bg-accent">
-                    <td className="px-4 py-3 border-b text-card-foreground">{r.studentName}</td>
-                    <td className="px-4 py-3 border-b text-card-foreground">{r.studentIndex}</td>
-                    <td className="px-4 py-3 border-b text-card-foreground">
-                      {r.subjectName}
-                      {r.semester && (
-                        <span className="block text-xs text-muted-foreground">{r.semester}</span>
-                      )}
-                    </td>
-                    <td className="px-4 py-3 border-b">
-                      <div className="flex items-center gap-3">
-                        <select
-                          className="border border-border rounded-lg px-3 py-2"
-                          value={selected}
-                          onChange={(e) =>
-                            setGradeSelection((prev) => ({
-                              ...prev,
-                              [key]: Number.parseInt(e.target.value, 10),
-                            }))
-                          }
-                        >
-                          {[6, 7, 8, 9, 10].map((g) => (
-                            <option key={g} value={g}>
-                              {g}
-                            </option>
-                          ))}
-                        </select>
-                        <span className="text-sm text-muted-foreground">
-                          {t('current')}: {r.grade > 0 ? r.grade : t('none')}
-                        </span>
-                      </div>
-                    </td>
-                    <td className="px-4 py-3 border-b">
-                      <div className="flex flex-wrap gap-2">
-                        <button
-                          disabled={busy}
-                          className="px-3 py-2 rounded-lg bg-green-600 text-white text-sm font-medium disabled:opacity-50"
-                          onClick={() => {
-                            void postGrade(
-                              "/api/prof/grade/add",
-                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: selected },
-                              key,
-                            );
-                          }}
-                        >
-                          {t('add_grade')}
-                        </button>
-
-                        <button
-                          disabled={busy}
-                          className="px-3 py-2 rounded-lg bg-blue-600 text-white text-sm font-medium disabled:opacity-50"
-                          onClick={() => {
-                            void postGrade(
-                              "/api/prof/grade/edit",
-                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: selected },
-                              key,
-                            );
-                          }}
-                        >
-                          {t('edit_grade')}
-                        </button>
-
-                        <button
-                          disabled={busy}
-                          className="px-3 py-2 rounded-lg bg-gray-800 text-white text-sm font-medium disabled:opacity-50"
-                          onClick={() => {
-                            void postGrade(
-                              "/api/prof/grade/remove",
-                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: 0 },
-                              key,
-                            );
-                          }}
-                        >
-                          {t('remove_grade')}
-                        </button>
-                      </div>
-                    </td>
-                  </tr>
-                );
-              })
-            )}
-          </tbody>
-        </table>
-      </div>
-    </div>
-  );
-}
Index: c/app/students/applications/page.tsx
===================================================================
--- src/app/students/applications/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,254 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { 
-  faPenToSquare, 
-  faChevronDown,
-  faCalendarAlt,
-  faFileText,
-  faMoneyBillWave,
-  faUser,
-  faInfoCircle,
-  faCheckCircle,
-  faTimesCircle
-} from '@fortawesome/free-solid-svg-icons';
-import { useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import applicationsData from '@/data/applications.json';
-
-interface TableCellProps {
-  children: React.ReactNode;
-  className?: string;
-}
-
-const TableCell = ({ children, className = "" }: TableCellProps) => (
-  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
-    {children}
-  </td>
-);
-
-const CompletedBadge = ({ completed }: { completed: string }) => {
-  const { t } = useTranslation();
-  if (completed === 'Да') {
-    return (
-      <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full" title={t('completed')}> 
-        <FontAwesomeIcon icon={faCheckCircle} className="w-4 h-4" />
-      </span>
-    );
-  } else {
-    return (
-      <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full" title={t('not_completed')}>
-        <FontAwesomeIcon icon={faTimesCircle} className="w-4 h-4" />
-      </span>
-    );
-  }
-};
-
-const FeeBadge = ({ fee }: { fee: string }) => {
-  const feeValue = parseFloat(fee.replace(',', '.'));
-  
-  if (feeValue === 0) {
-    return (
-      <span className="inline-flex items-center gap-1 px-2 py-1 bg-green-100 text-green-800 rounded-md text-xs font-medium">
-        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
-        {fee}
-      </span>
-    );
-  } else {
-    return (
-      <span className="inline-flex items-center gap-1 px-2 py-1 bg-yellow-100 text-yellow-800 rounded-md text-xs font-medium">
-        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
-        {fee}
-      </span>
-    );
-  }
-};
-
-export default function ApplicationsPage() {
-  const { t } = useTranslation();
-  const [selectedSession, setSelectedSession] = useState(applicationsData.currentSession.id);
-  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
-
-  const currentSessionData = applicationsData.examSessions.find(s => s.id === selectedSession) || applicationsData.currentSession;
-  const { applications } = applicationsData;
-
-  return (
-    <div className="min-h-screen pb-8">
-      {/* Header */}
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex items-center gap-4">
-          <div className="bg-white rounded-full p-4">
-            <FontAwesomeIcon icon={faPenToSquare} className="text-3xl text-[#0272D1]" />
-          </div>
-          <div>
-            <h1 className="text-3xl font-bold mb-2">{t('applications_header', 'Пријави')}</h1>
-            <p className="text-lg opacity-90">
-              {t('applications_subheader', 'Електронски пријави за испити')}
-            </p>
-          </div>
-        </div>
-      </div>
-
-      {/* Session Selection */}
-      <div className="bg-card rounded-xl p-6 shadow-sm border border-border mb-8">
-        <div className="flex items-center justify-between">
-          <h2 className="text-lg font-semibold text-card-foreground flex items-center gap-2">
-            <FontAwesomeIcon icon={faCalendarAlt} className="text-primary" />
-            {t('select_exam_session', 'Избери испитна сесија:')}
-          </h2>
-
-          <div className="relative">
-            <button
-              onClick={() => setIsDropdownOpen(!isDropdownOpen)}
-              className="bg-card border border-border rounded-lg px-4 py-2 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary min-w-80"
-            >
-              <div className="flex items-center justify-between">
-                <span className="text-sm font-medium text-primary">
-                  {t(currentSessionData.id, currentSessionData.name)}
-                </span>
-                <FontAwesomeIcon
-                  icon={faChevronDown}
-                  className={`w-4 h-4 text-muted-foreground transition-transform ml-4 ${isDropdownOpen ? 'rotate-180' : ''}`}
-                />
-              </div>
-            </button>
-
-            {isDropdownOpen && (
-              <div className="absolute z-10 right-0 mt-1 w-80 bg-card border border-border rounded-lg shadow-lg">
-                {applicationsData.examSessions.map((session) => (
-                  <button
-                    key={session.id}
-                    onClick={() => {
-                      setSelectedSession(session.id);
-                      setIsDropdownOpen(false);
-                    }}
-                    className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent first:rounded-t-lg last:rounded-b-lg"
-                  >
-                    <div className="font-medium text-card-foreground">{t(session.id, session.name)}</div>
-                    <div className="text-xs text-muted-foreground">{session.year} - {t(session.semester, session.semester)} - {t(session.session, session.session)}</div>
-                  </button>
-                ))}
-              </div>
-            )}
-          </div>
-        </div>
-      </div>
-
-      {/* Applications Section */}
-      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-        <div className="bg-primary text-white px-6 py-4">
-          <h2 className="text-xl font-bold">{t('registered_exams', 'Пријавени испити')}</h2>
-        </div>
-
-        <div className="overflow-x-auto">
-          <table className="w-full">
-            <thead className="bg-accent">
-              <tr>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('serial_number', 'Сериски број')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('code', 'Код')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('subject', 'Предмет')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('completed', 'Завршена')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('fee', 'Таксени')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date', 'Датум')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('instructor', 'Наставник')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('decade', 'Декада')}</th>
-              </tr>
-            </thead>
-            <tbody className="divide-y divide-border">
-              {applications.map((application) => (
-                <tr key={application.id} className="hover:bg-accent transition-colors">
-                  <TableCell className="font-medium text-card-foreground">{application.id}</TableCell>
-                  <TableCell>
-                    <span className="font-mono text-sm text-primary font-medium hover:underline cursor-pointer">
-                      {application.serviceNumber}
-                    </span>
-                  </TableCell>
-                  <TableCell className="font-mono text-sm font-medium">{application.code}</TableCell>
-                  <TableCell className="font-medium text-card-foreground max-w-xs">
-                    <div className="flex items-center gap-2">
-                      <FontAwesomeIcon icon={faFileText} className="w-4 h-4 text-primary" />
-                      {t(application.subject, application.subject)}
-                    </div>
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <CompletedBadge completed={application.completed} />
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <FeeBadge fee={application.fee} />
-                  </TableCell>
-                  <TableCell className="text-muted-foreground font-medium">{application.date}</TableCell>
-                  <TableCell>
-                    <div className="flex items-center gap-2">
-                      <FontAwesomeIcon icon={faUser} className="w-4 h-4 text-muted-foreground" />
-                      <span className="font-medium text-card-foreground">{t(application.instructor, application.instructor)}</span>
-                    </div>
-                  </TableCell>
-                  <TableCell className="text-center font-medium text-primary">{application.decade}</TableCell>
-                </tr>
-              ))}
-            </tbody>
-          </table>
-        </div>
-
-        {/* Important Note */}
-        <div className="bg-blue-50 border-t border-blue-100 p-6">
-          <div className="flex items-start gap-3">
-            <FontAwesomeIcon icon={faInfoCircle} className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
-            <div>
-              <h3 className="font-medium text-blue-900 mb-1">{t('important_note', 'Важна забелешка')}</h3>
-              <p className="text-sm text-blue-800 leading-relaxed">
-                {t('applications_important_note_text')}
-              </p>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      {/* Statistics Cards */}
-      <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-blue-100 text-blue-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faFileText} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('registered_exams', 'Пријавени испити')}</h3>
-              <p className="text-2xl font-bold text-blue-600">
-                {applications.length}
-              </p>
-            </div>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-green-100 text-green-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('completed', 'Завршени')}</h3>
-              <p className="text-2xl font-bold text-green-600">
-                {applications.filter(app => app.completed === 'Да').length}
-              </p>
-            </div>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-yellow-100 text-yellow-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faMoneyBillWave} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('total_fee', 'Вкупна такса')}</h3>
-              <p className="text-2xl font-bold text-yellow-600">
-                {applications.reduce((sum, app) => sum + parseFloat(app.fee.replace(',', '.')), 0).toFixed(2)}
-              </p>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/students/documents/page.tsx
===================================================================
--- src/app/students/documents/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,447 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { 
-  faFilePdf, 
-  faChevronDown,
-  faCheckCircle,
-  faClock,
-  faMoneyBillWave,
-  faFileText,
-  faChevronLeft,
-  faChevronRight,
-  faAngleDoubleLeft,
-  faAngleDoubleRight,
-  faSpinner
-} from '@fortawesome/free-solid-svg-icons';
-import { useState } from 'react';
-import documentsData from '@/data/documents.json';
-import { useTranslation } from 'react-i18next';
-import { getAccessToken } from '@/lib/auth';
-import { downloadDocumentPDF } from '@/lib/pdf-generators';
-
-interface TableCellProps {
-  children: React.ReactNode;
-  className?: string;
-}
-
-const TableCell = ({ children, className = "" }: TableCellProps) => (
-  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
-    {children}
-  </td>
-);
-
-const StatusBadge = ({ status }: { status: string }) => {
-  const { t } = useTranslation();
-  if (status === 'approved' || status === t('approved', 'Одобрено')) {
-    return (
-      <span className="inline-flex items-center justify-center w-8 h-8 bg-green-100 text-green-600 rounded-full">
-        <FontAwesomeIcon icon={faCheckCircle} className="w-5 h-5" />
-      </span>
-    );
-  }
-  if (status === 'pending') {
-    return (
-      <span className="inline-flex items-center gap-1 text-xs font-medium text-yellow-700 bg-yellow-100 px-2 py-1 rounded-full">
-        <FontAwesomeIcon icon={faClock} className="w-3 h-3" />
-        {t('pending', 'Во обработка')}
-      </span>
-    );
-  }
-  return (
-    <span className="inline-flex items-center justify-center w-8 h-8 bg-accent text-muted-foreground rounded-full">
-      <FontAwesomeIcon icon={faFileText} className="w-4 h-4" />
-    </span>
-  );
-};
-
-const PriceBadge = ({ price }: { price: number }) => {
-  const { t } = useTranslation();
-  if (price === 0) {
-    return <span className="font-medium text-green-600">{t('free', '0,00')}</span>;
-  }
-  return <span className="font-medium text-blue-600">{price.toFixed(2)}</span>;
-};
-
-interface DocumentRecord {
-  id: number;
-  archive: string;
-  date: string;
-  request: string;
-  price: number;
-  paid: string;
-  document: string;
-  payOnline: boolean;
-  status: string;
-  comment: string;
-}
-
-export default function DocumentsPage() {
-  const [selectedDocumentType, setSelectedDocumentType] = useState("select_document");
-  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
-  const [comment, setComment] = useState("");
-  const [currentPage, setCurrentPage] = useState(1);
-  const [recordsPerPage, setRecordsPerPage] = useState(15);
-  const [downloadingId, setDownloadingId] = useState<number | null>(null);
-  const [documents, setDocuments] = useState<DocumentRecord[]>(documentsData.documents as DocumentRecord[]);
-  const [isSubmitting, setIsSubmitting] = useState(false);
-  const { t } = useTranslation();
-
-  const handleDownload = async (docId: number, request: string, archive: string, date: string) => {
-    const token = getAccessToken();
-    if (!token) {
-      alert(t('not_authenticated', 'Не сте најавени. Ве молиме најавете се повторно.'));
-      return;
-    }
-    setDownloadingId(docId);
-    try {
-      await downloadDocumentPDF(request, archive, date, token);
-    } catch (err) {
-      console.error('PDF generation error:', err);
-      alert(t('pdf_error', 'Грешка при генерирање на документот. Обидете се повторно.'));
-    } finally {
-      setDownloadingId(null);
-    }
-  };
-
-  const handleSubmit = () => {
-    if (selectedDocumentType === "select_document") return;
-
-    const docType = documentsData.documentTypes.find(d => d.id === selectedDocumentType);
-    if (!docType) return;
-
-    setIsSubmitting(true);
-
-    // Generate archive number (random 5-digit)
-    const archiveNumber = String(90000 + Math.floor(Math.random() * 10000));
-
-    // Current date in DD.MM.YYYY format
-    const now = new Date();
-    const dateStr = `${String(now.getDate()).padStart(2, '0')}.${String(now.getMonth() + 1).padStart(2, '0')}.${now.getFullYear()}`;
-
-    const newDoc: DocumentRecord = {
-      id: documents.length > 0 ? Math.max(...documents.map(d => d.id)) + 1 : 1,
-      archive: archiveNumber,
-      date: dateStr,
-      request: docType.name,
-      price: docType.price,
-      paid: "Не",
-      document: "Преземи",
-      payOnline: docType.price > 0,
-      status: "pending",
-      comment: comment,
-    };
-
-    setDocuments(prev => [newDoc, ...prev]);
-    setSelectedDocumentType("select_document");
-    setComment("");
-    setIsSubmitting(false);
-    alert(t('document_submitted', 'Барањето за документ е успешно поднесено!'));
-  };
-
-  const selectedDocument = documentsData.documentTypes.find(d => d.id === selectedDocumentType);
-  const { paymentInfo } = documentsData;
-
-  const totalPages = Math.ceil(documents.length / recordsPerPage);
-  const startIndex = (currentPage - 1) * recordsPerPage;
-  const endIndex = startIndex + recordsPerPage;
-  const currentDocuments = documents.slice(startIndex, endIndex);
-
-  return (
-    <div className="min-h-screen pb-8">
-      {/* Header */}
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex items-center gap-4">
-          <div className="bg-white rounded-full p-4">
-            <FontAwesomeIcon icon={faFilePdf} className="text-3xl text-[#0272D1]" />
-          </div>
-          <div>
-            <h1 className="text-3xl font-bold mb-2">{t('documents')}</h1>
-            <p className="text-lg opacity-90">
-              {t('documents_overview', 'Преглед на вашите документи и нивниот статус.')}
-            </p>
-          </div>
-        </div>
-      </div>
-
-      {/* Document Request Form */}
-      <div className="bg-card rounded-xl p-6 shadow-sm border border-border mb-8">
-        <h2 className="text-lg font-semibold text-card-foreground mb-6 flex items-center gap-2">
-          <FontAwesomeIcon icon={faFileText} className="text-primary" />
-          {t('new_document_request', 'Ново барање за документ')}
-        </h2>
-        
-        <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
-          {/* Document Type Selection */}
-          <div>
-            <label className="block text-sm font-medium text-muted-foreground mb-2">
-              {t('select_document', 'Избери документ')}:
-            </label>
-            <div className="relative">
-              <button
-                onClick={() => setIsDropdownOpen(!isDropdownOpen)}
-                className="w-full bg-card border border-border rounded-lg px-4 py-3 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
-              >
-                <div className="flex items-center justify-between">
-                  <span className="text-sm text-card-foreground truncate">
-                    {selectedDocument ? t(selectedDocument.id) : t('select_document', 'Избери документ')}
-                  </span>
-                  <FontAwesomeIcon 
-                    icon={faChevronDown} 
-                    className={`w-4 h-4 text-muted-foreground transition-transform ml-2 flex-shrink-0 ${isDropdownOpen ? 'rotate-180' : ''}`}
-                  />
-                </div>
-              </button>
-              
-              {isDropdownOpen && (
-                <div className="absolute z-10 w-full mt-1 bg-card border border-border rounded-lg shadow-lg max-h-80 overflow-y-auto">
-                  {documentsData.documentTypes.map((docType) => (
-                    <button
-                      key={docType.id}
-                      onClick={() => {
-                        setSelectedDocumentType(docType.id);
-                        setIsDropdownOpen(false);
-                      }}
-                      className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent border-b border-border last:border-b-0"
-                    >
-                      <div className="font-medium text-card-foreground">{t(docType.id)}</div>
-                      {docType.price > 0 && (
-                        <div className="text-xs text-blue-600 mt-1">{t('price', 'Цена')}: {docType.price} мкд</div>
-                      )}
-                    </button>
-                  ))}
-                </div>
-              )}
-            </div>
-          </div>
-
-          {/* Comment Section */}
-          <div>
-            <label className="block text-sm font-medium text-muted-foreground mb-2">
-              {t('comment', 'Коментар')}:
-            </label>
-            <textarea
-              value={comment}
-              onChange={(e) => setComment(e.target.value)}
-              rows={4}
-              className="w-full border border-border rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary resize-none"
-              placeholder={t('add_comment', 'Додај коментар')}
-            />
-          </div>
-        </div>
-
-        <div className="flex justify-end mt-6">
-          <button
-            onClick={handleSubmit}
-            className="bg-primary hover:bg-blue-700 text-white font-medium py-2 px-6 rounded-lg transition-colors duration-200 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
-            disabled={selectedDocumentType === "select_document" || isSubmitting}
-          >
-            <FontAwesomeIcon icon={isSubmitting ? faSpinner : faFileText} className={`w-4 h-4 ${isSubmitting ? 'animate-spin' : ''}`} />
-            {isSubmitting ? t('submitting', 'Се поднесува...') : t('submit', 'Поднеси')}
-          </button>
-        </div>
-      </div>
-
-      {/* Documents Table */}
-      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-        <div className="bg-primary text-white px-6 py-4">
-          <h2 className="text-xl font-bold">{t('my_documents', 'Мои документи')}</h2>
-        </div>
-        
-        <div className="overflow-x-auto">
-          <table className="w-full">
-            <thead className="bg-accent">
-              <tr>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('archive', 'Архива')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date', 'Датум')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('request', 'Барање')}</th>
-                <th className="px-4 py-4 text-right text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('price', 'Цена')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('paid', 'Платено')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('document', 'Документ')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('pay_online', 'Плати онлајн')}</th>
-                <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('status', 'Статус')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('comment', 'Коментар')}</th>
-              </tr>
-            </thead>
-            <tbody className="divide-y divide-border">
-              {currentDocuments.map((document) => (
-                <tr key={document.id} className="hover:bg-accent transition-colors">
-                  <TableCell className="font-medium text-card-foreground">{document.id}</TableCell>
-                  <TableCell className="font-mono text-sm text-primary font-medium">{document.archive}</TableCell>
-                  <TableCell className="text-muted-foreground">{document.date}</TableCell>
-                  <TableCell className="font-medium text-card-foreground max-w-xs">
-                    {t(document.request)}
-                  </TableCell>
-                  <TableCell className="text-right">
-                    <PriceBadge price={document.price} />
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <span className={`text-sm font-medium ${document.paid === 'ДА' ? 'text-green-600' : 'text-red-500'}`}>
-                      {document.paid}
-                    </span>
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <button 
-                      onClick={() => handleDownload(document.id, document.request, document.archive, document.date)}
-                      disabled={downloadingId === document.id}
-                      className="text-primary hover:text-blue-700 font-medium text-sm underline disabled:opacity-50 disabled:cursor-wait inline-flex items-center gap-1"
-                    >
-                      {downloadingId === document.id ? (
-                        <>
-                          <FontAwesomeIcon icon={faSpinner} className="w-3 h-3 animate-spin" />
-                          {t('generating', 'Генерира...')}
-                        </>
-                      ) : (
-                        t('download', document.document)
-                      )}
-                    </button>
-                  </TableCell>
-                  <TableCell className="text-center">
-                    {document.payOnline ? (
-                      <FontAwesomeIcon icon={faCheckCircle} className="w-5 h-5 text-green-600" />
-                    ) : (
-                      <span className="text-muted-foreground">{t('none', '—')}</span>
-                    )}
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <StatusBadge status={document.status} />
-                  </TableCell>
-                  <TableCell>
-                    {document.comment || (
-                      <span className="text-muted-foreground">{t('none', '—')}</span>
-                    )}
-                  </TableCell>
-                </tr>
-              ))}
-            </tbody>
-          </table>
-        </div>
-
-        {/* Pagination */}
-        <div className="bg-accent px-6 py-4 flex items-center justify-between border-t border-border">
-          <div className="flex items-center gap-4 text-sm text-muted-foreground">
-            <div className="flex items-center gap-2">
-              <span>{t('show_rows', 'Прикажи редови')}:</span>
-              <select
-                value={recordsPerPage}
-                onChange={(e) => setRecordsPerPage(Number(e.target.value))}
-                className="border border-border rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-primary"
-              >
-                <option value={15}>15</option>
-                <option value={25}>25</option>
-                <option value={50}>50</option>
-              </select>
-            </div>
-            <div>
-              {t('page', 'Страница')} <input
-                type="number"
-                min="1"
-                max={totalPages}
-                value={currentPage}
-                onChange={(e) => setCurrentPage(Number(e.target.value))}
-                className="w-12 border border-border rounded px-2 py-1 text-sm text-center focus:outline-none focus:ring-1 focus:ring-primary"
-              /> {t('of', 'од')} {totalPages}
-            </div>
-          </div>
-
-          <div className="flex items-center gap-2">
-            <button
-              onClick={() => setCurrentPage(1)}
-              disabled={currentPage === 1}
-              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
-            >
-              <FontAwesomeIcon icon={faAngleDoubleLeft} className="w-4 h-4" />
-            </button>
-            <button
-              onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
-              disabled={currentPage === 1}
-              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
-            >
-              <FontAwesomeIcon icon={faChevronLeft} className="w-4 h-4" />
-            </button>
-            <span className="px-4 py-2 bg-primary text-white rounded text-sm font-medium">
-              {t('first', 'Прва')}
-            </span>
-            <button
-              onClick={() => setCurrentPage(Math.min(totalPages, currentPage + 1))}
-              disabled={currentPage === totalPages}
-              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
-            >
-              <FontAwesomeIcon icon={faChevronRight} className="w-4 h-4" />
-            </button>
-            <button
-              onClick={() => setCurrentPage(totalPages)}
-              disabled={currentPage === totalPages}
-              className="p-2 text-muted-foreground hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
-            >
-              <FontAwesomeIcon icon={faAngleDoubleRight} className="w-4 h-4" />
-            </button>
-            <span className="ml-4 text-sm text-muted-foreground">
-              {t('last', 'Последна')}
-            </span>
-          </div>
-
-          <div className="text-sm text-muted-foreground">
-            {t('total', 'Вкупно')}: {documents.length}
-          </div>
-        </div>
-
-        {/* Payment Info */}
-        <div className="bg-blue-50 border-t border-blue-100 p-4">
-          <div className="flex items-start gap-3">
-            <FontAwesomeIcon icon={faMoneyBillWave} className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
-            <p className="text-sm text-blue-800 leading-relaxed">
-              {t('documents_payment_info', paymentInfo)}
-            </p>
-          </div>
-        </div>
-      </div>
-
-      {/* Statistics Cards */}
-      <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-blue-100 text-blue-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faFileText} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('total_documents', 'Вкупно документи')}</h3>
-              <p className="text-2xl font-bold text-blue-600">
-                {documents.length}
-              </p>
-            </div>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-green-100 text-green-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('approved', 'Одобрени')}</h3>
-              <p className="text-2xl font-bold text-green-600">
-                {documents.filter(doc => doc.status === "approved").length}
-              </p>
-            </div>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-yellow-100 text-yellow-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faMoneyBillWave} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('total_price', 'Вкупна цена')}</h3>
-              <p className="text-2xl font-bold text-yellow-600">
-                {documents.reduce((sum, doc) => sum + doc.price, 0).toFixed(2)} {t('mkd', 'мкд')}
-              </p>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/students/exams/page.tsx
===================================================================
--- src/app/students/exams/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,7 +1,0 @@
-import Exams from "@/components/exams";
-
-export default function ExamsPage() {
-  return (
-    <Exams></Exams>
-  );
-}
Index: c/app/students/layout.tsx
===================================================================
--- src/app/students/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,40 +1,0 @@
-import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
-import "../globals.css";
-import "@fortawesome/fontawesome-svg-core/styles.css";
-import { config } from "@fortawesome/fontawesome-svg-core";
-import Header from "@/components/header";
-import Navbar from "@/components/navbar";
-
-// Prevent FontAwesome from adding CSS automatically
-config.autoAddCss = false;
-
-const geistSans = Geist({
-  variable: "--font-geist-sans",
-  subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
-  variable: "--font-geist-mono",
-  subsets: ["latin"],
-});
-
-export const metadata: Metadata = {
-  title: "IKnow - UKIM",
-  description:
-    "University Managment System used to provide students informations and manage their progress.",
-};
-
-export default function RootLayout({
-  children,
-}: Readonly<{
-  children: React.ReactNode;
-}>) {
-  return (
-    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
-      <Header />
-      <Navbar />
-      {children}
-    </div>
-  );
-}
Index: c/app/students/page.tsx
===================================================================
--- src/app/students/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,5 +1,0 @@
-import { redirect } from "next/navigation";
-
-export default function StudentsHome() {
-  redirect("/students/profile");
-}
Index: c/app/students/profile/page.tsx
===================================================================
--- src/app/students/profile/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,338 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { 
-  faUser, 
-  faIdCard, 
-  faGraduationCap, 
-  faAddressCard, 
-  faSchool,
-  faCalendarAlt,
-  faFlag,
-  faVenus,
-  faMars,
-  faEnvelope,
-  faPhone,
-  faMapMarkerAlt,
-  faPassport
-} from '@fortawesome/free-solid-svg-icons';
-import { useEffect, useState } from 'react';
-import { getAccessToken } from '@/lib/auth';
-import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
-import { useTranslation } from 'react-i18next';
-import { apiUrl } from '@/lib/api';
-
-type PersonalInfo = {
-  firstName: string;
-  middleName: string;
-  lastName: string;
-  maidenName: string;
-  dateOfBirth: string;
-  gender: string;
-  nationality: string;
-  citizenship: string;
-  scholarship: string;
-  currentPlan: string;
-  registryNumber: string;
-  studyGroup: string;
-  notes?: string;
-  index: string;
-  embg: string;
-};
-
-type BirthInfo = {
-  placeOfBirth: string;
-  municipalityOfBirth: string;
-  country: string;
-};
-
-type PreviousEducation = {
-  type: string;
-  profession: string;
-  average: string | number;
-  language: string;
-  country: string;
-  previousUniversity: string;
-  previousFaculty: string;
-  previousStudyMode: string;
-};
-
-type EnrollmentInfo = {
-  enrollmentYear: string | number;
-  status: string;
-  cycle: string;
-  program: string;
-  quota: string;
-  secondaryEducationNumber: string;
-  previousEducationCredits: string | number;
-};
-
-type Contact = {
-  placeOfResidence: string;
-  municipalityOfResidence: string;
-  country: string;
-  address: string;
-  temporaryAddress: string;
-  phone: string;
-  mobilePhone: string;
-  passportNumber: string;
-  passportExpiryDate: string;
-  email: string;
-  microsoftEmail: string;
-};
-
-type StudentProfile = {
-  personalInfo: PersonalInfo;
-  birthInfo: BirthInfo;
-  previousEducation: PreviousEducation;
-  enrollmentInfo: EnrollmentInfo;
-  contact: Contact;
-};
-
-interface InfoRowProps {
-  label: string;
-  value: string | number;
-  icon?: IconDefinition;
-}
-
-const InfoRow = ({ label, value, icon }: InfoRowProps) => {
-  const { t } = useTranslation();
-  return (
-    <div className="flex justify-between items-center py-3 border-b border-border last:border-b-0">
-      <div className="flex items-center gap-2 text-muted-foreground font-medium">
-        {icon && <FontAwesomeIcon icon={icon} className="w-4 h-4" />}
-        <span>{t(label)}:</span>
-      </div>
-      <div className="text-card-foreground font-semibold text-right max-w-xs break-words">
-        {value || t('n_a')}
-      </div>
-    </div>
-  );
-};
-
-interface SectionProps {
-  title: string;
-  icon: IconDefinition;
-  children: React.ReactNode;
-}
-
-const Section = ({ title, icon, children }: SectionProps) => {
-  const { t } = useTranslation();
-  return (
-    <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-      <div className="bg-primary text-white px-6 py-4">
-        <div className="flex items-center gap-3">
-          <FontAwesomeIcon icon={icon} className="text-xl" />
-          <h2 className="text-xl font-bold">{t(title)}</h2>
-        </div>
-      </div>
-      <div className="p-6">
-        {children}
-      </div>
-    </div>
-  );
-};
-
-export default function ProfilePage() {
-  const [studentData, setStudentData] = useState<StudentProfile | null>(null);
-  const [isLoading, setIsLoading] = useState(true);
-  const [errorMessage, setErrorMessage] = useState<string | null>(null);
-  const { t } = useTranslation();
-
-  useEffect(() => {
-    let cancelled = false;
-
-    async function load() {
-      setIsLoading(true);
-      setErrorMessage(null);
-
-      const token = getAccessToken();
-      if (!token) {
-        setErrorMessage('Not authenticated. Please login again.');
-        setIsLoading(false);
-        return;
-      }
-
-      try {
-        const response = await fetch(apiUrl('/api/user/getUser'), {
-          method: 'GET',
-          headers: {
-            Authorization: `Bearer ${token}`,
-          },
-        });
-
-        if (!response.ok) {
-          const text = await response.text().catch(() => '');
-          throw new Error(text || `Failed to load profile (${response.status})`);
-        }
-
-        const data = (await response.json()) as StudentProfile;
-        if (!cancelled) setStudentData(data);
-      } catch (err) {
-        if (!cancelled) {
-          setErrorMessage(err instanceof Error ? err.message : 'Failed to load profile.');
-        }
-      } finally {
-        if (!cancelled) setIsLoading(false);
-      }
-    }
-
-    void load();
-
-    return () => {
-      cancelled = true;
-    };
-  }, []);
-
-  if (isLoading) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="bg-card rounded-xl shadow-sm border border-border p-6">
-          {t('loading')}
-        </div>
-      </div>
-    );
-  }
-
-  if (errorMessage || !studentData) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
-          {errorMessage ?? t('failed_to_load_profile')}
-        </div>
-      </div>
-    );
-  }
-
-  const { personalInfo, birthInfo, previousEducation, enrollmentInfo, contact } = studentData;
-
-  return (
-    <div className="min-h-screen pb-8">
-      {/* Header */}
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex items-center gap-6">
-          <div className="relative">
-            <div className="w-20 h-20 bg-white rounded-full flex items-center justify-center border-2 border-white shadow-lg">
-              <FontAwesomeIcon icon={faUser} className="text-3xl text-[#0272D1]" />
-            </div>
-            <div className="absolute -bottom-1 -right-1 w-6 h-6 bg-green-500 rounded-full border-2 border-white"></div>
-          </div>
-          <div>
-            <h1 className="text-3xl font-bold mb-2">
-              {personalInfo.firstName} {personalInfo.middleName} {personalInfo.lastName}
-            </h1>
-            <div className="text-lg opacity-90">
-              {t('index')}: {personalInfo.index} | {t('embg')}: {personalInfo.embg}
-            </div>
-            <div className="text-base opacity-80 mt-1">
-              {enrollmentInfo.program}
-            </div>
-          </div>
-        </div>
-      </div>
-
-      {/* Profile Sections */}
-      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
-        
-        {/* Personal Information */}
-        <Section title="personal_info" icon={faIdCard}>
-          <InfoRow label="first_name" value={personalInfo.firstName} />
-          <InfoRow label="middle_name" value={personalInfo.middleName} />
-          <InfoRow label="last_name" value={personalInfo.lastName} />
-          <InfoRow label="maiden_name" value={personalInfo.maidenName} />
-          <InfoRow 
-            label="date_of_birth" 
-            value={personalInfo.dateOfBirth} 
-            icon={faCalendarAlt} 
-          />
-          <InfoRow 
-            label="gender" 
-            value={personalInfo.gender} 
-            icon={personalInfo.gender === t('male') ? faMars : faVenus} 
-          />
-          <InfoRow 
-            label="nationality" 
-            value={personalInfo.nationality} 
-            icon={faFlag} 
-          />
-          <InfoRow label="citizenship" value={personalInfo.citizenship} />
-          <InfoRow label="scholarship" value={personalInfo.scholarship} />
-          <InfoRow label="current_plan" value={personalInfo.currentPlan} />
-          <InfoRow label="registry_number" value={personalInfo.registryNumber} />
-          <InfoRow label="study_group" value={personalInfo.studyGroup} />
-          {personalInfo.notes && (
-            <div className="mt-4 p-4 bg-blue-50 rounded-lg">
-              <div className="text-sm font-medium text-blue-800 mb-1">{t('note')}:</div>
-              <div className="text-sm text-blue-700">{personalInfo.notes}</div>
-            </div>
-          )}
-        </Section>
-
-        {/* Birth Information */}
-        <Section title="birth_info" icon={faMapMarkerAlt}>
-          <InfoRow label="place_of_birth" value={birthInfo.placeOfBirth} />
-          <InfoRow label="municipality_of_birth" value={birthInfo.municipalityOfBirth} />
-          <InfoRow label="country" value={birthInfo.country} />
-        </Section>
-
-        {/* Previous Education */}
-        <Section title="previous_education" icon={faSchool}>
-          <InfoRow label="type" value={previousEducation.type} />
-          <InfoRow label="profession" value={previousEducation.profession} />
-          <InfoRow label="average" value={previousEducation.average} />
-          <InfoRow label="language" value={previousEducation.language} />
-          <InfoRow label="country" value={previousEducation.country} />
-          <InfoRow label="previous_university" value={previousEducation.previousUniversity} />
-          <InfoRow label="previous_faculty" value={previousEducation.previousFaculty} />
-          <InfoRow label="previous_study_mode" value={previousEducation.previousStudyMode} />
-        </Section>
-
-        {/* Enrollment Information */}
-        <Section title="enrollment_info" icon={faGraduationCap}>
-          <InfoRow label="enrollment_year" value={enrollmentInfo.enrollmentYear} />
-          <InfoRow label="status" value={enrollmentInfo.status} />
-          <InfoRow label="cycle" value={enrollmentInfo.cycle} />
-          <InfoRow label="program" value={enrollmentInfo.program} />
-          <InfoRow label="quota" value={enrollmentInfo.quota} />
-          <InfoRow label="secondary_education_number" value={enrollmentInfo.secondaryEducationNumber} />
-          <InfoRow label="previous_education_credits" value={enrollmentInfo.previousEducationCredits} />
-        </Section>
-
-        {/* Contact Information */}
-        <div className="lg:col-span-2">
-          <Section title="contact" icon={faAddressCard}>
-            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
-              <div>
-                <InfoRow 
-                  label="place_of_residence" 
-                  value={contact.placeOfResidence} 
-                  icon={faMapMarkerAlt} 
-                />
-                <InfoRow label="municipality_of_residence" value={contact.municipalityOfResidence} />
-                <InfoRow label="country" value={contact.country} />
-                <InfoRow label="address" value={contact.address} />
-                <InfoRow label="temporary_address" value={contact.temporaryAddress} />
-              </div>
-              <div>
-                <InfoRow label="phone" value={contact.phone} icon={faPhone} />
-                <InfoRow label="mobile_phone" value={contact.mobilePhone} icon={faPhone} />
-                <InfoRow label="passport_number" value={contact.passportNumber} icon={faPassport} />
-                <InfoRow label="passport_expiry_date" value={contact.passportExpiryDate} />
-                <InfoRow 
-                  label="email" 
-                  value={contact.email} 
-                  icon={faEnvelope} 
-                />
-                <InfoRow 
-                  label="microsoft_email" 
-                  value={contact.microsoftEmail} 
-                  icon={faEnvelope} 
-                />
-              </div>
-            </div>
-          </Section>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/app/students/semesters/page.tsx
===================================================================
--- src/app/students/semesters/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,397 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { 
-  faCalendarAlt, 
-  faCheck, 
-  faTimes, 
-  faFileAlt, 
-  faMoneyBillWave,
-  faSignature,
-  faCheckCircle,
-  faTimesCircle
-} from '@fortawesome/free-solid-svg-icons';
-import { useEffect, useState } from 'react';
-import { getAccessToken } from '@/lib/auth';
-import { useTranslation } from 'react-i18next';
-import { apiUrl } from '@/lib/api';
-import EnrollSemesterDialog from '@/components/enroll-semester-dialog';
-
-type Semester = {
-  id: number | string;
-  semester: string;
-  direction: string;
-  quota: string;
-  note: string;
-  studentCom: string;
-  sum: string;
-  paid: string;
-  ukim: string;
-  createdOn: string;
-  dateChanged: string;
-  credits: string;
-  type: string;
-  doc: string;
-  doc1: string;
-  verified: string;
-  taxes: string;
-  signatures: string;
-  status: string;
-  completed: string;
-};
-
-type SemestersResponse = {
-  semesters: Semester[];
-};
-
-interface TableCellProps {
-  children: React.ReactNode;
-  className?: string;
-}
-
-const TableCell = ({ children, className = "" }: TableCellProps) => (
-  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
-    {children}
-  </td>
-);
-
-const StatusBadge = ({ status }: { status: string }) => {
-  const { t } = useTranslation();
-  const baseClasses = "px-2 py-1 rounded-full text-xs font-medium";
-  if (status === 'Валидно') {
-    return (
-      <span className={`${baseClasses} bg-green-100 text-green-800 flex items-center gap-1`}>
-        <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
-        {t('Валидно', 'Валидно')}
-      </span>
-    );
-  }
-  return (
-    <span className={`${baseClasses} bg-accent text-gray-800`}>
-      {t(status, status)}
-    </span>
-  );
-};
-
-const YesNoBadge = ({ value }: { value: string }) => {
-  const { t } = useTranslation();
-  if (value === 'Да') {
-    return (
-      <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full">
-        <FontAwesomeIcon icon={faCheck} className="w-3 h-3" />
-      </span>
-    );
-  } else if (value === 'Не') {
-    return (
-      <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full">
-        <FontAwesomeIcon icon={faTimes} className="w-3 h-3" />
-      </span>
-    );
-  }
-  return <span className="text-muted-foreground">—</span>;
-};
-
-const SignatureBadge = ({ signatures }: { signatures: string }) => {
-  const [completed, total] = signatures.split('/').map(Number);
-  const percentage = total > 0 ? (completed / total) * 100 : 0;
-  
-  let colorClass = "text-red-600 bg-red-100";
-  if (percentage === 100) {
-    colorClass = "text-green-600 bg-green-100";
-  } else if (percentage >= 50) {
-    colorClass = "text-yellow-600 bg-yellow-100";
-  }
-  
-  return (
-    <span className={`px-2 py-1 rounded-full text-xs font-medium flex items-center gap-1 ${colorClass}`}>
-      <FontAwesomeIcon icon={faSignature} className="w-3 h-3" />
-      {signatures}
-    </span>
-  );
-};
-
-export default function SemestersPage() {
-  const [semesters, setSemesters] = useState<Semester[]>([]);
-  const [isLoading, setIsLoading] = useState(true);
-  const [errorMessage, setErrorMessage] = useState<string | null>(null);
-  const [enrollOpen, setEnrollOpen] = useState(false);
-  // Bumped after a successful enrolment so the table reloads.
-  const [reloadKey, setReloadKey] = useState(0);
-  const { t } = useTranslation();
-
-  useEffect(() => {
-    let cancelled = false;
-
-    async function load() {
-      setIsLoading(true);
-      setErrorMessage(null);
-
-      const token = getAccessToken();
-      if (!token) {
-        setErrorMessage('Not authenticated. Please login again.');
-        setIsLoading(false);
-        return;
-      }
-
-      try {
-        const response = await fetch(apiUrl('/api/user/getSemesters'), {
-          method: 'GET',
-          headers: {
-            Authorization: `Bearer ${token}`,
-          },
-        });
-
-        if (!response.ok) {
-          const text = await response.text().catch(() => '');
-          throw new Error(text || `Failed to load semesters (${response.status})`);
-        }
-
-        const data = (await response.json()) as SemestersResponse;
-        if (!cancelled) setSemesters(Array.isArray(data?.semesters) ? data.semesters : []);
-      } catch (err) {
-        if (!cancelled) {
-          setErrorMessage(err instanceof Error ? err.message : 'Failed to load semesters.');
-        }
-      } finally {
-        if (!cancelled) setIsLoading(false);
-      }
-    }
-
-    void load();
-
-    return () => {
-      cancelled = true;
-    };
-  }, [reloadKey]);
-
-  if (isLoading) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="bg-card rounded-xl shadow-sm border border-border p-6">
-          {t('loading')}
-        </div>
-      </div>
-    );
-  }
-
-  if (errorMessage) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
-          {errorMessage}
-        </div>
-      </div>
-    );
-  }
-
-  return (
-    <div className="min-h-screen pb-8">
-      {/* Header */}
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
-          <div className="flex items-center gap-4">
-            <div className="bg-white rounded-full p-4">
-              <FontAwesomeIcon icon={faCalendarAlt} className="text-3xl text-[#0272D1]" />
-            </div>
-            <div>
-              <h1 className="text-3xl font-bold mb-2">{t('semesters')}</h1>
-              <p className="text-lg opacity-90">
-                {t('semesters_overview')}
-              </p>
-            </div>
-          </div>
-
-          <button
-            className="self-start rounded-lg bg-white px-5 py-3 font-semibold text-[#0272D1] shadow-sm hover:bg-white/90 md:self-auto"
-            onClick={() => setEnrollOpen(true)}
-          >
-            + {t('enroll_semester')}
-          </button>
-        </div>
-      </div>
-
-      {/* Table Container */}
-      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-        <div className="bg-primary text-white px-6 py-4">
-          <h2 className="text-xl font-bold">{t('semesters_list')}</h2>
-        </div>
-        
-        <div className="overflow-x-auto">
-          <table className="w-full">
-            <thead className="bg-accent">
-              <tr>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('semester')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('direction')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('quota')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('note')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('student_com')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('sum')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('paid')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('ukim')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('created_on')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date_changed')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('credits')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('type')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('doc')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('doc1')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('verified')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('taxes')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('signatures')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('status')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('completed')}</th>
-              </tr>
-            </thead>
-            <tbody className="divide-y divide-border">
-              {semesters.map((semester) => (
-                <tr key={semester.id} className="hover:bg-accent transition-colors">
-                  <TableCell className="font-medium text-card-foreground">{semester.id}</TableCell>
-                  <TableCell className="font-medium text-primary">{semester.semester}</TableCell>
-                  <TableCell>{semester.direction}</TableCell>
-                  <TableCell className="max-w-xs">
-                    <div className="truncate" title={semester.quota}>
-                      {semester.quota}
-                    </div>
-                  </TableCell>
-                  <TableCell>
-                    {semester.note ? (
-                      <span className="text-yellow-600 font-medium" title={semester.note}>
-                        {semester.note.length > 10 ? `${semester.note.substring(0, 10)}...` : semester.note}
-                      </span>
-                    ) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell>
-                    {semester.studentCom ? (
-                      <span className="text-blue-600 font-medium" title={semester.studentCom}>
-                        {semester.studentCom.length > 10 ? `${semester.studentCom.substring(0, 10)}...` : semester.studentCom}
-                      </span>
-                    ) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell className="font-medium">
-                    {semester.sum ? (
-                      <span className="text-green-600 flex items-center gap-1">
-                        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
-                        {semester.sum}
-                      </span>
-                    ) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell className="font-medium">
-                    {semester.paid ? (
-                      <span className="text-green-600 flex items-center gap-1">
-                        <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
-                        {semester.paid}
-                      </span>
-                    ) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell className="font-medium">
-                    {semester.ukim ? (
-                      <span className="text-blue-600">{semester.ukim}</span>
-                    ) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell className="text-muted-foreground">{semester.createdOn}</TableCell>
-                  <TableCell className="text-muted-foreground">{semester.dateChanged}</TableCell>
-                  <TableCell className="font-medium text-primary">{semester.credits}</TableCell>
-                  <TableCell>
-                    <span className="px-2 py-1 bg-blue-100 text-blue-800 rounded-full text-xs font-medium">
-                      {semester.type}
-                    </span>
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <YesNoBadge value={semester.doc} />
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <YesNoBadge value={semester.doc1} />
-                  </TableCell>
-                  <TableCell className="text-center">
-                    <YesNoBadge value={semester.verified} />
-                  </TableCell>
-                  <TableCell className="font-medium text-green-600">{semester.taxes}</TableCell>
-                  <TableCell>
-                    <SignatureBadge signatures={semester.signatures} />
-                  </TableCell>
-                  <TableCell>
-                    <StatusBadge status={semester.status} />
-                  </TableCell>
-                  <TableCell>
-                    {semester.completed !== "Не" ? (
-                      <span className="text-green-600 font-medium flex items-center gap-1">
-                        <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
-                        {t(semester.completed, semester.completed)}
-                      </span>
-                    ) : (
-                      <span className="text-red-600 font-medium flex items-center gap-1">
-                        <FontAwesomeIcon icon={faTimesCircle} className="w-3 h-3" />
-                        {t('Не', 'Не')}
-                      </span>
-                    )}
-                  </TableCell>
-                </tr>
-              ))}
-            </tbody>
-          </table>
-        </div>
-      </div>
-
-      {/* Summary Cards */}
-      <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-green-100 text-green-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('completed_semesters')}</h3>
-              <p className="text-2xl font-bold text-green-600">
-                {semesters.filter(s => s.completed !== "Не").length}
-              </p>
-            </div>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-blue-100 text-blue-600 rounded-full p-3">
-              <FontAwesomeIcon icon={faFileAlt} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('verified_semesters')}</h3>
-              <p className="text-2xl font-bold text-blue-600">
-                {semesters.filter(s => s.verified === "Да").length}
-              </p>
-            </div>
-          </div>
-        </div>
-
-        <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-          <div className="flex items-center gap-4">
-            <div className="bg-primary text-white rounded-full p-3">
-              <FontAwesomeIcon icon={faCalendarAlt} className="text-xl" />
-            </div>
-            <div>
-              <h3 className="text-lg font-bold text-card-foreground">{t('total_semesters')}</h3>
-              <p className="text-2xl font-bold text-primary">
-                {semesters.length}
-              </p>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <EnrollSemesterDialog
-        open={enrollOpen}
-        onClose={() => setEnrollOpen(false)}
-        onEnrolled={() => setReloadKey((k) => k + 1)}
-      />
-    </div>
-  );
-}
Index: c/app/students/subjects/page.tsx
===================================================================
--- src/app/students/subjects/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,529 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { 
-  faBook, 
-  faChevronDown,
-  faFileInvoice
-} from '@fortawesome/free-solid-svg-icons';
-import { useEffect, useState } from 'react';
-import { getAccessToken } from '@/lib/auth';
-import { useTranslation } from 'react-i18next';
-import { apiUrl } from '@/lib/api';
-
-interface Subject {
-  id: number;
-  code: string;
-  hours: string;
-  kojPat: number;
-  name: string;
-  semester: number;
-  status: string;
-  signature: string;
-  group: string;
-  professor: string;
-}
-
-type SemesterInfo = {
-  id: number;
-  name: string;
-  status: string;
-  serviceNumber: string | number;
-};
-
-type FinancialInfo = {
-  sum: string | number;
-  paid: string;
-  due: string;
-  materialCosts: string;
-  credits: string;
-  MKSA: string;
-  electronicRegistration: string;
-  eUKIM: string;
-  bankProvision: string;
-  total: string;
-};
-
-type CurrentSemester = {
-  id: string;
-  name: string;
-  status: string;
-  serviceNumber: string | number;
-  ticketNumber: string;
-  debt: string;
-  financialInfo: FinancialInfo;
-};
-
-type SubjectsResponse = {
-  currentSemester: CurrentSemester;
-  semesters: SemesterInfo[];
-  subjectsBySemester: Record<string, Subject[]>;
-  semesterKeyById: Record<number, string>;
-};
-
-type ApiCurrentSemester = {
-  id: string;
-  name: string;
-  status: string;
-  serviceNumber: string | number;
-  ticketNumber: string;
-  debt: string;
-  financialInfo: {
-    sum: string | number;
-    paid: string;
-    due: string;
-    materialCosts: string;
-    credits: string;
-    totalCredits?: string;
-    mksa?: string;
-    MKSA?: string;
-    electronicRegistration: string;
-    eUKIM: string;
-    bankProvision: string;
-    total: string;
-  };
-};
-
-type ApiSubjectsResponse = {
-  semesters: SemesterInfo[];
-  currentSemester?: ApiCurrentSemester;
-  currentSemestar?: ApiCurrentSemester;
-  subjectsBySemester: Record<string, Subject[]>;
-};
-
-function normalizeKey(input: string) {
-  return input.toLowerCase().replace(/\s|\(|\)|\.|,/g, '');
-}
-
-function detectSeasonFromName(name: string): 'summer' | 'winter' | null {
-  const n = name.toLowerCase();
-  if (n.includes('летен')) return 'summer';
-  if (n.includes('зимски')) return 'winter';
-  return null;
-}
-
-function buildSemesterKeyById(semesters: SemesterInfo[], keys: string[]) {
-  const keyBySeason: Partial<Record<'summer' | 'winter', string>> = {};
-  for (const key of keys) {
-    const k = key.toLowerCase();
-    if (k.includes('summer')) keyBySeason.summer = key;
-    if (k.includes('winter')) keyBySeason.winter = key;
-  }
-
-  const mapping: Record<number, string> = {};
-  for (const s of semesters) {
-    const season = detectSeasonFromName(s.name);
-    const mapped = season ? keyBySeason[season] : undefined;
-    if (mapped) mapping[s.id] = mapped;
-  }
-
-  // Fallback: if we couldn't infer seasons, try matching by normalized names.
-  if (Object.keys(mapping).length === 0) {
-    for (const s of semesters) {
-      const ns = normalizeKey(s.name);
-      const match = keys.find((k) => normalizeKey(k).includes(ns) || ns.includes(normalizeKey(k)));
-      if (match) mapping[s.id] = match;
-    }
-  }
-
-  // Last resort: map in order.
-  if (Object.keys(mapping).length === 0) {
-    semesters.forEach((s, idx) => {
-      if (keys[idx]) mapping[s.id] = keys[idx];
-    });
-  }
-
-  return mapping;
-}
-
-interface TableCellProps {
-  children: React.ReactNode;
-  className?: string;
-}
-
-const TableCell = ({ children, className = "" }: TableCellProps) => (
-  <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
-    {children}
-  </td>
-);
-
-const StatusBadge = ({ status }: { status: string }) => {
-  const { t } = useTranslation();
-  const baseClasses = "px-3 py-1 rounded-md text-xs font-medium";
-  if (status === t('mandatory_short')) {
-    return (
-      <span className={`${baseClasses} bg-blue-100 text-blue-800`}>
-        {t('mandatory_short')}
-      </span>
-    );
-  } else if (status === t('elective_short')) {
-    return (
-      <span className={`${baseClasses} bg-green-100 text-green-800`}>
-        {t('elective_short')}
-      </span>
-    );
-  }
-  return (
-    <span className={`${baseClasses} bg-accent text-gray-800`}>
-      {t(status) || status}
-    </span>
-  );
-};
-
-export default function SubjectsPage() {
-  const [subjectsData, setSubjectsData] = useState<SubjectsResponse | null>(null);
-  const [selectedSemester, setSelectedSemester] = useState<number | null>(null);
-  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
-  const [isLoading, setIsLoading] = useState(true);
-  const [errorMessage, setErrorMessage] = useState<string | null>(null);
-  const { t } = useTranslation();
-
-  useEffect(() => {
-    let cancelled = false;
-
-    async function load() {
-      setIsLoading(true);
-      setErrorMessage(null);
-
-      const token = getAccessToken();
-      if (!token) {
-        setErrorMessage('Not authenticated. Please login again.');
-        setIsLoading(false);
-        return;
-      }
-
-      try {
-        const response = await fetch(apiUrl('/api/user/getSubjects'), {
-          method: 'GET',
-          headers: {
-            Authorization: `Bearer ${token}`,
-          },
-        });
-
-        if (!response.ok) {
-          const text = await response.text().catch(() => '');
-          throw new Error(text || `Failed to load subjects (${response.status})`);
-        }
-
-        const apiData = (await response.json()) as ApiSubjectsResponse;
-        if (cancelled) return;
-
-        const current = apiData.currentSemester ?? apiData.currentSemestar;
-        if (!current) {
-          throw new Error('Response missing currentSemestar/currentSemester');
-        }
-
-        const keys = Object.keys(apiData.subjectsBySemester ?? {});
-        const semesterKeyById = buildSemesterKeyById(apiData.semesters ?? [], keys);
-
-        const normalized: SubjectsResponse = {
-          semesters: apiData.semesters ?? [],
-          subjectsBySemester: apiData.subjectsBySemester ?? {},
-          semesterKeyById,
-          currentSemester: {
-            id: current.id,
-            name: current.name,
-            status: current.status,
-            serviceNumber: current.serviceNumber,
-            ticketNumber: current.ticketNumber,
-            debt: current.debt,
-            financialInfo: {
-              sum: current.financialInfo.sum,
-              paid: current.financialInfo.paid,
-              due: current.financialInfo.due,
-              materialCosts: current.financialInfo.materialCosts,
-              credits: current.financialInfo.credits,
-              MKSA: current.financialInfo.MKSA ?? current.financialInfo.mksa ?? '',
-              electronicRegistration: current.financialInfo.electronicRegistration,
-              eUKIM: current.financialInfo.eUKIM,
-              bankProvision: current.financialInfo.bankProvision,
-              total: current.financialInfo.total,
-            },
-          },
-        };
-
-        setSubjectsData(normalized);
-
-        setSelectedSemester((prev) => {
-          if (prev !== null) return prev;
-          const season = detectSeasonFromName(current.name);
-          if (season) {
-            const key = keys.find((k) => k.toLowerCase().includes(season));
-            if (key) {
-              const matchId = normalized.semesters.find((s) => normalized.semesterKeyById[s.id] === key)?.id;
-              if (typeof matchId === 'number') return matchId;
-            }
-          }
-          return normalized.semesters[0]?.id ?? null;
-        });
-      } catch (err) {
-        if (!cancelled) {
-          setErrorMessage(err instanceof Error ? err.message : 'Failed to load subjects.');
-        }
-      } finally {
-        if (!cancelled) setIsLoading(false);
-      }
-    }
-
-    void load();
-
-    return () => {
-      cancelled = true;
-    };
-  }, []);
-
-  if (isLoading) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="bg-card rounded-xl shadow-sm border border-border p-6">
-          {t('loading')}
-        </div>
-      </div>
-    );
-  }
-
-  if (errorMessage || !subjectsData || selectedSemester === null) {
-    return (
-      <div className="min-h-screen pb-8">
-        <div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
-          {errorMessage ?? t('failed_to_load_subjects')}
-        </div>
-      </div>
-    );
-  }
-  
-  const currentSemesterData =
-    subjectsData.semesters.find((s) => s.id === selectedSemester) ?? subjectsData.semesters[0];
-  const semesterKey =
-    subjectsData.semesterKeyById[selectedSemester] ??
-    Object.keys(subjectsData.subjectsBySemester)[0];
-  const currentSubjects: Subject[] = semesterKey ? subjectsData.subjectsBySemester[semesterKey] || [] : [];
-  const { currentSemester } = subjectsData;
-
-  return (
-    <div className="min-h-screen pb-8">
-      {/* Header */}
-      <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex items-center gap-4">
-          <div className="bg-white rounded-full p-4">
-            <FontAwesomeIcon icon={faBook} className="text-3xl text-[#0272D1]" />
-          </div>
-          <div>
-            <h1 className="text-3xl font-bold mb-2">{t('subjects')}</h1>
-            <p className="text-lg opacity-90">
-              {t('subjects_overview')}
-            </p>
-          </div>
-        </div>
-      </div>
-
-      {/* Status and Selection Section */}
-      <div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
-        
-        {/* Left Column - Status and Dropdown */}
-        <div className="lg:col-span-1 space-y-6">
-          
-          {/* Status Card */}
-          <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-            <div className="text-sm text-muted-foreground mb-2">
-              {t('status')}: <span className="text-primary font-semibold">{t('enrolled_by_student')}</span>
-            </div>
-            <div className="text-sm text-muted-foreground">
-              {t('ticket_number')}: <span className="font-semibold">{currentSemester.ticketNumber}</span>
-            </div>
-          </div>
-
-          {/* Semester Selection */}
-          <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-            <div className="text-sm text-muted-foreground mb-2">
-              {t('debt_from_documents')}: <span className="font-semibold">{currentSemester.debt}</span>
-            </div>
-            
-            <div className="relative mt-4">
-              <label className="block text-sm font-medium text-muted-foreground mb-2">
-                {t('select_semester')}:
-              </label>
-              <div className="relative">
-                <button
-                  onClick={() => setIsDropdownOpen(!isDropdownOpen)}
-                  className="w-full bg-card border border-border rounded-lg px-4 py-3 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
-                >
-                  <div className="flex items-center justify-between">
-                    <span className="text-sm font-medium text-primary">
-                      {currentSemesterData.name}
-                    </span>
-                    <FontAwesomeIcon 
-                      icon={faChevronDown} 
-                      className={`w-4 h-4 text-muted-foreground transition-transform ${isDropdownOpen ? 'rotate-180' : ''}`}
-                    />
-                  </div>
-                </button>
-                
-                {isDropdownOpen && (
-                  <div className="absolute z-10 w-full mt-1 bg-card border border-border rounded-lg shadow-lg">
-                    {subjectsData.semesters.map((semester) => (
-                      <button
-                        key={semester.id}
-                        onClick={() => {
-                          setSelectedSemester(semester.id);
-                          setIsDropdownOpen(false);
-                        }}
-                        className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent first:rounded-t-lg last:rounded-b-lg"
-                      >
-                        <div className="font-medium text-card-foreground">{semester.name}</div>
-                        <div className="text-xs text-muted-foreground">{t('status')}: {semester.status}</div>
-                      </button>
-                    ))}
-                  </div>
-                )}
-              </div>
-            </div>
-
-            <div className="mt-4 text-sm">
-              <div className="text-primary font-medium">
-                {t('serial_number')}: {currentSemesterData.serviceNumber}
-              </div>
-            </div>
-          </div>
-
-          {/* Enrolled Subjects */}
-          <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
-            <h3 className="font-semibold text-card-foreground mb-3 flex items-center gap-2">
-              <FontAwesomeIcon icon={faBook} className="w-4 h-4 text-primary" />
-              {t('enrolled_subjects')}
-            </h3>
-            <div className="text-3xl font-bold text-primary">
-              {currentSubjects.length}
-            </div>
-          </div>
-        </div>
-
-        {/* Right Column - Financial Information */}
-        <div className="lg:col-span-2">
-          <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-            <div className="bg-primary text-white px-6 py-4">
-              <h2 className="text-xl font-bold flex items-center gap-2">
-                <FontAwesomeIcon icon={faFileInvoice} />
-                {t('financial_info')}
-              </h2>
-            </div>
-            
-            <div className="p-6">
-              <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
-                
-                {/* Left Financial Column */}
-                <div className="space-y-4">
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('sum')}:</span>
-                    <span className="font-semibold text-primary">{currentSemester.financialInfo.sum}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('paid')}:</span>
-                    <span className="font-semibold text-green-600">{currentSemester.financialInfo.paid}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('due')}:</span>
-                    <span className="font-semibold text-red-600">{currentSemester.financialInfo.due}</span>
-                  </div>
-                  <div className="mt-4 p-4 bg-blue-50 rounded-lg">
-                    <div className="text-sm font-medium text-blue-800 mb-1">{t('material_costs')}:</div>
-                    <div className="text-sm text-blue-700">{t('material_costs_info')}</div>
-                  </div>
-                </div>
-
-                {/* Right Financial Column */}
-                <div className="space-y-4">
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('credits')}:</span>
-                    <span className="font-semibold text-primary">{currentSemester.financialInfo.credits}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('mksa')}:</span>
-                    <span className="font-semibold">{currentSemester.financialInfo.MKSA}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('electronic_registration')}:</span>
-                    <span className="font-semibold">{currentSemester.financialInfo.electronicRegistration}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('eukim')}:</span>
-                    <span className="font-semibold">{currentSemester.financialInfo.eUKIM}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-2 border-b border-border">
-                    <span className="text-muted-foreground">{t('bank_provision')}:</span>
-                    <span className="font-semibold">{currentSemester.financialInfo.bankProvision}</span>
-                  </div>
-                  <div className="flex justify-between items-center py-3 border-t-2 border-primary bg-primary bg-opacity-5 rounded-lg px-4">
-                    <span className="font-bold text-white">{t('total')}:</span>
-                    <span className="font-bold text-xl text-white">{currentSemester.financialInfo.total}</span>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      {/* Subjects Table */}
-      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
-        <div className="bg-primary text-white px-6 py-4">
-          <h2 className="text-xl font-bold">{t('subjects_list')}</h2>
-        </div>
-        
-        <div className="overflow-x-auto">
-          <table className="w-full">
-            <thead className="bg-accent">
-              <tr>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('code')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('hours')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('which_time')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('subject')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('semester')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('status')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('signature')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('group')}</th>
-                <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('professor')}</th>
-              </tr>
-            </thead>
-            <tbody className="divide-y divide-border">
-              {currentSubjects.map((subject: Subject) => (
-                <tr key={subject.id} className="hover:bg-accent transition-colors">
-                  <TableCell className="font-medium text-card-foreground">{subject.id}</TableCell>
-                  <TableCell className="font-mono text-sm text-primary font-medium">{subject.code}</TableCell>
-                  <TableCell className="font-medium">{subject.hours}</TableCell>
-                  <TableCell className="text-center font-medium">{subject.kojPat}</TableCell>
-                  <TableCell className="font-medium text-card-foreground max-w-xs">
-                    <div className="flex items-center gap-2">
-                      <FontAwesomeIcon icon={faBook} className="w-4 h-4 text-primary" />
-                      {t(subject.name, subject.name)}
-                    </div>
-                  </TableCell>
-                  <TableCell className="text-center font-medium text-primary">{t(subject.semester.toString(), subject.semester.toString())}</TableCell>
-                  <TableCell>
-                    <StatusBadge status={subject.status} />
-                  </TableCell>
-                  <TableCell className="text-center">
-                    {subject.signature ? t(subject.signature, subject.signature) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell className="text-center">
-                    {subject.group ? t(subject.group, subject.group) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                  <TableCell>
-                    {subject.professor ? t(subject.professor, subject.professor) : (
-                      <span className="text-muted-foreground">—</span>
-                    )}
-                  </TableCell>
-                </tr>
-              ))}
-            </tbody>
-          </table>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/components/LanguageSwitcher.tsx
===================================================================
--- src/components/LanguageSwitcher.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,29 +1,0 @@
-"use client";
-import { useTranslation } from 'react-i18next';
-
-export default function LanguageSwitcher() {
-  const { i18n } = useTranslation();
-
-  const changeLanguage = (lng: string) => {
-    i18n.changeLanguage(lng);
-  };
-
-  return (
-    <div className="flex gap-2 items-center">
-      <button
-        onClick={() => changeLanguage('mk')}
-        className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'mk' ? 'border-primary text-primary bg-accent' : 'border-border text-muted-foreground bg-card hover:border-primary hover:text-primary'}`}
-        aria-label="Macedonian"
-      >
-        MK
-      </button>
-      <button
-        onClick={() => changeLanguage('en')}
-        className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'en' ? 'border-primary text-primary bg-accent' : 'border-border text-muted-foreground bg-card hover:border-primary hover:text-primary'}`}
-        aria-label="English"
-      >
-        EN
-      </button>
-    </div>
-  );
-}
Index: c/components/admin-navbar.tsx
===================================================================
--- src/components/admin-navbar.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,67 +1,0 @@
-"use client";
-
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faBook, faCalendarPlus, faChalkboardUser, faBars, faTimes, faUserGear } from "@fortawesome/free-solid-svg-icons";
-import Link from "next/link";
-import { useState } from "react";
-import { useTranslation } from "react-i18next";
-
-const AdminNavbar = () => {
-  const [isMenuOpen, setIsMenuOpen] = useState(false);
-  const toggleMenu = () => setIsMenuOpen((v) => !v);
-
-  const { t } = useTranslation();
-  const menuItems = [
-    { icon: faBook, label: t("admin_subjects"), href: "/admin/subjects" },
-    { icon: faCalendarPlus, label: t("admin_semesters"), href: "/admin/semesters" },
-    { icon: faChalkboardUser, label: t("admin_schedule"), href: "/admin/schedule" },
-  ];
-
-  return (
-    <>
-      {/* Desktop Navbar */}
-      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
-        {menuItems.map((item) => (
-          <Link key={item.href} href={item.href}>
-            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
-              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
-              <span>{item.label}</span>
-            </div>
-          </Link>
-        ))}
-      </nav>
-
-      {/* Mobile Navbar */}
-      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
-        <div className="flex justify-between items-center p-4">
-          <div className="flex items-center gap-2 text-xl font-bold">
-            <FontAwesomeIcon icon={faUserGear} className="text-xl" />
-            {t("admin_portal")}
-          </div>
-          <button
-            onClick={toggleMenu}
-            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
-            aria-label="Toggle menu"
-          >
-            <FontAwesomeIcon icon={isMenuOpen ? faTimes : faBars} className="text-xl transition-transform duration-300" />
-          </button>
-        </div>
-
-        <div className={`overflow-hidden transition-all duration-300 ease-in-out ${isMenuOpen ? "max-h-64 opacity-100" : "max-h-0 opacity-0"}`}>
-          <div className="px-4 pb-4 space-y-2">
-            {menuItems.map((item) => (
-              <Link key={item.href} href={item.href}>
-                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
-                  <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
-                  <span className="text-lg">{item.label}</span>
-                </div>
-              </Link>
-            ))}
-          </div>
-        </div>
-      </nav>
-    </>
-  );
-};
-
-export default AdminNavbar;
Index: c/components/contact-bubble.tsx
===================================================================
--- src/components/contact-bubble.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,176 +1,0 @@
-"use client"
-
-import { useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faEnvelope, faTimes, faPaperPlane, faSpinner } from '@fortawesome/free-solid-svg-icons';
-
-export default function ContactBubble() {
-  const { t } = useTranslation();
-  const [isOpen, setIsOpen] = useState(false);
-  const [isSending, setIsSending] = useState(false);
-  const [sent, setSent] = useState(false);
-  const [form, setForm] = useState({ name: '', email: '', subject: '', message: '' });
-
-  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
-    setForm((prev) => ({ ...prev, [e.target.name]: e.target.value }));
-  };
-
-  const handleSubmit = async (e: React.FormEvent) => {
-    e.preventDefault();
-    setIsSending(true);
-    // Simulate sending
-    await new Promise((r) => setTimeout(r, 1200));
-    setIsSending(false);
-    setSent(true);
-    setTimeout(() => {
-      setSent(false);
-      setIsOpen(false);
-      setForm({ name: '', email: '', subject: '', message: '' });
-    }, 2500);
-  };
-
-  return (
-    <>
-      {/* Floating bubble */}
-      <button
-        onClick={() => setIsOpen(true)}
-        className={`fixed bottom-6 right-6 z-50 flex items-center gap-2 bg-primary hover:bg-blue-700 text-white px-5 py-3 rounded-full shadow-lg transition-all duration-300 hover:scale-105 hover:shadow-xl ${isOpen ? 'scale-0 opacity-0' : 'scale-100 opacity-100'}`}
-        aria-label={t('contact_us', 'Контактирај нè')}
-      >
-        <FontAwesomeIcon icon={faEnvelope} className="w-5 h-5" />
-        <span className="font-medium text-sm">{t('contact_us', 'Контактирај нè')}</span>
-      </button>
-
-      {/* Backdrop */}
-      {isOpen && (
-        <div
-          className="fixed inset-0 z-50 bg-black/40 backdrop-blur-sm transition-opacity duration-300"
-          onClick={() => setIsOpen(false)}
-        />
-      )}
-
-      {/* Modal */}
-      <div
-        className={`fixed z-50 bottom-6 right-6 w-[380px] max-w-[calc(100vw-2rem)] bg-card border border-border rounded-2xl shadow-2xl transition-all duration-300 origin-bottom-right ${isOpen ? 'scale-100 opacity-100' : 'scale-0 opacity-0 pointer-events-none'}`}
-      >
-        {/* Modal header */}
-        <div className="bg-primary text-white rounded-t-2xl px-6 py-4 flex items-center justify-between">
-          <div className="flex items-center gap-3">
-            <FontAwesomeIcon icon={faEnvelope} className="w-5 h-5" />
-            <h2 className="text-lg font-bold">{t('contact_us', 'Контактирај нè')}</h2>
-          </div>
-          <button
-            onClick={() => setIsOpen(false)}
-            className="text-white/80 hover:text-white transition-colors p-1"
-            aria-label={t('close', 'Затвори')}
-          >
-            <FontAwesomeIcon icon={faTimes} className="w-5 h-5" />
-          </button>
-        </div>
-
-        {/* Modal body */}
-        <div className="p-6">
-          {sent ? (
-            <div className="text-center py-8">
-              <div className="w-16 h-16 bg-green-100 text-green-600 rounded-full flex items-center justify-center mx-auto mb-4">
-                <FontAwesomeIcon icon={faPaperPlane} className="w-7 h-7" />
-              </div>
-              <h3 className="text-lg font-bold text-card-foreground mb-1">
-                {t('contact_sent_title', 'Пораката е испратена!')}
-              </h3>
-              <p className="text-sm text-muted-foreground">
-                {t('contact_sent_desc', 'Ќе ви одговориме наскоро.')}
-              </p>
-            </div>
-          ) : (
-            <form onSubmit={handleSubmit} className="space-y-4">
-              {/* Name */}
-              <div>
-                <label className="block text-sm font-medium text-muted-foreground mb-1">
-                  {t('contact_name', 'Име и презиме')}
-                </label>
-                <input
-                  type="text"
-                  name="name"
-                  required
-                  value={form.name}
-                  onChange={handleChange}
-                  placeholder={t('contact_name_placeholder', 'Вашето име')}
-                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
-                />
-              </div>
-
-              {/* Email */}
-              <div>
-                <label className="block text-sm font-medium text-muted-foreground mb-1">
-                  {t('contact_email', 'Е-пошта')}
-                </label>
-                <input
-                  type="email"
-                  name="email"
-                  required
-                  value={form.email}
-                  onChange={handleChange}
-                  placeholder={t('contact_email_placeholder', 'example@email.com')}
-                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
-                />
-              </div>
-
-              {/* Subject */}
-              <div>
-                <label className="block text-sm font-medium text-muted-foreground mb-1">
-                  {t('contact_subject', 'Наслов')}
-                </label>
-                <input
-                  type="text"
-                  name="subject"
-                  required
-                  value={form.subject}
-                  onChange={handleChange}
-                  placeholder={t('contact_subject_placeholder', 'Тема на пораката')}
-                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
-                />
-              </div>
-
-              {/* Message */}
-              <div>
-                <label className="block text-sm font-medium text-muted-foreground mb-1">
-                  {t('contact_message', 'Порака')}
-                </label>
-                <textarea
-                  name="message"
-                  required
-                  rows={3}
-                  value={form.message}
-                  onChange={handleChange}
-                  placeholder={t('contact_message_placeholder', 'Напишете ја вашата порака...')}
-                  className="w-full border border-border rounded-lg px-3 py-2 text-sm bg-card text-card-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary resize-none"
-                />
-              </div>
-
-              {/* Submit */}
-              <button
-                type="submit"
-                disabled={isSending}
-                className="w-full bg-primary hover:bg-blue-700 text-white font-medium py-2.5 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2 disabled:opacity-60 disabled:cursor-not-allowed"
-              >
-                {isSending ? (
-                  <>
-                    <FontAwesomeIcon icon={faSpinner} className="w-4 h-4 animate-spin" />
-                    {t('contact_sending', 'Испраќа...')}
-                  </>
-                ) : (
-                  <>
-                    <FontAwesomeIcon icon={faPaperPlane} className="w-4 h-4" />
-                    {t('contact_send', 'Испрати')}
-                  </>
-                )}
-              </button>
-            </form>
-          )}
-        </div>
-      </div>
-    </>
-  );
-}
Index: c/components/enroll-semester-dialog.tsx
===================================================================
--- src/components/enroll-semester-dialog.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,287 +1,0 @@
-"use client";
-
-import { useEffect, useMemo, useState } from "react";
-import { useTranslation } from "react-i18next";
-import { apiUrl } from "@/lib/api";
-import { getAccessToken } from "@/lib/auth";
-
-type SubjectOption = {
-  id: number;
-  name?: string;
-  code?: string;
-  credits: number;
-  mandatorySemester: number;
-  alreadyPassed: boolean;
-};
-
-type MajorOption = {
-  id: number;
-  name?: string;
-  subjects: SubjectOption[];
-};
-
-type SemesterOption = {
-  id: number;
-  name?: string;
-  year: number;
-  type?: string;
-};
-
-type EnrollmentOptions = {
-  requiredSubjects: number;
-  semesters: SemesterOption[];
-  majors: MajorOption[];
-  defaultMajorId: number | null;
-};
-
-export default function EnrollSemesterDialog({
-  open,
-  onClose,
-  onEnrolled,
-}: {
-  open: boolean;
-  onClose: () => void;
-  onEnrolled: () => void;
-}) {
-  const { t } = useTranslation();
-
-  const [options, setOptions] = useState<EnrollmentOptions | null>(null);
-  const [loading, setLoading] = useState(false);
-  const [submitting, setSubmitting] = useState(false);
-  const [error, setError] = useState<string | null>(null);
-
-  const [semesterId, setSemesterId] = useState<number | null>(null);
-  const [majorId, setMajorId] = useState<number | null>(null);
-  const [picked, setPicked] = useState<number[]>([]);
-
-  useEffect(() => {
-    if (!open) return;
-
-    let cancelled = false;
-
-    async function load() {
-      setLoading(true);
-      setError(null);
-      try {
-        const token = getAccessToken();
-        if (!token) throw new Error(t("enroll_not_signed_in"));
-
-        const res = await fetch(apiUrl("/api/enrollment/options"), {
-          cache: "no-store",
-          headers: { Authorization: `Bearer ${token}` },
-        });
-        if (!res.ok) throw new Error(`${t("enroll_options_failed")} (${res.status})`);
-
-        const data = (await res.json()) as EnrollmentOptions;
-        if (cancelled) return;
-
-        setOptions(data);
-        setSemesterId(data.semesters[0]?.id ?? null);
-        setMajorId(data.defaultMajorId ?? data.majors[0]?.id ?? null);
-        setPicked([]);
-      } catch (e) {
-        if (!cancelled) setError(e instanceof Error ? e.message : String(e));
-      } finally {
-        if (!cancelled) setLoading(false);
-      }
-    }
-
-    void load();
-    return () => {
-      cancelled = true;
-    };
-  }, [open, t]);
-
-  const required = options?.requiredSubjects ?? 5;
-
-  const subjects = useMemo(
-    () => options?.majors.find((m) => m.id === majorId)?.subjects ?? [],
-    [options, majorId],
-  );
-
-  function toggle(subjectId: number) {
-    setPicked((prev) => {
-      if (prev.includes(subjectId)) return prev.filter((id) => id !== subjectId);
-      if (prev.length >= required) return prev; // the cap is the point of the form
-      return [...prev, subjectId];
-    });
-  }
-
-  async function submit() {
-    setSubmitting(true);
-    setError(null);
-    try {
-      const token = getAccessToken();
-      if (!token) throw new Error(t("enroll_not_signed_in"));
-
-      const res = await fetch(apiUrl("/api/enrollment"), {
-        method: "POST",
-        headers: {
-          "Content-Type": "application/json",
-          Authorization: `Bearer ${token}`,
-        },
-        body: JSON.stringify({
-          SemesterId: semesterId,
-          MajorId: majorId,
-          SubjectIds: picked,
-        }),
-      });
-
-      const body = (await res.json()) as { ok: boolean; message?: string };
-      if (!res.ok || !body.ok) {
-        throw new Error(body.message || `${t("enroll_failed")} (${res.status})`);
-      }
-
-      onEnrolled();
-      onClose();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : String(e));
-    } finally {
-      setSubmitting(false);
-    }
-  }
-
-  if (!open) return null;
-
-  const noSemestersLeft = !loading && options !== null && options.semesters.length === 0;
-  const canSubmit =
-    !submitting && semesterId !== null && majorId !== null && picked.length === required;
-
-  return (
-    <div
-      className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-black/50 p-4 sm:items-center"
-      role="dialog"
-      aria-modal="true"
-      onClick={onClose}
-    >
-      <div
-        className="w-full max-w-3xl rounded-xl border border-border bg-card shadow-lg"
-        onClick={(e) => e.stopPropagation()}
-      >
-        <div className="flex items-center justify-between rounded-t-xl bg-primary px-6 py-4 text-white">
-          <h2 className="text-xl font-bold">{t("enroll_semester")}</h2>
-          <button
-            className="rounded-lg px-3 py-1 text-sm hover:bg-white/20"
-            onClick={onClose}
-            aria-label={t("close")}
-          >
-            ✕
-          </button>
-        </div>
-
-        <div className="p-6">
-          {loading ? (
-            <p className="text-muted-foreground">{t("loading")}</p>
-          ) : noSemestersLeft ? (
-            <p className="text-muted-foreground">{t("enroll_no_semesters")}</p>
-          ) : (
-            <>
-              <div className="grid gap-4 sm:grid-cols-2">
-                <div className="flex flex-col">
-                  <label className="text-sm text-muted-foreground">{t("semester")}</label>
-                  <select
-                    className="rounded-lg border border-border bg-background px-3 py-2"
-                    value={semesterId ?? ""}
-                    onChange={(e) => setSemesterId(Number.parseInt(e.target.value, 10))}
-                  >
-                    {options?.semesters.map((s) => (
-                      <option key={s.id} value={s.id}>
-                        {s.name}
-                      </option>
-                    ))}
-                  </select>
-                </div>
-
-                <div className="flex flex-col">
-                  <label className="text-sm text-muted-foreground">{t("direction")}</label>
-                  <select
-                    className="rounded-lg border border-border bg-background px-3 py-2"
-                    value={majorId ?? ""}
-                    onChange={(e) => {
-                      setMajorId(Number.parseInt(e.target.value, 10));
-                      setPicked([]); // subjects differ per programme
-                    }}
-                  >
-                    {options?.majors.map((m) => (
-                      <option key={m.id} value={m.id}>
-                        {m.name}
-                      </option>
-                    ))}
-                  </select>
-                </div>
-              </div>
-
-              <div className="mt-6 flex items-center justify-between">
-                <h3 className="font-semibold text-card-foreground">{t("subjects")}</h3>
-                <span
-                  className={`text-sm font-medium ${
-                    picked.length === required ? "text-green-700" : "text-muted-foreground"
-                  }`}
-                >
-                  {picked.length} / {required}
-                </span>
-              </div>
-
-              <div className="mt-2 max-h-80 overflow-y-auto rounded-lg border border-border">
-                {subjects.map((s) => {
-                  const checked = picked.includes(s.id);
-                  const atLimit = !checked && picked.length >= required;
-                  return (
-                    <label
-                      key={s.id}
-                      className={`flex items-center gap-3 border-b border-border px-4 py-3 last:border-b-0 ${
-                        atLimit ? "opacity-50" : "cursor-pointer hover:bg-accent"
-                      }`}
-                    >
-                      <input
-                        type="checkbox"
-                        checked={checked}
-                        disabled={atLimit}
-                        onChange={() => toggle(s.id)}
-                      />
-                      <span className="flex-1">
-                        <span className="text-card-foreground">{s.name}</span>
-                        <span className="ml-2 font-mono text-xs text-muted-foreground">{s.code}</span>
-                        {s.alreadyPassed && (
-                          <span className="ml-2 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-800">
-                            {t("enroll_already_passed")}
-                          </span>
-                        )}
-                      </span>
-                      <span className="text-xs text-muted-foreground">
-                        {t("enroll_semester_short")} {s.mandatorySemester} · {s.credits} {t("enroll_credits")}
-                      </span>
-                    </label>
-                  );
-                })}
-              </div>
-            </>
-          )}
-
-          {error && (
-            <div className="mt-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
-              {error}
-            </div>
-          )}
-
-          <div className="mt-6 flex justify-end gap-3">
-            <button
-              className="rounded-lg border border-border px-4 py-2 text-sm font-medium"
-              onClick={onClose}
-              disabled={submitting}
-            >
-              {t("cancel")}
-            </button>
-            <button
-              className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
-              onClick={() => void submit()}
-              disabled={!canSubmit}
-            >
-              {submitting ? t("loading") : t("enroll_confirm")}
-            </button>
-          </div>
-        </div>
-      </div>
-    </div>
-  );
-}
Index: c/components/exams.tsx
===================================================================
--- src/components/exams.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,312 +1,0 @@
-"use client"
-import { useEffect, useMemo, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faSort, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons';
-import { getAccessToken } from '@/lib/auth';
-import { apiUrl } from '@/lib/api';
-
-type PassedSubject = {
-  id: number;
-  subjectId: number;
-  code: string;
-  subject: string;
-  credits: number;
-  grade: number;
-  gradeText: string;
-  date: string; // DD.MM.YYYY
-  semester: string;
-  professor: string;
-};
-
-type PassedSubjectsResponse = {
-  passedSubjects: PassedSubject[];
-};
-
-type ExamRow = {
-  id: number;
-  code: string;
-  subject: string;
-  date: string;
-  semester: string;
-  credits: number;
-  grade: number;
-};
-
-const Exams = () => {
-  const { t } = useTranslation();
-  const [sortField, setSortField] = useState<'grade' | 'date' | null>(null);
-  const [sortOrder, setSortOrder] = useState<'asc' | 'desc' | null>(null);
-  const [exams, setExams] = useState<ExamRow[]>([]);
-  const [isLoading, setIsLoading] = useState(true);
-  const [errorMessage, setErrorMessage] = useState<string | null>(null);
-
-  useEffect(() => {
-    let cancelled = false;
-
-    async function load() {
-      setIsLoading(true);
-      setErrorMessage(null);
-
-      const token = getAccessToken();
-      if (!token) {
-        setErrorMessage('Not authenticated. Please login again.');
-        setIsLoading(false);
-        return;
-      }
-
-      try {
-        const response = await fetch(apiUrl('/api/user/getPassedSubjects'), {
-          method: 'GET',
-          headers: {
-            Authorization: `Bearer ${token}`,
-          },
-        });
-
-        if (!response.ok) {
-          const text = await response.text().catch(() => '');
-          throw new Error(text || `Failed to load passed subjects (${response.status})`);
-        }
-
-        const data = (await response.json()) as PassedSubjectsResponse;
-        const rows: ExamRow[] = (data?.passedSubjects ?? []).map((s) => ({
-          id: s.id,
-          code: s.code,
-          subject: s.subject,
-          date: s.date,
-          semester: s.semester,
-          credits: s.credits,
-          grade: s.grade,
-        }));
-
-        if (!cancelled) setExams(rows);
-      } catch (err) {
-        if (!cancelled) {
-          setErrorMessage(err instanceof Error ? err.message : 'Failed to load passed subjects.');
-        }
-      } finally {
-        if (!cancelled) setIsLoading(false);
-      }
-    }
-
-    void load();
-
-    return () => {
-      cancelled = true;
-    };
-  }, []);
-
-  const stats = useMemo(() => {
-    const passed = exams.length;
-    const creditsCurrent = exams.reduce((sum, s) => sum + (typeof s.credits === 'number' ? s.credits : 0), 0);
-    const numericGrades = exams.map((e) => (typeof e.grade === 'number' ? e.grade : null)).filter((g): g is number => g !== null);
-    const average =
-      numericGrades.length > 0
-        ? numericGrades.reduce((sum, g) => sum + g, 0) / numericGrades.length
-        : 0;
-
-    const totalCredits = 240;
-    const totalExams = 40;
-    return {
-      average: Number.isFinite(average) ? Number(average.toFixed(2)) : 0,
-      credits: { current: creditsCurrent, total: totalCredits },
-      passed,
-      remaining: Math.max(0, totalExams - passed),
-    };
-  }, [exams]);
-
-  const getGradeColor = (grade: number) => {
-    if (grade >= 9) return "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20";
-    if (grade >= 8) return "bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 border-yellow-500/20";
-    if (grade >= 6) return "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20";
-    return "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20";
-  };
-
-  const handleSortByGrade = () => {
-    if (sortField === 'grade') {
-      if (sortOrder === 'desc') {
-        setSortOrder('asc');
-      } else if (sortOrder === 'asc') {
-        setSortField(null);
-        setSortOrder(null);
-      } else {
-        setSortOrder('desc');
-      }
-    } else {
-      setSortField('grade');
-      setSortOrder('desc');
-    }
-  };
-
-  const handleSortByDate = () => {
-    if (sortField === 'date') {
-      if (sortOrder === 'desc') {
-        setSortOrder('asc');
-      } else if (sortOrder === 'asc') {
-        setSortField(null);
-        setSortOrder(null);
-      } else {
-        setSortOrder('desc');
-      }
-    } else {
-      setSortField('date');
-      setSortOrder('desc');
-    }
-  };
-
-  const getSortedExams = () => {
-    if (!sortField || !sortOrder) return exams;
-    
-    return [...exams].sort((a, b) => {
-      if (sortField === 'grade') {
-        return sortOrder === 'asc' ? a.grade - b.grade : b.grade - a.grade;
-      }
-      
-      if (sortField === 'date') {
-        // Convert date strings to Date objects for proper sorting
-        const dateA = new Date(a.date.split('.').reverse().join('-')); // Convert DD.MM.YYYY to YYYY-MM-DD
-        const dateB = new Date(b.date.split('.').reverse().join('-'));
-        
-        return sortOrder === 'asc' ? dateA.getTime() - dateB.getTime() : dateB.getTime() - dateA.getTime();
-      }
-      
-      return 0;
-    });
-  };
-
-  const getSortIcon = (field: 'grade' | 'date') => {
-    if (sortField === field) {
-      if (sortOrder === 'asc') return faSortUp;
-      if (sortOrder === 'desc') return faSortDown;
-    }
-    return faSort;
-  };
-
-  const creditsPercentage = stats.credits.total > 0 ? (stats.credits.current / stats.credits.total) * 100 : 0;
-
-  if (isLoading) {
-    return (
-      <div className="bg-card rounded-lg shadow-sm p-6">
-        {t('loading', 'Loading...')}
-      </div>
-    );
-  }
-
-  if (errorMessage) {
-    return (
-      <div className="bg-card rounded-lg shadow-sm p-6">
-        <div className="rounded-lg border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-400">
-          {t('failed_to_load_exams', errorMessage)}
-        </div>
-      </div>
-    );
-  }
-
-  return (
-    <div className="bg-card rounded-lg shadow-sm p-6 space-y-6">
-      {/* Statistics Section */}
-      <div className="space-y-4">
-        <div className="grid grid-cols-2 md:grid-cols-4 gap-6">
-          {/* Average Grade */}
-          <div className="text-center">
-            <div className="text-3xl font-bold text-card-foreground">{stats.average}</div>
-            <div className="text-sm text-muted-foreground mt-1">{t('average', 'Просек')}</div>
-          </div>
-
-          {/* Credits */}
-          <div className="text-center">
-            <div className="text-3xl font-bold text-card-foreground">
-              {stats.credits.current}
-              <span className="text-lg text-muted-foreground">/{stats.credits.total}</span>
-            </div>
-            <div className="text-sm text-muted-foreground mt-1">{t('credits', 'Кредити')}</div>
-          </div>
-
-          {/* Passed Exams */}
-          <div className="text-center">
-            <div className="text-3xl font-bold text-card-foreground">{stats.passed}</div>
-            <div className="text-sm text-muted-foreground mt-1">{t('passed', 'Положени')}</div>
-          </div>
-
-          {/* Remaining Exams */}
-          <div className="text-center">
-            <div className="text-3xl font-bold text-card-foreground">{stats.remaining}</div>
-            <div className="text-sm text-muted-foreground mt-1">{t('remaining', 'Останато')}</div>
-          </div>
-        </div>
-
-        {/* Progress Bar spanning entire statistics section */}
-        <div className="w-full bg-secondary rounded-full h-2">
-          <div
-            className="bg-primary h-2 rounded-full transition-all duration-300"
-            style={{ width: `${creditsPercentage}%` }}
-          ></div>
-        </div>
-      </div>
-
-      {/* Exams Table */}
-      <div>
-        <h3 className="text-xl font-semibold text-card-foreground mb-4">{t('exams', 'Испити')}</h3>
-
-        <div className="overflow-x-auto">
-          <table className="min-w-full">
-            <thead>
-              <tr className="border-b border-border">
-                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">#</th>
-                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('subject', 'Предмет')}</th>
-                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('semester', 'Семестар')}</th>
-                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('credits', 'Кредити')}</th>
-                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">
-                  <button
-                    onClick={handleSortByDate}
-                    className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-accent hover:text-accent-foreground transition-all duration-200 transform hover:scale-105"
-                  >
-                    {t('date', 'Датум')}
-                    <FontAwesomeIcon
-                      icon={getSortIcon('date')}
-                      className={`text-xs transition-colors duration-200 ${
-                        sortField === 'date' ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground'
-                      }`}
-                    />
-                  </button>
-                </th>
-                <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">
-                  <button
-                    onClick={handleSortByGrade}
-                    className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-accent hover:text-accent-foreground transition-all duration-200 transform hover:scale-105"
-                  >
-                    {t('grade', 'Оценка')}
-                    <FontAwesomeIcon
-                      icon={getSortIcon('grade')}
-                      className={`text-xs transition-colors duration-200 ${
-                        sortField === 'grade' ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground'
-                      }`}
-                    />
-                  </button>
-                </th>
-              </tr>
-            </thead>
-            <tbody className="divide-y divide-border">
-              {getSortedExams().map((exam) => (
-                <tr key={exam.id} className="hover:bg-accent/50 transition-colors duration-150">
-                  <td className="py-4 px-4 text-sm text-card-foreground">{exam.id}</td>
-                  <td className="py-4 px-4 text-sm text-card-foreground font-medium">{t(exam.subject, exam.subject)}</td>
-                  <td className="py-4 px-4 text-sm text-muted-foreground">{t(exam.semester, exam.semester)}</td>
-                  <td className="py-4 px-4 text-sm text-muted-foreground">{exam.credits}</td>
-                  <td className="py-4 px-4 text-sm text-muted-foreground">{exam.date}</td>
-                  <td className="py-4 px-4">
-                    <span className={`inline-flex items-center px-2.5 py-1 rounded-md text-sm font-medium border ${getGradeColor(exam.grade)}`}>
-                      {exam.grade}
-                    </span>
-                  </td>
-                </tr>
-              ))}
-            </tbody>
-          </table>
-        </div>
-      </div>
-    </div>
-  );
-};
-
-export default Exams;
Index: c/components/header.tsx
===================================================================
--- src/components/header.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,114 +1,0 @@
-"use client"
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faUser } from '@fortawesome/free-solid-svg-icons';
-import Image from 'next/image';
-
-import { useEffect, useState } from 'react';
-import { getAccessToken, clearAuthTokens } from '@/lib/auth';
-import { useTranslation } from 'react-i18next';
-import LanguageSwitcher from './LanguageSwitcher';
-import { apiUrl } from '@/lib/api';
-
-const Header = () => {
-
-  const [userName, setUserName] = useState<string>('');
-  const { t } = useTranslation();
-
-  useEffect(() => {
-    async function fetchUser() {
-      const token = getAccessToken();
-      if (!token) return;
-      try {
-        const response = await fetch(apiUrl('/api/user/getUser'), {
-          method: 'GET',
-          headers: { Authorization: `Bearer ${token}` },
-        });
-        if (!response.ok) return;
-        const data = await response.json();
-        // Try both student and professor shape
-        if (data?.personalInfo) {
-          const p = data.personalInfo;
-          setUserName([p.firstName, p.middleName, p.lastName].filter(Boolean).join(' '));
-        }
-      } catch {}
-    }
-    fetchUser();
-    return () => {};
-  }, []);
-
-  const handleLogout = () => {
-    clearAuthTokens();
-    if (typeof window !== 'undefined') {
-      window.location.href = '/';
-    }
-  };
-
-  return (
-    <header className="bg-card shadow-sm border-b border-border">
-      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
-        <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center py-4 gap-4 sm:gap-0">
-          {/* Left side - Logos and University Info */}
-          <div className="flex items-center gap-2 justify-center sm:justify-start">
-            {/* UKIM Logo */}
-            <div className="flex-shrink-0">
-              <Image
-                src="/ukim-logo.png"
-                alt="UKIM Logo"
-                width={40}
-                height={40}
-                className="h-10 w-auto"
-              />
-            </div>
-            {/* FINKI Logo */}
-            <div className="flex-shrink-0">
-              <Image
-                src="/finki-logo.png"
-                alt="FINKI Logo"
-                width={40}
-                height={40}
-                className="h-10 w-auto"
-              />
-            </div>
-            {/* University Text */}
-            <div className="hidden sm:block">
-              <div className="text-card-foreground font-medium text-sm">
-                {t('university')}
-              </div>
-              <div className="text-muted-foreground text-sm">
-                {t('faculty')}
-              </div>
-            </div>
-          </div>
-          {/* Right side - User Profile */}
-          <div className="flex flex-col sm:flex-row items-center gap-2 sm:gap-4 w-full sm:w-auto justify-center sm:justify-end">
-            {/* Language Switcher - now left of user info */}
-            <div className="sm:mr-2 w-full sm:w-auto flex justify-center sm:justify-end">
-              <LanguageSwitcher />
-            </div>
-            <div className="flex items-center gap-2 sm:gap-3 w-full sm:w-auto justify-center sm:justify-end">
-              {/* User Avatar */}
-              <div className="hidden sm:flex items-center justify-center w-10 h-10 bg-primary text-primary-foreground rounded-full">
-                <FontAwesomeIcon icon={faUser} className="text-sm" />
-              </div>
-              {/* User Name */}
-              <div className="hidden sm:block text-card-foreground font-medium">
-                {userName || '...'}
-              </div>
-              {/* Logout Button - more stylish and full width on mobile */}
-              <button
-                className="w-full sm:w-auto ml-0 sm:ml-2 px-4 py-2 border-2 border-primary text-primary bg-card rounded-lg font-semibold flex items-center justify-center gap-2 hover:bg-accent transition-all duration-200 shadow-sm"
-                onClick={handleLogout}
-              >
-                <svg xmlns='http://www.w3.org/2000/svg' className='h-4 w-4' fill='none' viewBox='0 0 24 24' stroke='currentColor'><path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a2 2 0 01-2 2H7a2 2 0 01-2-2V7a2 2 0 012-2h4a2 2 0 012 2v1' /></svg>
-                {t('logout')}
-              </button>
-            </div>
-          </div>
-        </div>
-      </div>
-    </header>
-  );
-};
-
-export default Header;
Index: c/components/navbar.tsx
===================================================================
--- src/components/navbar.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,86 +1,0 @@
-"use client"
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faUser } from '@fortawesome/free-solid-svg-icons';
-import { faBookmark } from '@fortawesome/free-solid-svg-icons';
-import { faBook } from '@fortawesome/free-solid-svg-icons';
-import { faPenToSquare } from '@fortawesome/free-solid-svg-icons';
-import { faListCheck } from '@fortawesome/free-solid-svg-icons';
-import { faFilePdf } from '@fortawesome/free-solid-svg-icons';
-import { faBars, faTimes, faGraduationCap } from '@fortawesome/free-solid-svg-icons';
-import { useState } from 'react';
-import Link from 'next/link';
-import { useTranslation } from 'react-i18next';
-
-const Navbar = () => {
-  const [isMenuOpen, setIsMenuOpen] = useState(false);
-
-  const toggleMenu = () => {
-    setIsMenuOpen(!isMenuOpen);
-  };
-
-  const { t } = useTranslation();
-  const menuItems = [
-    { icon: faUser, label: t('profile'), href: '/students/profile' },
-    { icon: faBookmark, label: t('semesters'), href: '/students/semesters' },
-    { icon: faBook, label: t('subjects'), href: '/students/subjects' },
-    { icon: faPenToSquare, label: t('applications'), href: '/students/applications' },
-    { icon: faListCheck, label: t('exams'), href: '/students/exams' },
-    { icon: faFilePdf, label: t('documents'), href: '/students/documents' }
-  ];
-
-  return (
-    <>
-      {/* Desktop Navbar */}
-      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
-        {menuItems.map((item, index) => (
-          <Link key={index} href={item.href}>
-            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
-              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
-              <span>{item.label}</span>
-            </div>
-          </Link>
-        ))}
-      </nav>
-
-      {/* Mobile Navbar */}
-      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
-        <div className="flex justify-between items-center p-4">
-          {/* IKnow Logo/Text */}
-          <div className="flex items-center gap-2 text-xl font-bold">
-            <FontAwesomeIcon icon={faGraduationCap} className="text-xl" />
-            IKnow
-          </div>
-          
-          {/* Hamburger Menu Button */}
-          <button
-            onClick={toggleMenu}
-            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
-          >
-            <FontAwesomeIcon 
-              icon={isMenuOpen ? faTimes : faBars} 
-              className="text-xl transition-transform duration-300"
-            />
-          </button>
-        </div>
-
-        {/* Mobile Menu Items */}
-        <div className={`overflow-hidden transition-all duration-300 ease-in-out ${
-          isMenuOpen ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
-        }`}>
-          <div className="px-4 pb-4 space-y-2">
-            {menuItems.map((item, index) => (
-              <Link key={index} href={item.href}>
-                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
-                  <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
-                  <span className="text-lg">{item.label}</span>
-                </div>
-              </Link>
-            ))}
-          </div>
-        </div>
-      </nav>
-    </>
-  );
-};
-
-export default Navbar;
Index: c/components/professor-navbar.tsx
===================================================================
--- src/components/professor-navbar.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,80 +1,0 @@
-"use client";
-
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faUser, faUsers, faBars, faTimes, faChalkboardUser } from "@fortawesome/free-solid-svg-icons";
-import Link from "next/link";
-import { useState } from "react";
-import { useTranslation } from 'react-i18next';
-
-const ProfessorNavbar = () => {
-  const [isMenuOpen, setIsMenuOpen] = useState(false);
-
-  const toggleMenu = () => {
-    setIsMenuOpen((v) => !v);
-  };
-
-  const { t } = useTranslation();
-  const menuItems = [
-    { icon: faUser, label: t('profile'), href: "/professor/profile" },
-    { icon: faUsers, label: t('students') || 'Студенти', href: "/professor/students" },
-  ];
-
-  return (
-    <>
-      {/* Desktop Navbar */}
-      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
-        {menuItems.map((item) => (
-          <Link key={item.href} href={item.href}>
-            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
-              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
-              <span>{item.label}</span>
-            </div>
-          </Link>
-        ))}
-      </nav>
-
-      {/* Mobile Navbar */}
-      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
-        <div className="flex justify-between items-center p-4">
-          <div className="flex items-center gap-2 text-xl font-bold">
-            <FontAwesomeIcon icon={faChalkboardUser} className="text-xl" />
-            Professor
-          </div>
-
-          <button
-            onClick={toggleMenu}
-            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
-            aria-label="Toggle menu"
-          >
-            <FontAwesomeIcon
-              icon={isMenuOpen ? faTimes : faBars}
-              className="text-xl transition-transform duration-300"
-            />
-          </button>
-        </div>
-
-        <div
-          className={`overflow-hidden transition-all duration-300 ease-in-out ${
-            isMenuOpen ? "max-h-64 opacity-100" : "max-h-0 opacity-0"
-          }`}
-        >
-          <div className="px-4 pb-4 space-y-2">
-            {menuItems.map((item) => (
-              <Link key={item.href} href={item.href}>
-                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
-                  <FontAwesomeIcon
-                    icon={item.icon}
-                    className="transition-transform duration-300 group-hover:rotate-12"
-                  />
-                  <span className="text-lg">{item.label}</span>
-                </div>
-              </Link>
-            ))}
-          </div>
-        </div>
-      </nav>
-    </>
-  );
-};
-
-export default ProfessorNavbar;
Index: c/components/theme-provider.tsx
===================================================================
--- src/components/theme-provider.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,8 +1,0 @@
-"use client";
-
-import { ThemeProvider as NextThemesProvider } from "next-themes";
-import { type ThemeProviderProps } from "next-themes";
-
-export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
-  return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
-}
Index: c/components/theme-toggle.tsx
===================================================================
--- src/components/theme-toggle.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,37 +1,0 @@
-"use client";
-
-import { Moon, Sun } from "lucide-react";
-import { useTheme } from "next-themes";
-import { useEffect, useState } from "react";
-
-export function ThemeToggle() {
-  const [mounted, setMounted] = useState(false);
-  const { theme, setTheme } = useTheme();
-
-  // Avoid hydration mismatch
-  useEffect(() => {
-    setMounted(true);
-  }, []);
-
-  if (!mounted) {
-    return (
-      <button className="p-2 rounded-md hover:bg-accent">
-        <Sun className="h-5 w-5" />
-      </button>
-    );
-  }
-
-  return (
-    <button
-      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
-      className="p-2 rounded-md hover:bg-accent transition-colors"
-      aria-label="Toggle theme"
-    >
-      {theme === "dark" ? (
-        <Sun className="h-5 w-5" />
-      ) : (
-        <Moon className="h-5 w-5" />
-      )}
-    </button>
-  );
-}
Index: c/data/applications.json
===================================================================
--- src/data/applications.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,144 +1,0 @@
-{
-  "examSessions": [
-    {
-      "id": "2025_summer_session2",
-      "name": "2025 (Летна) Втора испитна сесија",
-      "year": "2025",
-      "semester": "Летна",
-      "session": "Втора испитна сесија"
-    },
-    {
-      "id": "2025_summer_session1",
-      "name": "2025 (Летна) Прва испитна сесија",
-      "year": "2025",
-      "semester": "Летна",
-      "session": "Прва испитна сесија"
-    },
-    {
-      "id": "2025_winter_session2",
-      "name": "2025 (Зимска) Втора испитна сесија",
-      "year": "2025",
-      "semester": "Зимска",
-      "session": "Втора испитна сесија"
-    },
-    {
-      "id": "2025_winter_session1",
-      "name": "2025 (Зимска) Прва испитна сесија",
-      "year": "2025",
-      "semester": "Зимска",
-      "session": "Прва испитна сесија"
-    },
-    {
-      "id": "2024_summer_session2",
-      "name": "2024 (Летна) Втора испитна сесија",
-      "year": "2024",
-      "semester": "Летна",
-      "session": "Втора испитна сесија"
-    },
-    {
-      "id": "2024_summer_session1",
-      "name": "2024 (Летна) Прва испитна сесија",
-      "year": "2024",
-      "semester": "Летна",
-      "session": "Прва испитна сесија"
-    },
-    {
-      "id": "2024_winter_session2",
-      "name": "2024 (Зимска) Втора испитна сесија",
-      "year": "2024",
-      "semester": "Зимска",
-      "session": "Втора испитна сесија"
-    },
-    {
-      "id": "2024_winter_session1",
-      "name": "2024 (Зимска) Прва испитна сесија",
-      "year": "2024",
-      "semester": "Зимска",
-      "session": "Прва испитна сесија"
-    }
-  ],
-  "currentSession": {
-    "id": "2025_summer_session2",
-    "name": "2025 (Летна) Втора испитна сесија"
-  },
-  "applications": [
-    {
-      "id": 1,
-      "serviceNumber": "4684532",
-      "code": "F23L2W014",
-      "subject": "Компјутерски мрежи и безбедност",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Сашо Граматиков",
-      "decade": 1
-    },
-    {
-      "id": 2,
-      "serviceNumber": "4684531",
-      "code": "F23L2W167",
-      "subject": "Шаблони за дизајн на кориснички интерфејси",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Сузана Лошковска",
-      "decade": 1
-    },
-    {
-      "id": 3,
-      "serviceNumber": "4684530",
-      "code": "F23L3S100",
-      "subject": "Деловна пракса",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Александар Стојменски",
-      "decade": 1
-    },
-    {
-      "id": 4,
-      "serviceNumber": "4684529",
-      "code": "F23L2S026",
-      "subject": "Маркетинг",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Билјана Стојкоска",
-      "decade": 1
-    },
-    {
-      "id": 5,
-      "serviceNumber": "4684528",
-      "code": "F23L2S017",
-      "subject": "Оперативни системи",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Невена Ацковска",
-      "decade": 1
-    },
-    {
-      "id": 6,
-      "serviceNumber": "4684527",
-      "code": "F23L2S029",
-      "subject": "Софтверско инженерство",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Ѓорѓи Маџаров",
-      "decade": 1
-    },
-    {
-      "id": 7,
-      "serviceNumber": "4684526",
-      "code": "F23L2S030",
-      "subject": "Вештачка интелигенција",
-      "completed": "Не",
-      "fee": "0,00",
-      "date": "21.05.2025",
-      "instructor": "Соња Гиевска",
-      "decade": 1
-    }
-  ],
-  "note": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички."
-}
Index: c/data/documents.json
===================================================================
--- src/data/documents.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,185 +1,0 @@
-{
-  "documentTypes": [
-    {
-      "id": "select_document",
-      "name": "Изберете документ",
-      "price": 0
-    },
-    {
-      "id": "administrative_regulation",
-      "name": "Барање за административно регулирање на ретроактивен семестар (од 2024г) ( 1000)",
-      "price": 1000
-    },
-    {
-      "id": "exam_application_satisfaction",
-      "name": "Барање за задочно пријавување на испит (од 2024г) ( 1000)",
-      "price": 1000
-    },
-    {
-      "id": "semester_enrollment_after_deadline",
-      "name": "Барање за запишување на семестар по истек на рок (од 2024г) ( 1500)",
-      "price": 1500
-    },
-    {
-      "id": "certificate_issuance_various",
-      "name": "Барање за издавање потврди по разни основи (од 2024г) ( 1500)",
-      "price": 1500
-    },
-    {
-      "id": "student_status_verification",
-      "name": "Барање за мирување на студиите (од 2024г) ( 2000)",
-      "price": 2000
-    },
-    {
-      "id": "diploma_thesis_postponement",
-      "name": "Барање за откажување на пријавена тема за дипломска работа (од 2024г) ( 1000)",
-      "price": 1000
-    },
-    {
-      "id": "diploma_package",
-      "name": "Барање за пакет за дипломирање (од 2024г) (6200)",
-      "price": 6200
-    },
-    {
-      "id": "exam_postponement",
-      "name": "Барање за поништување на испит (од 2024г) ( 2000)",
-      "price": 2000
-    },
-    {
-      "id": "regular_student_certificate",
-      "name": "Барање за потврда за редовен студент (хартиена) ( 100)",
-      "price": 100
-    },
-    {
-      "id": "study_continuation_verification",
-      "name": "Барање за продолжување на студии во мирување (од 2024г) ( 2000)",
-      "price": 2000
-    },
-    {
-      "id": "failed_subject_grade_change",
-      "name": "Барање за промена на изборен предмет (од 2024г) ( 1500)",
-      "price": 1500
-    },
-    {
-      "id": "passed_subject_grade_change",
-      "name": "Барање за промена на положен предмет (од 2024г) ( 0)",
-      "price": 0
-    },
-    {
-      "id": "study_program_change_same_accreditation",
-      "name": "Барање за промена на студиска програма од иста акредитација (од 2024г) ( 2000)",
-      "price": 2000
-    },
-    {
-      "id": "study_program_change_new_accreditation",
-      "name": "Барање за промена на студиска програма од понова акредитација (од 2024г) ( 3000)",
-      "price": 3000
-    },
-    {
-      "id": "diploma_supplement",
-      "name": "Додаток на диплома ( 0)",
-      "price": 0
-    },
-    {
-      "id": "diploma_supplement_second_cycle",
-      "name": "Додаток на диплома (втор циклус) ( 0)",
-      "price": 0
-    },
-    {
-      "id": "mksa",
-      "name": "МКСА ( 750)",
-      "price": 750
-    },
-    {
-      "id": "exam_recognition",
-      "name": "Признавање на положени испити ( 0)",
-      "price": 0
-    },
-    {
-      "id": "student_card_old",
-      "name": "Студентски картон (Старо) ( 0)",
-      "price": 0
-    }
-  ],
-  "documents": [
-    {
-      "id": 1,
-      "archive": "91008",
-      "date": "05.11.2024",
-      "request": "Уверение за положени испити ФИНКИ",
-      "price": 100.00,
-      "paid": "ДА",
-      "document": "Преземи",
-      "payOnline": true,
-      "status": "approved",
-      "comment": ""
-    },
-    {
-      "id": 2,
-      "archive": "91007",
-      "date": "05.11.2024",
-      "request": "УППИ образец",
-      "price": 0.00,
-      "paid": "ДА",
-      "document": "Преземи",
-      "payOnline": false,
-      "status": "approved",
-      "comment": ""
-    },
-    {
-      "id": 3,
-      "archive": "90494",
-      "date": "31.10.2024",
-      "request": "Уверение за редовен студент - ФИНКИ",
-      "price": 0.00,
-      "paid": "ДА",
-      "document": "Преземи",
-      "payOnline": false,
-      "status": "approved",
-      "comment": ""
-    },
-    {
-      "id": 4,
-      "archive": "84239",
-      "date": "10.03.2024",
-      "request": "Уверение за редовен студент - ФИНКИ",
-      "price": 0.00,
-      "paid": "ДА",
-      "document": "Преземи",
-      "payOnline": false,
-      "status": "approved",
-      "comment": ""
-    },
-    {
-      "id": 5,
-      "archive": "84238",
-      "date": "10.03.2024",
-      "request": "Уверение за положени испити ФИНКИ",
-      "price": 100.00,
-      "paid": "ДА",
-      "document": "Преземи",
-      "payOnline": true,
-      "status": "approved",
-      "comment": ""
-    },
-    {
-      "id": 6,
-      "archive": "81891",
-      "date": "12.01.2024",
-      "request": "Уверение за редовен студент - ФИНКИ",
-      "price": 0.00,
-      "paid": "ДА",
-      "document": "Преземи",
-      "payOnline": false,
-      "status": "approved",
-      "comment": ""
-    }
-  ],
-  "pagination": {
-    "currentPage": 1,
-    "totalPages": 1,
-    "totalRecords": 6,
-    "recordsPerPage": 15
-  },
-  "paymentInfo": "Онлајн плаќањата имаат банкарска провизија за безготовинско плаќање од 1,14% од оригиналната сума (минималната провизија 3,00, максималната 300,00 мкд)"
-}
Index: c/i18n.ts
===================================================================
--- src/i18n.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,23 +1,0 @@
-import i18n from 'i18next';
-import { initReactI18next } from 'react-i18next';
-
-import translationEN from './locales/en/translation.json';
-import translationMK from './locales/mk/translation.json';
-
-const resources = {
-  en: { translation: translationEN },
-  mk: { translation: translationMK },
-};
-
-i18n
-  .use(initReactI18next)
-  .init({
-    resources,
-    lng: 'mk',
-    fallbackLng: 'mk',
-    interpolation: {
-      escapeValue: false,
-    },
-  });
-
-export default i18n;
Index: c/lib/admin-api.ts
===================================================================
--- src/lib/admin-api.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,90 +1,0 @@
-import { apiUrl } from "@/lib/api";
-import { getAccessToken } from "@/lib/auth";
-
-export type AdminResult = { ok: boolean; message?: string; id?: number | null };
-
-export type SubjectRef = { id: number; name?: string; code?: string | null };
-
-export type SubjectMajor = {
-  majorId: number;
-  majorName?: string;
-  mandatorySemester: number;
-};
-
-export type AdminSubject = {
-  id: number;
-  name?: string;
-  code?: string;
-  awardedCredits: number;
-  dependencyCredit?: number | null;
-  majors: SubjectMajor[];
-  prerequisites: SubjectRef[];
-  enrolledCount: number;
-};
-
-export type AdminSemester = {
-  id: number;
-  year: number;
-  type?: string;
-  name?: string;
-  enrolmentCount: number;
-  uncoveredSubjects: SubjectRef[];
-};
-
-export type ScheduleRow = {
-  subjectId: number;
-  subjectName?: string;
-  subjectCode?: string;
-  professorId: number;
-  professorName?: string;
-};
-
-export type ProfessorLoad = {
-  professorId: number;
-  professorName?: string;
-  subjects: number;
-};
-
-export type Schedule = {
-  semesterId: number;
-  semesterName?: string;
-  assignments: ScheduleRow[];
-  load: ProfessorLoad[];
-  uncoveredSubjects: SubjectRef[];
-  allSubjects: SubjectRef[];
-  professors: { id: number; name?: string }[];
-};
-
-function authHeaders(): Record<string, string> {
-  const token = getAccessToken();
-  if (!token) throw new Error("You are not signed in.");
-  return { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
-}
-
-/** GET that throws with the server message rather than a bare status code. */
-export async function adminGet<T>(path: string): Promise<T> {
-  const res = await fetch(apiUrl(path), { cache: "no-store", headers: authHeaders() });
-  if (!res.ok) {
-    const body = await res.json().catch(() => null);
-    throw new Error(body?.message || `Request failed (${res.status})`);
-  }
-  return (await res.json()) as T;
-}
-
-/** POST/PUT/DELETE returning the standard {ok, message} envelope. */
-export async function adminSend(
-  path: string,
-  method: "POST" | "PUT" | "DELETE",
-  body?: unknown,
-): Promise<AdminResult> {
-  const res = await fetch(apiUrl(path), {
-    method,
-    headers: authHeaders(),
-    body: body === undefined ? undefined : JSON.stringify(body),
-  });
-  const result = (await res.json().catch(() => null)) as AdminResult | null;
-  if (!res.ok || !result?.ok) {
-    throw new Error(result?.message || `Request failed (${res.status})`);
-  }
-  return result;
-}
Index: c/lib/api.ts
===================================================================
--- src/lib/api.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,15 +1,0 @@
-/**
- * Base URL of the iknow-api backend.
- *
- * Set NEXT_PUBLIC_API_BASE_URL in .env.local to point at a local API run
- * (see .env.example). The faculty database is only reachable through the SSH
- * tunnel on the developer machine, so the deployed backend cannot read it -
- * working against real data means running iknow-api locally.
- */
-export const API_BASE_URL =
-  process.env.NEXT_PUBLIC_API_BASE_URL ?? 'https://iknow-api.onrender.com';
-
-/** Builds an absolute API URL from a path such as `/api/user/getUser`. */
-export function apiUrl(path: string): string {
-  return `${API_BASE_URL}${path}`;
-}
Index: c/lib/auth.ts
===================================================================
--- src/lib/auth.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,142 +1,0 @@
-import { API_BASE_URL } from './api';
-export type AuthTokens = {
-  accessToken: string;
-  refreshToken: string;
-};
-
-export type UserRole = 'Professor' | 'Student' | 'Admin' | string;
-
-export type AuthSession = AuthTokens & {
-  role: UserRole;
-};
-
-type StoredToken = {
-  value: string;
-  expiresAt: number; // epoch ms
-};
-
-const STORAGE_KEYS = {
-  access: 'iknow.auth.access',
-  refresh: 'iknow.auth.refresh',
-  role: 'iknow.auth.role',
-} as const;
-
-const ACCESS_TOKEN_TTL_MS = 60 * 60 * 1000; // 1 hour
-const REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 60 * 1000; // ~1 month (30 days)
-
-function isBrowser() {
-  return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
-}
-
-function readStoredToken(key: string): StoredToken | null {
-  if (!isBrowser()) return null;
-  const raw = window.localStorage.getItem(key);
-  if (!raw) return null;
-
-  try {
-    const parsed = JSON.parse(raw) as StoredToken;
-    if (!parsed?.value || typeof parsed.expiresAt !== 'number') {
-      window.localStorage.removeItem(key);
-      return null;
-    }
-
-    if (Date.now() >= parsed.expiresAt) {
-      window.localStorage.removeItem(key);
-      return null;
-    }
-
-    return parsed;
-  } catch {
-    window.localStorage.removeItem(key);
-    return null;
-  }
-}
-
-function writeStoredToken(key: string, value: string, ttlMs: number) {
-  if (!isBrowser()) return;
-  const payload: StoredToken = {
-    value,
-    expiresAt: Date.now() + ttlMs,
-  };
-  window.localStorage.setItem(key, JSON.stringify(payload));
-}
-
-export function setAuthTokens(tokens: AuthTokens) {
-  writeStoredToken(STORAGE_KEYS.access, tokens.accessToken, ACCESS_TOKEN_TTL_MS);
-  writeStoredToken(STORAGE_KEYS.refresh, tokens.refreshToken, REFRESH_TOKEN_TTL_MS);
-}
-
-export function setUserRole(role: UserRole) {
-  // Keep role TTL aligned with access token TTL.
-  writeStoredToken(STORAGE_KEYS.role, role, ACCESS_TOKEN_TTL_MS);
-}
-
-export function getAccessToken(): string | null {
-  return readStoredToken(STORAGE_KEYS.access)?.value ?? null;
-}
-
-export function getRefreshToken(): string | null {
-  return readStoredToken(STORAGE_KEYS.refresh)?.value ?? null;
-}
-
-export function getUserRole(): UserRole | null {
-  return readStoredToken(STORAGE_KEYS.role)?.value ?? null;
-}
-
-export function clearAuthTokens() {
-  if (!isBrowser()) return;
-  window.localStorage.removeItem(STORAGE_KEYS.access);
-  window.localStorage.removeItem(STORAGE_KEYS.refresh);
-  window.localStorage.removeItem(STORAGE_KEYS.role);
-}
-
-export async function login(params: { email: string; password: string }): Promise<AuthSession> {
-  const baseUrl = API_BASE_URL;
-
-  const response = await fetch(`${baseUrl}/api/auth/login`, {
-    method: 'POST',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-    body: JSON.stringify({
-      email: params.email,
-      password: params.password,
-      GenerateRefreshToken: true,
-    }),
-  });
-
-  if (!response.ok) {
-    let message = `Login failed (${response.status})`;
-    try {
-      const text = await response.text();
-      if (text) message = text;
-    } catch {
-      // ignore
-    }
-    throw new Error(message);
-  }
-
-  const data = (await response.json()) as {
-    token?: string;
-    refreshToken?: string;
-    role?: string;
-  };
-
-  const accessToken = data?.token;
-  const refreshToken = data?.refreshToken;
-  const role = data?.role;
-
-  if (!accessToken || !refreshToken) {
-    throw new Error('Login response did not contain tokens.');
-  }
-
-  const session: AuthSession = {
-    accessToken,
-    refreshToken,
-    role: role ?? 'Student',
-  };
-
-  setAuthTokens(session);
-  setUserRole(session.role);
-  return session;
-}
Index: c/lib/pdf-fonts.ts
===================================================================
--- src/lib/pdf-fonts.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,32 +1,0 @@
-import { jsPDF } from 'jspdf';
-
-let fontsLoaded = false;
-let regularFontBase64: string | null = null;
-let boldFontBase64: string | null = null;
-
-async function fetchFontAsBase64(url: string): Promise<string> {
-  const response = await fetch(url);
-  const buffer = await response.arrayBuffer();
-  const bytes = new Uint8Array(buffer);
-  let binary = '';
-  for (let i = 0; i < bytes.length; i++) {
-    binary += String.fromCharCode(bytes[i]);
-  }
-  return btoa(binary);
-}
-
-export async function loadCyrillicFonts(doc: jsPDF): Promise<void> {
-  if (!fontsLoaded) {
-    regularFontBase64 = await fetchFontAsBase64('/fonts/Roboto-Regular.ttf');
-    boldFontBase64 = await fetchFontAsBase64('/fonts/Roboto-Bold.ttf');
-    fontsLoaded = true;
-  }
-
-  doc.addFileToVFS('Roboto-Regular.ttf', regularFontBase64!);
-  doc.addFont('Roboto-Regular.ttf', 'Roboto', 'normal');
-
-  doc.addFileToVFS('Roboto-Bold.ttf', boldFontBase64!);
-  doc.addFont('Roboto-Bold.ttf', 'Roboto', 'bold');
-
-  doc.setFont('Roboto', 'normal');
-}
Index: c/lib/pdf-generators.ts
===================================================================
--- src/lib/pdf-generators.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,1207 +1,0 @@
-import { jsPDF } from 'jspdf';
-import autoTable from 'jspdf-autotable';
-import { loadCyrillicFonts } from './pdf-fonts';
-import { apiUrl } from './api';
-
-/* ---------- shared types ---------- */
-
-export type StudentInfo = {
-  firstName: string;
-  middleName: string;
-  lastName: string;
-  index: string;
-  embg: string;
-  dateOfBirth: string;
-  gender: string;
-  nationality: string;
-  citizenship: string;
-  currentPlan: string;
-  registryNumber: string;
-  studyGroup: string;
-  scholarship: string;
-};
-
-export type EnrollmentInfo = {
-  enrollmentYear: string | number;
-  status: string;
-  cycle: string;
-  program: string;
-  quota: string;
-};
-
-export type BirthInfo = {
-  placeOfBirth: string;
-  municipalityOfBirth: string;
-  country: string;
-};
-
-export type ContactInfo = {
-  placeOfResidence: string;
-  municipalityOfResidence: string;
-  address: string;
-  phone: string;
-  mobilePhone: string;
-  email: string;
-};
-
-export type PassedExam = {
-  id: number;
-  code: string;
-  subject: string;
-  credits: number;
-  grade: number;
-  date: string;
-  semester: string;
-  professor: string;
-};
-
-export type PreviousEducation = {
-  type: string;
-  profession: string;
-  average: string | number;
-  language: string;
-  country: string;
-  previousUniversity: string;
-  previousFaculty: string;
-};
-
-/* ---------- helpers ---------- */
-
-const PAGE_WIDTH = 210; // A4 mm
-const MARGIN = 20;
-const CONTENT_WIDTH = PAGE_WIDTH - 2 * MARGIN;
-
-function drawUniversityHeader(doc: jsPDF, y: number): number {
-  doc.setFont('Roboto', 'bold');
-
-  doc.setFontSize(11);
-  doc.text('УНИВЕРЗИТЕТ „СВ. КИРИЛ И МЕТОДИЈ" - СКОПЈЕ', PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 6;
-
-  doc.setFontSize(10);
-  doc.text('ФАКУЛТЕТ ЗА ИНФОРМАТИЧКИ НАУКИ И', PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 5;
-  doc.text('КОМПЈУТЕРСКО ИНЖЕНЕРСТВО', PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 5;
-
-  // Horizontal line under header
-  doc.setDrawColor(0, 114, 209); // primary blue
-  doc.setLineWidth(0.5);
-  doc.line(MARGIN, y, PAGE_WIDTH - MARGIN, y);
-  y += 8;
-
-  return y;
-}
-
-function drawDocumentTitle(doc: jsPDF, title: string, y: number): number {
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(14);
-  doc.text(title, PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 10;
-  return y;
-}
-
-function drawInfoRow(doc: jsPDF, label: string, value: string, x: number, y: number, labelWidth = 50): number {
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.text(`${label}:`, x, y);
-  doc.setFont('Roboto', 'normal');
-  doc.text(String(value || '—'), x + labelWidth, y);
-  return y + 5.5;
-}
-
-function drawFooter(doc: jsPDF, archiveNumber: string, date: string): void {
-  const pageHeight = doc.internal.pageSize.getHeight();
-  let y = pageHeight - 40;
-
-  doc.setDrawColor(0, 114, 209);
-  doc.setLineWidth(0.3);
-  doc.line(MARGIN, y, PAGE_WIDTH - MARGIN, y);
-  y += 8;
-
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(9);
-
-  doc.text(`Бр.: ${archiveNumber}`, MARGIN, y);
-  doc.text(`Датум: ${date}`, PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 12;
-
-  // Signature placeholders
-  doc.text('Потпис на студентот:', MARGIN, y);
-  doc.text('М.П.', PAGE_WIDTH / 2, y, { align: 'center' });
-  doc.text('Одговорно лице:', PAGE_WIDTH - MARGIN - 35, y);
-  y += 8;
-
-  doc.setDrawColor(150, 150, 150);
-  doc.setLineWidth(0.2);
-  doc.line(MARGIN, y, MARGIN + 45, y);
-  doc.line(PAGE_WIDTH / 2 - 15, y, PAGE_WIDTH / 2 + 15, y);
-  doc.line(PAGE_WIDTH - MARGIN - 45, y, PAGE_WIDTH - MARGIN, y);
-}
-
-/* ==================================================================
-   PDF 1 — Уверение за положени испити (Certificate of Passed Exams)
-   ================================================================== */
-
-export async function generatePassedExamsCertificate(
-  student: StudentInfo,
-  enrollment: EnrollmentInfo,
-  passedExams: PassedExam[],
-  archiveNumber: string,
-  date: string,
-): Promise<void> {
-  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
-  await loadCyrillicFonts(doc);
-
-  let y = 20;
-
-  // --- Header ---
-  y = drawUniversityHeader(doc, y);
-
-  // --- Title ---
-  y = drawDocumentTitle(doc, 'УВЕРЕНИЕ ЗА ПОЛОЖЕНИ ИСПИТИ', y);
-
-  // --- Student Info Block ---
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(9);
-
-  y = drawInfoRow(doc, 'Студент', `${student.firstName} ${student.middleName} ${student.lastName}`, MARGIN, y);
-  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y);
-  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y);
-  y = drawInfoRow(doc, 'Циклус на студии', enrollment.cycle, MARGIN, y);
-  y = drawInfoRow(doc, 'Статус', enrollment.status, MARGIN, y);
-  y += 4;
-
-  // --- Passed Exams Table ---
-  const tableBody = passedExams.map((exam, idx) => [
-    String(idx + 1),
-    exam.code,
-    exam.subject,
-    String(exam.credits),
-    String(exam.grade),
-    exam.date,
-    exam.semester,
-    exam.professor || '—',
-  ]);
-
-  autoTable(doc, {
-    startY: y,
-    head: [['Р.Б.', 'Шифра', 'Предмет', 'Кредити', 'Оцена', 'Датум', 'Семестар', 'Професор']],
-    body: tableBody,
-    theme: 'grid',
-    styles: {
-      font: 'Roboto',
-      fontSize: 7.5,
-      cellPadding: 2,
-      textColor: [30, 30, 30],
-      lineColor: [200, 200, 200],
-      lineWidth: 0.2,
-    },
-    headStyles: {
-      fillColor: [0, 114, 209],
-      textColor: [255, 255, 255],
-      fontStyle: 'bold',
-      fontSize: 7.5,
-      halign: 'center',
-    },
-    columnStyles: {
-      0: { halign: 'center', cellWidth: 10 },
-      1: { halign: 'center', cellWidth: 16 },
-      2: { cellWidth: 50 },
-      3: { halign: 'center', cellWidth: 14 },
-      4: { halign: 'center', cellWidth: 12 },
-      5: { halign: 'center', cellWidth: 20 },
-      6: { cellWidth: 22 },
-      7: { cellWidth: 26 },
-    },
-    margin: { left: MARGIN, right: MARGIN },
-    didParseCell: (data) => {
-      if (data.section === 'body' && data.row.index % 2 === 0) {
-        data.cell.styles.fillColor = [245, 247, 250];
-      }
-    },
-  });
-
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  y = (doc as any).lastAutoTable.finalY + 8;
-
-  // --- Summary ---
-  const totalCredits = passedExams.reduce((sum, e) => sum + e.credits, 0);
-  const grades = passedExams.map((e) => e.grade).filter((g) => g > 0);
-  const average = grades.length > 0 ? (grades.reduce((s, g) => s + g, 0) / grades.length).toFixed(2) : '0.00';
-
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(10);
-  doc.text(`Вкупно положени предмети: ${passedExams.length}`, MARGIN, y);
-  y += 6;
-  doc.text(`Вкупно кредити: ${totalCredits}`, MARGIN, y);
-  y += 6;
-  doc.text(`Просечна оцена: ${average}`, MARGIN, y);
-
-  // --- Footer ---
-  drawFooter(doc, archiveNumber, date);
-
-  doc.save(`Уверение_положени_испити_${student.index}.pdf`);
-}
-
-/* ==================================================================
-   PDF 2 — УППИ образец (UPPI Form / Student Record)
-   ================================================================== */
-
-export async function generateUPPIForm(
-  student: StudentInfo,
-  enrollment: EnrollmentInfo,
-  birth: BirthInfo,
-  contact: ContactInfo,
-  previousEdu: PreviousEducation,
-  passedExams: PassedExam[],
-  archiveNumber: string,
-  date: string,
-): Promise<void> {
-  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
-  await loadCyrillicFonts(doc);
-
-  let y = 20;
-
-  // --- Header ---
-  y = drawUniversityHeader(doc, y);
-
-  // --- Title ---
-  y = drawDocumentTitle(doc, 'УППИ ОБРАЗЕЦ', y);
-
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.text('УНИВЕРЗАЛНА ПРИЈАВА ЗА ПРАКТИЧНА ИНДИВИДУАЛНА РАБОТА', PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 10;
-
-  // --- Section: Personal Information ---
-  doc.setFillColor(0, 114, 209);
-  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.setTextColor(255, 255, 255);
-  doc.text('ЛИЧНИ ПОДАТОЦИ', MARGIN + 3, y + 0.5);
-  doc.setTextColor(30, 30, 30);
-  y += 10;
-
-  const col2X = MARGIN + CONTENT_WIDTH / 2;
-
-  y = drawInfoRow(doc, 'Име', student.firstName, MARGIN, y, 35);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'Презиме', student.lastName, col2X, y, 35);
-  y = drawInfoRow(doc, 'Татково име', student.middleName, MARGIN, y, 35);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'ЕМБГ', student.embg, col2X, y, 35);
-  y = drawInfoRow(doc, 'Датум на раѓање', student.dateOfBirth, MARGIN, y, 35);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'Пол', student.gender, col2X, y, 35);
-  y = drawInfoRow(doc, 'Националност', student.nationality, MARGIN, y, 35);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'Државјанство', student.citizenship, col2X, y, 35);
-  y += 3;
-
-  // --- Section: Birth Info ---
-  doc.setFillColor(0, 114, 209);
-  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.setTextColor(255, 255, 255);
-  doc.text('ПОДАТОЦИ ЗА РАЃАЊЕ', MARGIN + 3, y + 0.5);
-  doc.setTextColor(30, 30, 30);
-  y += 10;
-
-  y = drawInfoRow(doc, 'Место на раѓање', birth.placeOfBirth, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Општина', birth.municipalityOfBirth, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Држава', birth.country, MARGIN, y, 40);
-  y += 3;
-
-  // --- Section: Contact ---
-  doc.setFillColor(0, 114, 209);
-  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.setTextColor(255, 255, 255);
-  doc.text('КОНТАКТ ИНФОРМАЦИИ', MARGIN + 3, y + 0.5);
-  doc.setTextColor(30, 30, 30);
-  y += 10;
-
-  y = drawInfoRow(doc, 'Место на живеење', contact.placeOfResidence, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Адреса', contact.address, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Телефон', contact.phone || contact.mobilePhone, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Е-пошта', contact.email, MARGIN, y, 40);
-  y += 3;
-
-  // --- Section: Enrollment ---
-  doc.setFillColor(0, 114, 209);
-  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.setTextColor(255, 255, 255);
-  doc.text('СТУДИСКИ ИНФОРМАЦИИ', MARGIN + 3, y + 0.5);
-  doc.setTextColor(30, 30, 30);
-  y += 10;
-
-  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y, 40);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'Мат. број', student.registryNumber, col2X, y, 35);
-  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Циклус', enrollment.cycle, MARGIN, y, 40);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'Статус', enrollment.status, col2X, y, 35);
-  y = drawInfoRow(doc, 'Год. на запишување', String(enrollment.enrollmentYear), MARGIN, y, 40);
-  y -= 5.5;
-  y = drawInfoRow(doc, 'Квота', enrollment.quota, col2X, y, 35);
-  y += 3;
-
-  // --- Section: Previous Education ---
-  doc.setFillColor(0, 114, 209);
-  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.setTextColor(255, 255, 255);
-  doc.text('ПРЕТХОДНО ОБРАЗОВАНИЕ', MARGIN + 3, y + 0.5);
-  doc.setTextColor(30, 30, 30);
-  y += 10;
-
-  y = drawInfoRow(doc, 'Вид', previousEdu.type, MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Просек', String(previousEdu.average), MARGIN, y, 40);
-  y = drawInfoRow(doc, 'Јазик', previousEdu.language, MARGIN, y, 40);
-  y += 3;
-
-  // --- Section: Passed Exams mini-table ---
-  doc.setFillColor(0, 114, 209);
-  doc.rect(MARGIN, y - 4, CONTENT_WIDTH, 7, 'F');
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.setTextColor(255, 255, 255);
-  doc.text('ПОЛОЖЕНИ ИСПИТИ', MARGIN + 3, y + 0.5);
-  doc.setTextColor(30, 30, 30);
-  y += 8;
-
-  const examTableBody = passedExams.map((exam, idx) => [
-    String(idx + 1),
-    exam.code,
-    exam.subject,
-    String(exam.credits),
-    String(exam.grade),
-    exam.date,
-  ]);
-
-  autoTable(doc, {
-    startY: y,
-    head: [['#', 'Шифра', 'Предмет', 'Кредити', 'Оцена', 'Датум']],
-    body: examTableBody,
-    theme: 'grid',
-    styles: {
-      font: 'Roboto',
-      fontSize: 7,
-      cellPadding: 1.5,
-      textColor: [30, 30, 30],
-      lineColor: [200, 200, 200],
-      lineWidth: 0.2,
-    },
-    headStyles: {
-      fillColor: [0, 114, 209],
-      textColor: [255, 255, 255],
-      fontStyle: 'bold',
-      fontSize: 7,
-      halign: 'center',
-    },
-    columnStyles: {
-      0: { halign: 'center', cellWidth: 8 },
-      1: { halign: 'center', cellWidth: 18 },
-      2: { cellWidth: 70 },
-      3: { halign: 'center', cellWidth: 16 },
-      4: { halign: 'center', cellWidth: 14 },
-      5: { halign: 'center', cellWidth: 22 },
-    },
-    margin: { left: MARGIN, right: MARGIN },
-    didParseCell: (data) => {
-      if (data.section === 'body' && data.row.index % 2 === 0) {
-        data.cell.styles.fillColor = [245, 247, 250];
-      }
-    },
-  });
-
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  y = (doc as any).lastAutoTable.finalY + 8;
-
-  // Summary
-  const totalCredits = passedExams.reduce((sum, e) => sum + e.credits, 0);
-  const grades = passedExams.map((e) => e.grade).filter((g) => g > 0);
-  const average = grades.length > 0 ? (grades.reduce((s, g) => s + g, 0) / grades.length).toFixed(2) : '0.00';
-
-  doc.setFont('Roboto', 'bold');
-  doc.setFontSize(9);
-  doc.text(`Вкупно кредити: ${totalCredits}    |    Просечна оцена: ${average}`, MARGIN, y);
-
-  // Footer
-  drawFooter(doc, archiveNumber, date);
-
-  doc.save(`УППИ_образец_${student.index}.pdf`);
-}
-
-/* ==================================================================
-   PDF 3 — Уверение за редовен студент (Regular Student Certificate)
-   ================================================================== */
-
-export async function generateRegularStudentCertificate(
-  student: StudentInfo,
-  enrollment: EnrollmentInfo,
-  passedExams: PassedExam[],
-  archiveNumber: string,
-  date: string,
-): Promise<void> {
-  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
-  await loadCyrillicFonts(doc);
-
-  let y = 20;
-
-  // --- Header ---
-  y = drawUniversityHeader(doc, y);
-
-  // --- Title ---
-  y = drawDocumentTitle(doc, 'УВЕРЕНИЕ', y);
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(10);
-  doc.text('за редовен студент', PAGE_WIDTH / 2, y, { align: 'center' });
-  y += 12;
-
-  // --- Body text ---
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(10);
-
-  const totalCredits = passedExams.reduce((sum, e) => sum + e.credits, 0);
-  const grades = passedExams.map((e) => e.grade).filter((g) => g > 0);
-  const average = grades.length > 0 ? (grades.reduce((s, g) => s + g, 0) / grades.length).toFixed(2) : '0.00';
-
-  const bodyText = [
-    `Со ова се потврдува дека студентот/студентката`,
-    ``,
-    `${student.firstName} ${student.middleName} ${student.lastName}`,
-    ``,
-    `со индекс број ${student.index}, ЕМБГ ${student.embg},`,
-    `е редовен студент на Факултетот за информатички науки и компјутерско`,
-    `инженерство при Универзитетот „Св. Кирил и Методиј" - Скопје.`,
-    ``,
-    `Студиска програма: ${enrollment.program}`,
-    `Циклус на студии: ${enrollment.cycle}`,
-    `Статус: ${enrollment.status}`,
-    `Година на запишување: ${enrollment.enrollmentYear}`,
-    ``,
-    `Студентот/студентката до сега има положено ${passedExams.length} испити,`,
-    `со вкупно ${totalCredits} кредити и просечна оцена ${average}.`,
-    ``,
-    `Ова уверение се издава за потребите на студентот/студентката`,
-    `и може да послужи за секоја законска употреба.`,
-  ];
-
-  for (const line of bodyText) {
-    if (line === '') {
-      y += 4;
-    } else {
-      if (line.startsWith(`${student.firstName}`)) {
-        doc.setFont('Roboto', 'bold');
-        doc.setFontSize(12);
-        doc.text(line, PAGE_WIDTH / 2, y, { align: 'center' });
-        doc.setFont('Roboto', 'normal');
-        doc.setFontSize(10);
-      } else {
-        doc.text(line, MARGIN, y);
-      }
-      y += 6;
-    }
-  }
-
-  // Footer
-  drawFooter(doc, archiveNumber, date);
-
-  doc.save(`Уверение_редовен_студент_${student.index}.pdf`);
-}
-
-/* ==================================================================
-   Generic document — fallback for other document types
-   ================================================================== */
-
-export async function generateGenericDocument(
-  student: StudentInfo,
-  enrollment: EnrollmentInfo,
-  documentTitle: string,
-  archiveNumber: string,
-  date: string,
-): Promise<void> {
-  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
-  await loadCyrillicFonts(doc);
-
-  let y = 20;
-
-  y = drawUniversityHeader(doc, y);
-  y = drawDocumentTitle(doc, documentTitle.toUpperCase(), y);
-
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(10);
-
-  y = drawInfoRow(doc, 'Студент', `${student.firstName} ${student.middleName} ${student.lastName}`, MARGIN, y);
-  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y);
-  y = drawInfoRow(doc, 'ЕМБГ', student.embg, MARGIN, y);
-  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y);
-  y = drawInfoRow(doc, 'Циклус', enrollment.cycle, MARGIN, y);
-  y = drawInfoRow(doc, 'Статус', enrollment.status, MARGIN, y);
-  y += 8;
-
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(10);
-  doc.text('Документот е издаден по барање на студентот.', MARGIN, y);
-
-  drawFooter(doc, archiveNumber, date);
-
-  doc.save(`${documentTitle.replace(/\s+/g, '_')}_${student.index}.pdf`);
-}
-
-/* ==================================================================
-   Themed request generators — one for each document type
-   ================================================================== */
-
-async function generateRequestDocument(
-  student: StudentInfo,
-  enrollment: EnrollmentInfo,
-  title: string,
-  bodyLines: string[],
-  archiveNumber: string,
-  date: string,
-  filename: string,
-): Promise<void> {
-  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
-  await loadCyrillicFonts(doc);
-
-  let y = 20;
-
-  y = drawUniversityHeader(doc, y);
-  y = drawDocumentTitle(doc, title, y);
-
-  // Student info block
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(9);
-  y = drawInfoRow(doc, 'Студент', `${student.firstName} ${student.middleName} ${student.lastName}`, MARGIN, y);
-  y = drawInfoRow(doc, 'Индекс', student.index, MARGIN, y);
-  y = drawInfoRow(doc, 'ЕМБГ', student.embg, MARGIN, y);
-  y = drawInfoRow(doc, 'Студиска програма', enrollment.program, MARGIN, y);
-  y = drawInfoRow(doc, 'Циклус', enrollment.cycle, MARGIN, y);
-  y = drawInfoRow(doc, 'Статус', enrollment.status, MARGIN, y);
-  y = drawInfoRow(doc, 'Година на упис', String(enrollment.enrollmentYear), MARGIN, y);
-  y += 8;
-
-  // Separator
-  doc.setDrawColor(200, 200, 200);
-  doc.setLineWidth(0.3);
-  doc.line(MARGIN, y, PAGE_WIDTH - MARGIN, y);
-  y += 8;
-
-  // Body text
-  doc.setFont('Roboto', 'normal');
-  doc.setFontSize(10);
-  for (const line of bodyLines) {
-    if (line === '') {
-      y += 5;
-    } else {
-      const wrapped = doc.splitTextToSize(line, CONTENT_WIDTH);
-      for (const wl of wrapped) {
-        doc.text(wl, MARGIN, y);
-        y += 5.5;
-      }
-    }
-  }
-
-  drawFooter(doc, archiveNumber, date);
-  doc.save(`${filename}_${student.index}.pdf`);
-}
-
-// --- Administrative Regulation ---
-export async function generateAdministrativeRegulation(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА АДМИНИСТРАТИВНО РЕГУЛИРАЊЕ НА РЕТРОАКТИВЕН СЕМЕСТАР',
-    [
-      `До: Деканат на Факултетот за информатички науки и компјутерско инженерство`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `запишан/а на студиската програма ${enrollment.program}, ${enrollment.cycle} циклус студии,`,
-      `со ова барање побарувам административно регулирање на ретроактивен семестар.`,
-      '',
-      `Молам да ми се одобри административна регулација на семестар кој не е запишан во предвидениот рок,`,
-      `согласно одлуката на Факултетот и важечката регулатива.`,
-      '',
-      `Прилози: Уплатница за административна такса од 1000 ден.`,
-    ],
-    archiveNumber, date, 'Административно_регулирање');
-}
-
-// --- Late Exam Registration ---
-export async function generateExamApplicationSatisfaction(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ЗАДОЧНО ПРИЈАВУВАЊЕ НА ИСПИТ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `запишан/а на студиската програма ${enrollment.program},`,
-      `побарувам задочно пријавување на испит кој не е пријавен во предвидениот рок.`,
-      '',
-      `Причина за задоцнување: ___________________________________`,
-      '',
-      `Молам за одобрување на ова барање.`,
-      '',
-      `Прилози: Уплатница за административна такса од 1000 ден.`,
-    ],
-    archiveNumber, date, 'Задочно_пријавување_испит');
-}
-
-// --- Semester Enrollment After Deadline ---
-export async function generateSemesterEnrollmentAfterDeadline(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ЗАПИШУВАЊЕ НА СЕМЕСТАР ПО ИСТЕК НА РОК',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам да ми се одобри запишување на нареден семестар по истекот на официјалниот рок.`,
-      '',
-      `Причина за задоцнето запишување: ___________________________________`,
-      '',
-      `Молам за одобрување.`,
-      '',
-      `Прилози: Уплатница за административна такса од 1500 ден.`,
-    ],
-    archiveNumber, date, 'Запишување_семестар_по_рок');
-}
-
-// --- Certificate Issuance ---
-export async function generateCertificateIssuanceVarious(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ИЗДАВАЊЕ НА ПОТВРДИ ПО РАЗНИ ОСНОВИ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам издавање на потврда за следната намена:`,
-      '',
-      `Намена: ___________________________________`,
-      '',
-      `Молам да ми биде издадена бараната потврда.`,
-      '',
-      `Прилози: Уплатница за административна такса од 1500 ден.`,
-    ],
-    archiveNumber, date, 'Издавање_потврди');
-}
-
-// --- Study Suspension ---
-export async function generateStudySuspension(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА МИРУВАЊЕ НА СТУДИИТЕ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `запишан/а на студиската програма ${enrollment.program},`,
-      `побарувам мирување на студиите за период од ______ семестри.`,
-      '',
-      `Причина за мирување: ___________________________________`,
-      '',
-      `Изјавувам дека сум запознаен/а со правилата за продолжување на студиите`,
-      `по истекот на периодот на мирување.`,
-      '',
-      `Прилози: Уплатница за административна такса од 2000 ден.`,
-    ],
-    archiveNumber, date, 'Мирување_студии');
-}
-
-// --- Diploma Thesis Cancellation ---
-export async function generateDiplomaThesisCancellation(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ОТКАЖУВАЊЕ НА ПРИЈАВЕНА ТЕМА ЗА ДИПЛОМСКА РАБОТА',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам откажување на претходно пријавената тема за дипломска работа.`,
-      '',
-      `Назив на темата: ___________________________________`,
-      `Ментор: ___________________________________`,
-      '',
-      `Причина за откажување: ___________________________________`,
-      '',
-      `Прилози: Уплатница за административна такса од 1000 ден.`,
-    ],
-    archiveNumber, date, 'Откажување_дипломска');
-}
-
-// --- Graduation Package ---
-export async function generateDiplomaPackage(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПАКЕТ ЗА ДИПЛОМИРАЊЕ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `запишан/а на студиската програма ${enrollment.program}, ${enrollment.cycle} циклус,`,
-      `побарувам издавање на пакет за дипломирање.`,
-      '',
-      `Со ова потврдувам дека ги имам исполнето сите услови за дипломирање`,
-      `согласно студиската програма и правилникот на Факултетот.`,
-      '',
-      `Пакетот за дипломирање ги вклучува: диплома, додаток на диплома и свечена промоција.`,
-      '',
-      `Прилози: Уплатница за административна такса од 6200 ден.`,
-    ],
-    archiveNumber, date, 'Пакет_дипломирање');
-}
-
-// --- Exam Cancellation ---
-export async function generateExamCancellation(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПОНИШТУВАЊЕ НА ИСПИТ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам поништување на испит по предметот:`,
-      '',
-      `Предмет: ___________________________________`,
-      `Датум на полагање: ___________________________________`,
-      '',
-      `Причина за поништување: ___________________________________`,
-      '',
-      `Прилози: Уплатница за административна такса од 2000 ден.`,
-    ],
-    archiveNumber, date, 'Поништување_испит');
-}
-
-// --- Study Continuation ---
-export async function generateStudyContinuation(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПРОДОЛЖУВАЊЕ НА СТУДИИ ВО МИРУВАЊЕ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам продолжување на студиите по периодот на мирување.`,
-      '',
-      `Период на мирување: од ____________ до ____________`,
-      '',
-      `Молам да ми се одобри продолжување на студиите согласно тековната`,
-      `студиска програма и важечкиот правилник.`,
-      '',
-      `Прилози: Уплатница за административна такса од 2000 ден.`,
-    ],
-    archiveNumber, date, 'Продолжување_студии');
-}
-
-// --- Elective Subject Change ---
-export async function generateElectiveSubjectChange(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПРОМЕНА НА ИЗБОРЕН ПРЕДМЕТ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам промена на изборен предмет.`,
-      '',
-      `Предмет што се менува: ___________________________________`,
-      `Нов изборен предмет: ___________________________________`,
-      '',
-      `Причина за промена: ___________________________________`,
-      '',
-      `Прилози: Уплатница за административна такса од 1500 ден.`,
-    ],
-    archiveNumber, date, 'Промена_изборен_предмет');
-}
-
-// --- Passed Subject Change ---
-export async function generatePassedSubjectChange(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПРОМЕНА НА ПОЛОЖЕН ПРЕДМЕТ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам промена / корекција на запис за положен предмет.`,
-      '',
-      `Предмет: ___________________________________`,
-      `Датум на полагање: ___________________________________`,
-      `Оцена: ___________________________________`,
-      '',
-      `Детали за промена: ___________________________________`,
-    ],
-    archiveNumber, date, 'Промена_положен_предмет');
-}
-
-// --- Study Program Change (Same Accreditation) ---
-export async function generateProgramChangeSameAccreditation(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПРОМЕНА НА СТУДИСКА ПРОГРАМА ОД ИСТА АКРЕДИТАЦИЈА',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `тековно запишан/а на програмата ${enrollment.program},`,
-      `побарувам промена на студиска програма во рамки на истата акредитација.`,
-      '',
-      `Нова студиска програма: ___________________________________`,
-      '',
-      `Причина за промена: ___________________________________`,
-      '',
-      `Прилози: Уплатница за административна такса од 2000 ден.`,
-    ],
-    archiveNumber, date, 'Промена_програма_иста_акредитација');
-}
-
-// --- Study Program Change (New Accreditation) ---
-export async function generateProgramChangeNewAccreditation(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'БАРАЊЕ ЗА ПРОМЕНА НА СТУДИСКА ПРОГРАМА ОД ПОНОВА АКРЕДИТАЦИЈА',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `тековно запишан/а на програмата ${enrollment.program},`,
-      `побарувам промена на студиска програма во рамки на нова акредитација.`,
-      '',
-      `Нова студиска програма: ___________________________________`,
-      `Нова акредитација: ___________________________________`,
-      '',
-      `Причина за промена: ___________________________________`,
-      '',
-      `Прилози: Уплатница за административна такса од 3000 ден.`,
-    ],
-    archiveNumber, date, 'Промена_програма_нова_акредитација');
-}
-
-// --- Diploma Supplement ---
-export async function generateDiplomaSupplement(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'ДОДАТОК НА ДИПЛОМА',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `запишан/а на студиската програма ${enrollment.program}, ${enrollment.cycle} циклус,`,
-      `побарувам издавање на додаток на диплома.`,
-      '',
-      `Додатокот на дипломата се издава како придружен документ`,
-      `кон дипломата за завршените студии.`,
-    ],
-    archiveNumber, date, 'Додаток_диплома');
-}
-
-// --- Diploma Supplement Second Cycle ---
-export async function generateDiplomaSupplementSecondCycle(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'ДОДАТОК НА ДИПЛОМА (ВТОР ЦИКЛУС)',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `запишан/а на студиската програма ${enrollment.program}, втор циклус на студии,`,
-      `побарувам издавање на додаток на диплома за вториот циклус студии.`,
-      '',
-      `Додатокот на дипломата се издава како придружен документ`,
-      `кон магистерската диплома.`,
-    ],
-    archiveNumber, date, 'Додаток_диплома_втор_циклус');
-}
-
-// --- MKSA ---
-export async function generateMKSA(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'МКСА - МАКЕДОНСКА КВАЛИФИКАЦИСКА РАМКА',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам издавање на МКСА (Македонска Квалификациска Рамка) документ.`,
-      '',
-      `Студиска програма: ${enrollment.program}`,
-      `Циклус: ${enrollment.cycle}`,
-      '',
-      `Документот е потребен за целите на: ___________________________________`,
-      '',
-      `Прилози: Уплатница за административна такса од 750 ден.`,
-    ],
-    archiveNumber, date, 'МКСА');
-}
-
-// --- Exam Recognition ---
-export async function generateExamRecognition(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'ПРИЗНАВАЊЕ НА ПОЛОЖЕНИ ИСПИТИ',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам признавање на положени испити од претходна институција / програма.`,
-      '',
-      `Претходна институција: ___________________________________`,
-      `Претходна програма: ___________________________________`,
-      '',
-      `Листа на предмети за признавање:`,
-      `1. ___________________________________`,
-      `2. ___________________________________`,
-      `3. ___________________________________`,
-      '',
-      `Прилози: Уверение за положени испити од претходна институција.`,
-    ],
-    archiveNumber, date, 'Признавање_испити');
-}
-
-// --- Student Card (Old) ---
-export async function generateStudentCardOld(
-  student: StudentInfo, enrollment: EnrollmentInfo, archiveNumber: string, date: string,
-): Promise<void> {
-  await generateRequestDocument(student, enrollment,
-    'СТУДЕНТСКИ КАРТОН (СТАРО)',
-    [
-      `До: Деканат на ФИНКИ`,
-      '',
-      `Јас, ${student.firstName} ${student.middleName} ${student.lastName}, студент/ка со индекс ${student.index},`,
-      `побарувам издавање на студентски картон (стар формат).`,
-      '',
-      `Студиска програма: ${enrollment.program}`,
-      `Година на упис: ${enrollment.enrollmentYear}`,
-      '',
-      `Молам да ми биде издаден студентски картон.`,
-    ],
-    archiveNumber, date, 'Студентски_картон');
-}
-
-/* ==================================================================
-   Main dispatcher — called from the Documents page
-   ================================================================== */
-
-// Map document type IDs → generator function names
-const DOCUMENT_TYPE_MAP: Record<string, string> = {
-  'административно регулирање': 'administrative_regulation',
-  'задочно пријавување': 'exam_application_satisfaction',
-  'запишување на семестар по истек': 'semester_enrollment_after_deadline',
-  'издавање потврди': 'certificate_issuance_various',
-  'мирување на студиите': 'student_status_verification',
-  'откажување на пријавена тема': 'diploma_thesis_postponement',
-  'пакет за дипломирање': 'diploma_package',
-  'поништување на испит': 'exam_postponement',
-  'потврда за редовен студент': 'regular_student_certificate',
-  'продолжување на студии во мирување': 'study_continuation_verification',
-  'промена на изборен предмет': 'failed_subject_grade_change',
-  'промена на положен предмет': 'passed_subject_grade_change',
-  'промена на студиска програма од иста': 'study_program_change_same_accreditation',
-  'промена на студиска програма од понова': 'study_program_change_new_accreditation',
-  'додаток на диплома (втор циклус)': 'diploma_supplement_second_cycle',
-  'додаток на диплома': 'diploma_supplement',
-  'мкса': 'mksa',
-  'признавање на положени испити': 'exam_recognition',
-  'студентски картон': 'student_card_old',
-};
-
-function identifyDocumentType(request: string): string | null {
-  const lower = request.toLowerCase();
-
-  // Exact-match patterns (check longer patterns first)
-  if (lower.includes('положени испити')) return 'passed_exams_certificate';
-  if (lower.includes('уппи')) return 'uppi_form';
-  if (lower.includes('редовен студент')) return 'regular_student_certificate';
-
-  // Match by document type keywords
-  for (const [keyword, docType] of Object.entries(DOCUMENT_TYPE_MAP)) {
-    if (lower.includes(keyword)) return docType;
-  }
-
-  return null;
-}
-
-export async function downloadDocumentPDF(
-  documentRequest: string,
-  archiveNumber: string,
-  documentDate: string,
-  accessToken: string,
-): Promise<void> {
-  // Fetch student profile
-  const profileRes = await fetch(apiUrl('/api/user/getUser'), {
-    headers: { Authorization: `Bearer ${accessToken}` },
-  });
-  if (!profileRes.ok) throw new Error('Не може да се вчита профилот на студентот');
-
-  const profile = await profileRes.json();
-  const { personalInfo, enrollmentInfo, birthInfo, contact, previousEducation } = profile;
-
-  const student: StudentInfo = {
-    firstName: personalInfo.firstName,
-    middleName: personalInfo.middleName,
-    lastName: personalInfo.lastName,
-    index: personalInfo.index,
-    embg: personalInfo.embg,
-    dateOfBirth: personalInfo.dateOfBirth,
-    gender: personalInfo.gender,
-    nationality: personalInfo.nationality,
-    citizenship: personalInfo.citizenship,
-    currentPlan: personalInfo.currentPlan,
-    registryNumber: personalInfo.registryNumber,
-    studyGroup: personalInfo.studyGroup,
-    scholarship: personalInfo.scholarship,
-  };
-
-  const enrollment: EnrollmentInfo = {
-    enrollmentYear: enrollmentInfo.enrollmentYear,
-    status: enrollmentInfo.status,
-    cycle: enrollmentInfo.cycle,
-    program: enrollmentInfo.program,
-    quota: enrollmentInfo.quota,
-  };
-
-  const docType = identifyDocumentType(documentRequest);
-
-  // Types that need passed exams data
-  const needsExams = docType === 'passed_exams_certificate' || docType === 'uppi_form' || docType === 'regular_student_certificate';
-
-  let passedExams: PassedExam[] = [];
-  if (needsExams) {
-    const examsRes = await fetch(apiUrl('/api/user/getPassedSubjects'), {
-      headers: { Authorization: `Bearer ${accessToken}` },
-    });
-    if (examsRes.ok) {
-      const examsData = await examsRes.json();
-      passedExams = (examsData?.passedSubjects ?? []).map((s: Record<string, unknown>) => ({
-        id: s.id as number,
-        code: s.code as string,
-        subject: s.subject as string,
-        credits: s.credits as number,
-        grade: s.grade as number,
-        date: s.date as string,
-        semester: s.semester as string,
-        professor: (s.professor as string) || '—',
-      }));
-    }
-  }
-
-  switch (docType) {
-    case 'passed_exams_certificate':
-      await generatePassedExamsCertificate(student, enrollment, passedExams, archiveNumber, documentDate);
-      break;
-    case 'uppi_form': {
-      const birth: BirthInfo = {
-        placeOfBirth: birthInfo.placeOfBirth,
-        municipalityOfBirth: birthInfo.municipalityOfBirth,
-        country: birthInfo.country,
-      };
-      const contactInfo: ContactInfo = {
-        placeOfResidence: contact.placeOfResidence,
-        municipalityOfResidence: contact.municipalityOfResidence,
-        address: contact.address,
-        phone: contact.phone,
-        mobilePhone: contact.mobilePhone,
-        email: contact.email,
-      };
-      const prevEdu: PreviousEducation = {
-        type: previousEducation.type,
-        profession: previousEducation.profession,
-        average: previousEducation.average,
-        language: previousEducation.language,
-        country: previousEducation.country,
-        previousUniversity: previousEducation.previousUniversity,
-        previousFaculty: previousEducation.previousFaculty,
-      };
-      await generateUPPIForm(student, enrollment, birth, contactInfo, prevEdu, passedExams, archiveNumber, documentDate);
-      break;
-    }
-    case 'regular_student_certificate':
-      await generateRegularStudentCertificate(student, enrollment, passedExams, archiveNumber, documentDate);
-      break;
-    case 'administrative_regulation':
-      await generateAdministrativeRegulation(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'exam_application_satisfaction':
-      await generateExamApplicationSatisfaction(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'semester_enrollment_after_deadline':
-      await generateSemesterEnrollmentAfterDeadline(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'certificate_issuance_various':
-      await generateCertificateIssuanceVarious(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'student_status_verification':
-      await generateStudySuspension(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'diploma_thesis_postponement':
-      await generateDiplomaThesisCancellation(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'diploma_package':
-      await generateDiplomaPackage(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'exam_postponement':
-      await generateExamCancellation(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'study_continuation_verification':
-      await generateStudyContinuation(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'failed_subject_grade_change':
-      await generateElectiveSubjectChange(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'passed_subject_grade_change':
-      await generatePassedSubjectChange(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'study_program_change_same_accreditation':
-      await generateProgramChangeSameAccreditation(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'study_program_change_new_accreditation':
-      await generateProgramChangeNewAccreditation(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'diploma_supplement':
-      await generateDiplomaSupplement(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'diploma_supplement_second_cycle':
-      await generateDiplomaSupplementSecondCycle(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'mksa':
-      await generateMKSA(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'exam_recognition':
-      await generateExamRecognition(student, enrollment, archiveNumber, documentDate);
-      break;
-    case 'student_card_old':
-      await generateStudentCardOld(student, enrollment, archiveNumber, documentDate);
-      break;
-    default:
-      await generateGenericDocument(student, enrollment, documentRequest, archiveNumber, documentDate);
-      break;
-  }
-}
Index: c/lib/utils.ts
===================================================================
--- src/lib/utils.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,6 +1,0 @@
-import { clsx, type ClassValue } from "clsx"
-import { twMerge } from "tailwind-merge"
-
-export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs))
-}
Index: c/locales/en/translation.json
===================================================================
--- src/locales/en/translation.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,321 +1,0 @@
-{
-  "prof_students_title": "Professor • Students",
-  "prof_students_data_note": "Data comes from",
-  "filter_by_subject": "Filter by subject",
-  "all_subjects": "All subjects",
-  "find_student_by_id": "Find student by index / ID",
-  "student_id_placeholder": "e.g. 20001",
-  "no_students_found": "No students found.",
-  "taxes": "Taxes",
-  "signatures": "Signatures",
-  "valid": "Valid",
-  "completed_semester": "Completed semesters",
-  "verified_semesters": "Verified semesters",
-  "total_semesters": "Total semesters",
-  "completed_semesters": "Completed semesters",
-  "documents_overview": "Overview of your documents and their status.",
-  "new_document_request": "New Document Request",
-  "select_document": "Select Document",
-  "price": "Price",
-  "comment": "Comment",
-  "add_comment": "Add comment",
-  "submit": "Submit",
-  "submitting": "Submitting...",
-  "document_submitted": "Document request submitted successfully!",
-  "document_submit_error": "Error submitting document request.",
-  "not_authenticated": "You are not logged in. Please log in again.",
-  "pdf_error": "Error generating document. Please try again.",
-  "generating": "Generating...",
-  "pending": "Pending",
-  "my_documents": "My Documents",
-  "archive": "Archive",
-  "request": "Request",
-  "document": "Document",
-  "pay_online": "Pay Online",
-  "none": "—",
-  "show_rows": "Show rows",
-  "page": "Page",
-  "of": "of",
-  "first": "First",
-  "last": "Last",
-  "total": "Total",
-  "documents_payment_info": "For more information about document payments, contact the administration.",
-  "total_documents": "Total Documents",
-  "approved": "Approved",
-  "total_price": "Total Price",
-  "mkd": "MKD",
-  "free": "0.00",
-  "download": "Download",
-  "university": "University ‘St. Cyril and Methodius’ - Skopje",
-  "faculty": "Faculty of Computer Science and Engineering",
-  "logout": "Logout",
-  "profile": "Profile",
-  "semesters": "Semesters",
-  "applications": "Applications",
-  "documents": "Documents",
-  "exams": "Exams",
-  "subjects": "Subjects",
-  "students": "Students",
-  "loading": "Loading...",
-  "failed_to_load_profile": "Failed to load profile.",
-  "n_a": "N/A",
-  "index": "Index",
-  "embg": "EMBG",
-  "personal_info": "Personal Information",
-  "first_name": "First Name",
-  "middle_name": "Middle Name",
-  "last_name": "Last Name",
-  "maiden_name": "Maiden Name",
-  "date_of_birth": "Date of Birth",
-  "gender": "Gender",
-  "male": "Male",
-  "female": "Female",
-  "nationality": "Nationality",
-  "citizenship": "Citizenship",
-  "scholarship": "Scholarship",
-  "current_plan": "Current Plan",
-  "registry_number": "Registry Number",
-  "study_group": "Study Group",
-  "note": "Note",
-  "birth_info": "Birth Information",
-  "place_of_birth": "Place of Birth",
-  "municipality_of_birth": "Municipality of Birth",
-  "country": "Country",
-  "previous_education": "Previous Education",
-  "type": "Type",
-  "profession": "Profession",
-  "average": "Average",
-  "language": "Language",
-  "previous_university": "Previous University",
-  "previous_faculty": "Previous Faculty",
-  "previous_study_mode": "Previous Study Mode",
-  "enrollment_info": "Enrollment Information",
-  "enrollment_year": "Enrollment Year",
-  "status": "Status",
-  "cycle": "Cycle",
-  "program": "Program",
-  "quota": "Quota",
-  "secondary_education_number": "Secondary Education Number",
-  "previous_education_credits": "Previous Education Credits",
-  "contact": "Contact",
-  "place_of_residence": "Place of Residence",
-  "municipality_of_residence": "Municipality of Residence",
-  "address": "Address",
-  "temporary_address": "Temporary Address",
-  "phone": "Phone",
-  "mobile_phone": "Mobile Phone",
-  "passport_number": "Passport Number",
-  "passport_expiry_date": "Passport Expiry Date",
-  "email": "Email",
-  "microsoft_email": "Microsoft Email",
-  "applications_header": "Applications",
-  "applications_subheader": "Electronic exam applications",
-  "select_exam_session": "Select exam session:",
-  "registered_exams": "Registered Exams",
-  "serial_number": "Serial Number",
-  "code": "Code",
-  "subject": "Subject",
-  "completed": "Completed",
-  "not_completed": "Not Completed",
-  "fee": "Fee",
-  "date": "Date",
-  "instructor": "Instructor",
-  "decade": "Decade",
-  "important_note": "Important Note",
-  "applications_important_note": "Important note regarding exam applications",
-  "yes": "Yes",
-  "no": "No",
-  "total_fee": "Total Fee",
-  "failed_to_load_exams": "Failed to load exams.",
-  "credits": "Credits",
-  "passed": "Passed",
-  "remaining": "Remaining",
-  "semester": "Semester",
-  "grade": "Grade",
-  "semesters_overview": "Overview of your enrolled semesters and their statuses.",
-  "semesters_list": "Semesters List",
-  "direction": "Direction",
-  "student_com": "Student Commission",
-  "sum": "Sum",
-  "paid": "Paid",
-  "ukim": "UKIM",
-  "created_on": "Created On",
-  "date_changed": "Date Changed",
-  "doc": "Document",
-  "doc1": "Document 1",
-  "verified": "Verified",
-  "debt": "Debt",
-  "debt_from_documents": "Debt from documents",
-  "ticket_number": "Ticket number",
-  "select_semester": "Select semester",
-  "enrolled_subjects": "Enrolled subjects",
-  "financial_info": "Financial information",
-  "material_costs": "Material costs",
-  "material_costs_info": "Material costs include all required fees for materials and resources for the subjects.",
-  "electronic_registration": "Electronic registration",
-  "eukim": "eUKIM",
-  "bank_provision": "Bank provision",
-  "which_time": "Which time",
-  "signature": "Signature",
-  "group": "Group",
-  "professor": "Professor",
-  "subjects_list": "Subjects list",
-  "subjects_overview": "Overview of your enrolled subjects and their status.",
-  "mandatory_short": "Mand.",
-  "elective_short": "Elect.",
-  "enrolled_by_student": "Enrolled by student",
-  "due": "Debt",
-  "failed_to_load_subjects": "Failed to load subjects.",
-  "hours": "Hours",
-  "administrative_regulation": "Request for administrative regulation of retroactive semester (from 2024) (1000)",
-  "exam_application_satisfaction": "Request for late exam registration (from 2024) (1000)",
-  "semester_enrollment_after_deadline": "Request for semester enrollment after deadline (from 2024) (1500)",
-  "certificate_issuance_various": "Request for issuance of certificates for various reasons (from 2024) (1500)",
-  "student_status_verification": "Request for suspension of studies (from 2024) (2000)",
-  "diploma_thesis_postponement": "Request for cancellation of registered diploma thesis topic (from 2024) (1000)",
-  "diploma_package": "Request for graduation package (from 2024) (6200)",
-  "exam_postponement": "Request for exam cancellation (from 2024) (2000)",
-  "regular_student_certificate": "Request for regular student certificate (paper) (100)",
-  "study_continuation_verification": "Request for continuation of studies in suspension (from 2024) (2000)",
-  "failed_subject_grade_change": "Request for elective subject change (from 2024) (1500)",
-  "passed_subject_grade_change": "Request for passed subject change (from 2024) (0)",
-  "study_program_change_same_accreditation": "Request for study program change from same accreditation (from 2024) (2000)",
-  "study_program_change_new_accreditation": "Request for study program change from newer accreditation (from 2024) (3000)",
-  "diploma_supplement": "Diploma supplement (0)",
-  "diploma_supplement_second_cycle": "Diploma supplement (second cycle) (0)",
-  "mksa": "MKSA (750)",
-  "exam_recognition": "Recognition of passed exams (0)",
-  "student_card_old": "Student card (Old) (0)",
-  "Уверение за положени испити ФИНКИ": "Certificate of passed exams FINKI",
-  "УППИ образец": "UPPI form",
-  "Уверение за редовен студент - ФИНКИ": "Regular student certificate - FINKI",
-  "2025_summer_session2": "2025 (Summer) Second exam session",
-  "2025_summer_session1": "2025 (Summer) First exam session",
-  "2025_winter_session2": "2025 (Winter) Second exam session",
-  "2025_winter_session1": "2025 (Winter) First exam session",
-  "2024_summer_session2": "2024 (Summer) Second exam session",
-  "2024_summer_session1": "2024 (Summer) First exam session",
-  "2024_winter_session2": "2024 (Winter) Second exam session",
-  "2024_winter_session1": "2024 (Winter) First exam session",
-  "applications_important_note_text": "The serial number of the electronic application must be entered on the paper application that the student will submit physically.",
-  "login_student_title": "Login for Student",
-  "login_student_example": "Email: stefan.saveski@students.finki.ukim.mk\nPassword: Test12345!",
-  "login_professor_title": "Login for Professor",
-  "login_professor_example": "Email: vangel.ajanovski@finki.ukim.mk\nPassword: Test12345!",
-  "login_admin_title": "Login for Administrator",
-  "login_admin_example": "Email: igor.adminovski@finki.ukim.mk\nPassword: Test12345!",
-  "login_welcome": "Welcome",
-  "login_subtitle": "Sign in to your IKnow account",
-  "login_email_label": "Enter email",
-  "login_email_placeholder": "Enter email",
-  "login_password_label": "Password",
-  "login_password_placeholder": "Enter password",
-  "login_remember_me": "Remember me",
-  "login_forgot_password": "Forgot password?",
-  "login_button": "Sign in",
-  "login_button_loading": "Signing in...",
-  "login_no_account": "Don't have an account?",
-  "login_contact_admin": "Contact administration",
-  "login_footer": "Student Information System",
-  "contact_us": "Contact Us",
-  "close": "Close",
-  "contact_name": "Full Name",
-  "contact_name_placeholder": "Your name",
-  "contact_email": "Email",
-  "contact_email_placeholder": "example@email.com",
-  "contact_subject": "Subject",
-  "contact_subject_placeholder": "Message topic",
-  "contact_message": "Message",
-  "contact_message_placeholder": "Write your message...",
-  "contact_send": "Send",
-  "contact_sending": "Sending...",
-  "contact_sent_title": "Message sent!",
-  "contact_sent_desc": "We will get back to you soon.",
-  "Компјутерски мрежи и безбедност": "Computer Networks and Security",
-  "Шаблони за дизајн на кориснички интерфејси": "User Interface Design Patterns",
-  "Деловна пракса": "Business Practice",
-  "Маркетинг": "Marketing",
-  "Оперативни системи": "Operating Systems",
-  "Софтверско инженерство": "Software Engineering",
-  "Вештачка интелигенција": "Artificial Intelligence",
-  "Сашо Граматиков": "Sasho Gramatikov",
-  "Сузана Лошковска": "Suzana Loshkovska",
-  "Александар Стојменски": "Aleksandar Stojmenski",
-  "Билјана Стојкоска": "Biljana Stojkoska",
-  "Невена Ацковска": "Nevena Ackovska",
-  "Ѓорѓи Маџаров": "Gjorgji Madjarov",
-  "Соња Гиевска": "Sonja Gievska",
-  "Летна": "Summer",
-  "Зимска": "Winter",
-  "Прва испитна сесија": "First exam session",
-  "Втора испитна сесија": "Second exam session",
-  "Валидно": "Valid",
-  "Да": "Yes",
-  "Не": "No",
-  "exams_overview": "Overview of your passed exams and grades.",
-  "failed_to_load_semesters": "Failed to load semesters.",
-  "add_grade": "Add Grade",
-  "edit_grade": "Edit Grade",
-  "remove_grade": "Remove Grade",
-  "current": "Current",
-  "login_demo_note": "Use these credentials to explore the system.",
-  "enroll_semester": "Enroll semester",
-  "enroll_confirm": "Enroll",
-  "enroll_no_semesters": "You are already enrolled in every available semester.",
-  "enroll_already_passed": "passed",
-  "enroll_credits": "credits",
-  "enroll_semester_short": "sem.",
-  "enroll_not_signed_in": "You are not signed in.",
-  "enroll_options_failed": "Could not load enrollment options",
-  "enroll_failed": "Enrollment failed",
-  "cancel": "Cancel",
-  "admin_portal": "Admin",
-  "admin_subjects": "Subjects",
-  "admin_semesters": "Semesters",
-  "admin_schedule": "Teaching schedule",
-  "admin_subjects_intro": "Add subjects, map them to study programmes and set prerequisites.",
-  "admin_semesters_intro": "Open an active semester so students can enroll in it.",
-  "admin_schedule_intro": "Decide which professor teaches which subject in which semester.",
-  "admin_new_subject": "New subject",
-  "admin_edit_subject": "Edit subject",
-  "admin_subject_name": "Name",
-  "admin_subject_code": "Code",
-  "admin_credits": "Credits",
-  "admin_dependency_credit": "Required credits",
-  "admin_create": "Create",
-  "admin_save": "Save",
-  "admin_delete": "Delete",
-  "admin_remove": "Remove",
-  "admin_add": "Add",
-  "admin_manage": "Manage",
-  "admin_close": "Close",
-  "admin_majors": "Study programmes",
-  "admin_prerequisites": "Prerequisites",
-  "admin_pick_major": "Pick a study programme",
-  "admin_pick_prerequisite": "Pick a prerequisite",
-  "admin_pick_subject": "Pick a subject",
-  "admin_pick_professor": "Pick a professor",
-  "admin_search_subject": "Search by name or code",
-  "admin_no_subjects": "No subjects found.",
-  "admin_delete_blocked": "Cannot delete: {{count}} enrolment(s) already contain this subject.",
-  "admin_new_semester": "Open a new semester",
-  "admin_year": "Year",
-  "admin_type": "Type",
-  "admin_winter": "Winter",
-  "admin_summer": "Summer",
-  "admin_open_semester": "Open semester",
-  "admin_open_semesters": "Open semesters",
-  "admin_no_semesters": "No semesters yet.",
-  "admin_enrolments": "Enrolments",
-  "admin_coverage": "Coverage",
-  "admin_fully_covered": "all subjects covered",
-  "admin_uncovered_count": "{{count}} subject(s) without a professor",
-  "admin_uncovered_hint": "Students cannot enroll in a subject nobody teaches that semester.",
-  "admin_show_uncovered": "Show",
-  "admin_professor": "Professor",
-  "admin_assign": "Assign",
-  "admin_assignments": "Assignments",
-  "admin_load": "Teaching load",
-  "admin_no_assignments": "Nothing assigned yet.",
-  "admin_no_professors": "No professors."
-}
Index: c/locales/mk/translation.json
===================================================================
--- src/locales/mk/translation.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,325 +1,0 @@
-{
-  "prof_students_title": "Професор • Студенти",
-  "prof_students_data_note": "Податоците се од",
-  "filter_by_subject": "Филтрирај по предмет",
-  "all_subjects": "Сите предмети",
-  "find_student_by_id": "Најди студент по индекс / ID",
-  "student_id_placeholder": "пр. 20001",
-  "no_students_found": "Не се пронајдени студенти.",
-  "student": "Студент",
-  "id": "ID",
-  "actions": "Акции",
-  "current": "Тековна",
-  "add_grade": "Додади оценка",
-  "edit_grade": "Измени оценка",
-  "remove_grade": "Избриши оценка",
-  "taxes": "Такси",
-  "signatures": "Потписи",
-  "valid": "Валидно",
-  "completed_semester": "Завршени семестри",
-  "verified_semesters": "Потврдени семестри",
-  "total_semesters": "Вкупно семестри",
-  "completed_semesters": "Завршени семестри",
-  "documents_overview": "Преглед на вашите документи и нивниот статус.",
-  "new_document_request": "Ново барање за документ",
-  "select_document": "Изберете документ",
-  "price": "Цена",
-  "comment": "Коментар",
-  "add_comment": "Додај коментар",
-  "submit": "Поднеси",
-  "submitting": "Се поднесува...",
-  "document_submitted": "Барањето за документ е успешно поднесено!",
-  "document_submit_error": "Грешка при поднесување на барањето.",
-  "not_authenticated": "Не сте најавени. Ве молиме најавете се повторно.",
-  "pdf_error": "Грешка при генерирање на документот. Обидете се повторно.",
-  "generating": "Генерира...",
-  "pending": "Во обработка",
-  "my_documents": "Мои документи",
-  "archive": "Архива",
-  "request": "Барање",
-  "document": "Документ",
-  "pay_online": "Плати онлајн",
-  "none": "—",
-  "show_rows": "Прикажи редови",
-  "page": "Страница",
-  "of": "од",
-  "first": "Прва",
-  "last": "Последна",
-  "total": "Вкупно",
-  "documents_payment_info": "За повеќе информации за плаќање документи, обратете се во администрација.",
-  "total_documents": "Вкупно документи",
-  "approved": "Одобрено",
-  "total_price": "Вкупна цена",
-  "mkd": "мкд",
-  "free": "0,00",
-  "download": "Преземи",
-  "choose_document": "Избери документ",
-  "university": "Универзитет „Св. КИРИЛ И МЕТОДИЈ“ - Скопје",
-  "faculty": "Факултет за информатички науки и компјутерско инженерство",
-  "logout": "Одјави се",
-  "profile": "Профил",
-  "semesters": "Семестри",
-  "applications": "Апликации",
-  "documents": "Документи",
-  "exams": "Испити",
-  "subjects": "Предмети",
-  "students": "Студенти",
-  "loading": "Се вчитува...",
-  "failed_to_load_profile": "Не успеавме да го вчитаме профилот.",
-  "n_a": "Н/П",
-  "index": "Индекс",
-  "embg": "ЕМБГ",
-  "personal_info": "Лични податоци",
-  "first_name": "Име",
-  "middle_name": "Средно име",
-  "last_name": "Презиме",
-  "maiden_name": "Моминско презиме",
-  "date_of_birth": "Датум на раѓање",
-  "gender": "Пол",
-  "male": "машки",
-  "female": "женски",
-  "nationality": "Националност",
-  "citizenship": "Државјанство",
-  "scholarship": "Стипендија",
-  "current_plan": "Тековен план",
-  "registry_number": "Бр. во матична книга",
-  "study_group": "Група на студирање",
-  "note": "Забелешка",
-  "birth_info": "Податоци за раѓање",
-  "place_of_birth": "Место на раѓање",
-  "municipality_of_birth": "Општина на раѓање",
-  "country": "Земја",
-  "previous_education": "Претходно образование",
-  "type": "Тип",
-  "profession": "Професија",
-  "average": "Просек",
-  "language": "Јазик",
-  "previous_university": "Претходен универзитет",
-  "previous_faculty": "Претходен факултет",
-  "previous_study_mode": "Режим на претходни студии",
-  "enrollment_info": "Податоци за упис",
-  "enrollment_year": "Година на упис",
-  "status": "Статус",
-  "cycle": "Циклус",
-  "program": "Запишана програма",
-  "quota": "Квота на прв упис",
-  "secondary_education_number": "Бр. дипл. ср. образование",
-  "previous_education_credits": "Кред. пр. образование",
-  "contact": "Контакт",
-  "place_of_residence": "Место на живеење",
-  "municipality_of_residence": "Општина на живеење",
-  "address": "Адреса",
-  "temporary_address": "Адреса на престој",
-  "phone": "Телефон",
-  "mobile_phone": "Моб. телефон",
-  "passport_number": "Број на пасош",
-  "passport_expiry_date": "Датум на истекување на пасошот",
-  "email": "Е-пошта",
-  "microsoft_email": "Microsoft email",
-  "applications_header": "Пријави",
-  "applications_subheader": "Електронски пријави за испити",
-  "select_exam_session": "Избери испитна сесија:",
-  "registered_exams": "Пријавени испити",
-  "serial_number": "Сериски број",
-  "code": "Код",
-  "subject": "Предмет",
-  "completed": "Завршени",
-  "not_completed": "Незавршени",
-  "fee": "Таксени",
-  "date": "Датум",
-  "instructor": "Наставник",
-  "decade": "Декада",
-  "important_note": "Важна забелешка",
-  "applications_important_note": "Важна забелешка за испитните пријави",
-  "yes": "Да",
-  "no": "Не",
-  "total_fee": "Вкупна такса",
-  "failed_to_load_exams": "Не успеавме да ги вчитаме испитите.",
-  "credits": "Кредити",
-  "passed": "Положени",
-  "remaining": "Останато",
-  "semester": "Семестар",
-  "grade": "Оценка",
-  "semesters_overview": "Преглед на вашите запишани семестри и нивниот статус.",
-  "semesters_list": "Листа на семестри",
-  "direction": "Насока",
-  "student_com": "Студентска комисија",
-  "sum": "Сума",
-  "paid": "Платено",
-  "ukim": "УКИМ",
-  "created_on": "Креирано на",
-  "date_changed": "Датум на промена",
-  "doc": "Документ",
-  "doc1": "Документ 1",
-  "verified": "Потврдено",
-  "debt": "Долг",
-  "debt_from_documents": "Долг од документи",
-  "ticket_number": "Број на тикет",
-  "select_semester": "Избери семестар",
-  "enrolled_subjects": "Запишани предмети",
-  "financial_info": "Финансиски информации",
-  "material_costs": "Материјални трошоци",
-  "material_costs_info": "Материјалните трошоци ги вклучуваат сите задолжителни надоместоци за материјали и ресурси за предметите.",
-  "electronic_registration": "Електронска регистрација",
-  "eukim": "еУКИМ",
-  "bank_provision": "Банкарска провизија",
-  "which_time": "Кој пат",
-  "signature": "Потпис",
-  "group": "Група",
-  "professor": "Професор",
-  "subjects_list": "Листа на предмети",
-  "subjects_overview": "Преглед на вашите запишани предмети и нивниот статус.",
-  "mandatory_short": "Зад.",
-  "elective_short": "Изб.",
-  "enrolled_by_student": "Запишан од студентот",
-  "due": "Долг",
-  "failed_to_load_subjects": "Не успеавме да ги вчитаме предметите.",
-  "hours": "Часови",
-  "administrative_regulation": "Барање за административно регулирање на ретроактивен семестар (од 2024г) ( 1000)",
-  "exam_application_satisfaction": "Барање за задочно пријавување на испит (од 2024г) ( 1000)",
-  "semester_enrollment_after_deadline": "Барање за запишување на семестар по истек на рок (од 2024г) ( 1500)",
-  "certificate_issuance_various": "Барање за издавање потврди по разни основи (од 2024г) ( 1500)",
-  "student_status_verification": "Барање за мирување на студиите (од 2024г) ( 2000)",
-  "diploma_thesis_postponement": "Барање за откажување на пријавена тема за дипломска работа (од 2024г) ( 1000)",
-  "diploma_package": "Барање за пакет за дипломирање (од 2024г) (6200)",
-  "exam_postponement": "Барање за поништување на испит (од 2024г) ( 2000)",
-  "regular_student_certificate": "Барање за потврда за редовен студент (хартиена) ( 100)",
-  "study_continuation_verification": "Барање за продолжување на студии во мирување (од 2024г) ( 2000)",
-  "failed_subject_grade_change": "Барање за промена на изборен предмет (од 2024г) ( 1500)",
-  "passed_subject_grade_change": "Барање за промена на положен предмет (од 2024г) ( 0)",
-  "study_program_change_same_accreditation": "Барање за промена на студиска програма од иста акредитација (од 2024г) ( 2000)",
-  "study_program_change_new_accreditation": "Барање за промена на студиска програма од понова акредитација (од 2024г) ( 3000)",
-  "diploma_supplement": "Додаток на диплома ( 0)",
-  "diploma_supplement_second_cycle": "Додаток на диплома (втор циклус) ( 0)",
-  "mksa": "МКСА ( 750)",
-  "exam_recognition": "Признавање на положени испити ( 0)",
-  "student_card_old": "Студентски картон (Старо) ( 0)",
-  "Уверение за положени испити ФИНКИ": "Уверение за положени испити ФИНКИ",
-  "УППИ образец": "УППИ образец",
-  "Уверение за редовен студент - ФИНКИ": "Уверение за редовен студент - ФИНКИ",
-  "Компјутерски мрежи и безбедност": "Компјутерски мрежи и безбедност",
-  "Шаблони за дизајн на кориснички интерфејси": "Шаблони за дизајн на кориснички интерфејси",
-  "Деловна пракса": "Деловна пракса",
-  "Маркетинг": "Маркетинг",
-  "Оперативни системи": "Оперативни системи",
-  "Софтверско инженерство": "Софтверско инженерство",
-  "Вештачка интелигенција": "Вештачка интелигенција",
-  "Сашо Граматиков": "Сашо Граматиков",
-  "Сузана Лошковска": "Сузана Лошковска",
-  "Александар Стојменски": "Александар Стојменски",
-  "Билјана Стојкоска": "Билјана Стојкоска",
-  "Невена Ацковска": "Невена Ацковска",
-  "Ѓорѓи Маџаров": "Ѓорѓи Маџаров",
-  "Соња Гиевска": "Соња Гиевска",
-  "exams_overview": "Преглед на вашите положени испити и оценки.",
-  "failed_to_load_semesters": "Не успеавме да ги вчитаме семестрите.",
-  "Летна": "Летна",
-  "Зимска": "Зимска",
-  "Прва испитна сесија": "Прва испитна сесија",
-  "Втора испитна сесија": "Втора испитна сесија",
-  "Валидно": "Валидно",
-  "Да": "Да",
-  "Не": "Не",
-  "2025_summer_session2": "2025 (Летна) Втора испитна сесија",
-  "2025_summer_session1": "2025 (Летна) Прва испитна сесија",
-  "2025_winter_session2": "2025 (Зимска) Втора испитна сесија",
-  "2025_winter_session1": "2025 (Зимска) Прва испитна сесија",
-  "2024_summer_session2": "2024 (Летна) Втора испитна сесија",
-  "2024_summer_session1": "2024 (Летна) Прва испитна сесија",
-  "2024_winter_session2": "2024 (Зимска) Втора испитна сесија",
-  "2024_winter_session1": "2024 (Зимска) Прва испитна сесија",
-  "applications_important_note_text": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички.",
-  "login_student_title": "Најава за студент",
-  "login_student_example": "Е-пошта: stefan.saveski@students.finki.ukim.mk\nЛозинка: Test12345!",
-  "login_professor_title": "Најава за професор",
-  "login_professor_example": "Е-пошта: vangel.ajanovski@finki.ukim.mk\nЛозинка: Test12345!",
-  "login_admin_title": "Најава за администратор",
-  "login_admin_example": "Е-пошта: igor.adminovski@finki.ukim.mk\nЛозинка: Test12345!",
-  "login_welcome": "Добредојде",
-  "login_subtitle": "Најавете се во вашиот IKnow акаунт",
-  "login_email_label": "Внесете е-пошта",
-  "login_email_placeholder": "Внесете е-пошта",
-  "login_password_label": "Лозинка",
-  "login_password_placeholder": "Внесете лозинка",
-  "login_remember_me": "Запомни ме",
-  "login_forgot_password": "Заборавена лозинка?",
-  "login_button": "Најави се",
-  "login_button_loading": "Најавување...",
-  "login_no_account": "Немате акаунт?",
-  "login_contact_admin": "Контактирајте ја администрацијата",
-  "login_footer": "Студентски информационен систем",
-  "contact_us": "Контактирај нè",
-  "close": "Затвори",
-  "contact_name": "Име и презиме",
-  "contact_name_placeholder": "Вашето име",
-  "contact_email": "Е-пошта",
-  "contact_email_placeholder": "example@email.com",
-  "contact_subject": "Наслов",
-  "contact_subject_placeholder": "Тема на пораката",
-  "contact_message": "Порака",
-  "contact_message_placeholder": "Напишете ја вашата порака...",
-  "contact_send": "Испрати",
-  "contact_sending": "Испраќа...",
-  "contact_sent_title": "Пораката е испратена!",
-  "contact_sent_desc": "Ќе ви одговориме наскоро.",
-  "login_demo_note": "Користете ги овие податоци за да го истражите системот.",
-  "enroll_semester": "Запиши семестар",
-  "enroll_confirm": "Запиши",
-  "enroll_no_semesters": "Веќе сте запишани во сите достапни семестри.",
-  "enroll_already_passed": "положен",
-  "enroll_credits": "кредити",
-  "enroll_semester_short": "сем.",
-  "enroll_not_signed_in": "Не сте најавени.",
-  "enroll_options_failed": "Не може да се вчитаат опциите за запишување",
-  "enroll_failed": "Запишувањето не успеа",
-  "cancel": "Откажи",
-  "admin_portal": "Админ",
-  "admin_subjects": "Предмети",
-  "admin_semesters": "Семестри",
-  "admin_schedule": "Распоред",
-  "admin_subjects_intro": "Додавање предмети, поврзување со студиски програми и предуслови.",
-  "admin_semesters_intro": "Отворање активен семестар во кој студентите можат да се запишат.",
-  "admin_schedule_intro": "Определување кој професор кој предмет го предава.",
-  "admin_new_subject": "Нов предмет",
-  "admin_edit_subject": "Измена на предмет",
-  "admin_subject_name": "Назив",
-  "admin_subject_code": "Шифра",
-  "admin_credits": "Кредити",
-  "admin_dependency_credit": "Потребни кредити",
-  "admin_create": "Креирај",
-  "admin_save": "Зачувај",
-  "admin_delete": "Избриши",
-  "admin_remove": "Отстрани",
-  "admin_add": "Додади",
-  "admin_manage": "Уреди",
-  "admin_close": "Затвори",
-  "admin_majors": "Студиски програми",
-  "admin_prerequisites": "Предуслови",
-  "admin_pick_major": "Избери студиска програма",
-  "admin_pick_prerequisite": "Избери предуслов",
-  "admin_pick_subject": "Избери предмет",
-  "admin_pick_professor": "Избери професор",
-  "admin_search_subject": "Пребарај по назив или шифра",
-  "admin_no_subjects": "Нема предмети.",
-  "admin_delete_blocked": "Не може да се избрише: {{count}} запишувања го содржат предметот.",
-  "admin_new_semester": "Отвори нов семестар",
-  "admin_year": "Година",
-  "admin_type": "Тип",
-  "admin_winter": "Зимски",
-  "admin_summer": "Летен",
-  "admin_open_semester": "Отвори семестар",
-  "admin_open_semesters": "Отворени семестри",
-  "admin_no_semesters": "Нема семестри.",
-  "admin_enrolments": "Запишувања",
-  "admin_coverage": "Покриеност",
-  "admin_fully_covered": "сите предмети се покриени",
-  "admin_uncovered_count": "{{count}} предмети без професор",
-  "admin_uncovered_hint": "Студентите не можат да запишат предмет кој никој не го предава.",
-  "admin_show_uncovered": "Прикажи",
-  "admin_professor": "Професор",
-  "admin_assign": "Распореди",
-  "admin_assignments": "Распоред",
-  "admin_load": "Оптовареност",
-  "admin_no_assignments": "Секој нема распоред.",
-  "admin_no_professors": "Нема професори."
-}
Index: config.json
===================================================================
--- tsconfig.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ 	(revision )
@@ -1,41 +1,0 @@
-{
-  "compilerOptions": {
-    "target": "ES2017",
-    "lib": [
-      "dom",
-      "dom.iterable",
-      "esnext"
-    ],
-    "allowJs": true,
-    "skipLibCheck": true,
-    "strict": true,
-    "esModuleInterop": true,
-    "module": "esnext",
-    "moduleResolution": "bundler",
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "jsx": "react-jsx",
-    "incremental": true,
-    "plugins": [
-      {
-        "name": "next"
-      }
-    ],
-    "paths": {
-      "@/*": [
-        "./src/*"
-      ]
-    },
-    "noEmit": true
-  },
-  "include": [
-    "next-env.d.ts",
-    "**/*.ts",
-    "**/*.tsx",
-    ".next/types/**/*.ts",
-    ".next/dev/types/**/*.ts"
-  ],
-  "exclude": [
-    "node_modules"
-  ]
-}
