Index: src/app/globals.css
===================================================================
--- src/app/globals.css	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/app/globals.css	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -46,5 +46,5 @@
 :root {
   --radius: 0.625rem;
-  --background: oklch(1 0 0);
+  --background: #F4FAFF;
   --foreground: oklch(0.145 0 0);
   --card: oklch(1 0 0);
Index: src/app/layout.tsx
===================================================================
--- src/app/layout.tsx	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/app/layout.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -8,4 +8,5 @@
 import { ThemeProvider } from '../components/theme-provider';
 import { ThemeToggle } from '../components/theme-toggle';
+import ContactBubble from '../components/contact-bubble';
 
 config.autoAddCss = false;
@@ -35,4 +36,5 @@
             </div>
             <div className="mx-auto max-w-6xl px-4">{children}</div>
+            <ContactBubble />
           </I18nextProvider>
         </ThemeProvider>
Index: src/app/page.tsx
===================================================================
--- src/app/page.tsx	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/app/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -58,9 +58,9 @@
                 <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 font-mono">
+                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
                     {t('login_student_example')}
                   </div>
-                  <div className="mt-3 text-xs text-muted-foreground">
-                    {t('login_note_slow')}
+                  <div className="mt-3 text-xs text-blue-600 font-medium">
+                    {t('login_demo_note')}
                   </div>
                 </div>
@@ -68,6 +68,9 @@
                 <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 font-mono">
+                  <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>
Index: src/app/students/applications/page.tsx
===================================================================
--- src/app/students/applications/page.tsx	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/app/students/applications/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -30,5 +30,5 @@
 const CompletedBadge = ({ completed }: { completed: string }) => {
   const { t } = useTranslation();
-  if (completed === t('yes', 'Да')) {
+  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')}> 
@@ -230,5 +230,5 @@
               <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 === t('yes', 'Да')).length}
+                {applications.filter(app => app.completed === 'Да').length}
               </p>
             </div>
Index: src/app/students/documents/page.tsx
===================================================================
--- src/app/students/documents/page.tsx	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/app/students/documents/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -6,4 +6,5 @@
   faChevronDown,
   faCheckCircle,
+  faClock,
   faMoneyBillWave,
   faFileText,
@@ -11,9 +12,12 @@
   faChevronRight,
   faAngleDoubleLeft,
-  faAngleDoubleRight
+  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 {
@@ -30,8 +34,16 @@
 const StatusBadge = ({ status }: { status: string }) => {
   const { t } = useTranslation();
-  if (status === t('approved', 'Одобрено')) {
+  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>
     );
@@ -52,4 +64,17 @@
 };
 
+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");
@@ -58,8 +83,63 @@
   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 { documents, paymentInfo } = documentsData;
+  const { paymentInfo } = documentsData;
 
   const totalPages = Math.ceil(documents.length / recordsPerPage);
@@ -153,9 +233,10 @@
         <div className="flex justify-end mt-6">
           <button
-            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={selectedDocumentType === "select_document"}
+            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={faFileText} className="w-4 h-4" />
-            {t('submit', 'Поднеси')}
+            <FontAwesomeIcon icon={isSubmitting ? faSpinner : faFileText} className={`w-4 h-4 ${isSubmitting ? 'animate-spin' : ''}`} />
+            {isSubmitting ? t('submitting', 'Се поднесува...') : t('submit', 'Поднеси')}
           </button>
         </div>
@@ -197,11 +278,22 @@
                   </TableCell>
                   <TableCell className="text-center">
-                    <span className="text-sm font-medium text-green-600">
+                    <span className={`text-sm font-medium ${document.paid === 'ДА' ? 'text-green-600' : 'text-red-500'}`}>
                       {document.paid}
                     </span>
                   </TableCell>
                   <TableCell className="text-center">
-                    <button className="text-primary hover:text-blue-700 font-medium text-sm underline">
-                      {document.document}
+                    <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>
Index: src/app/students/semesters/page.tsx
===================================================================
--- src/app/students/semesters/page.tsx	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/app/students/semesters/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -57,9 +57,9 @@
   const { t } = useTranslation();
   const baseClasses = "px-2 py-1 rounded-full text-xs font-medium";
-  if (status === t('valid')) {
+  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('valid')}
+        {t('Валидно', 'Валидно')}
       </span>
     );
@@ -67,5 +67,5 @@
   return (
     <span className={`${baseClasses} bg-accent text-gray-800`}>
-      {t(status) || status}
+      {t(status, status)}
     </span>
   );
@@ -74,5 +74,5 @@
 const YesNoBadge = ({ value }: { value: string }) => {
   const { t } = useTranslation();
-  if (value === t('yes')) {
+  if (value === 'Да') {
     return (
       <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full">
@@ -80,5 +80,5 @@
       </span>
     );
-  } else if (value === t('no')) {
+  } else if (value === 'Не') {
     return (
       <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full">
@@ -313,10 +313,10 @@
                       <span className="text-green-600 font-medium flex items-center gap-1">
                         <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
-                        {semester.completed}
+                        {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" />
-                        {semester.completed}
+                        {t('Не', 'Не')}
                       </span>
                     )}
Index: src/components/contact-bubble.tsx
===================================================================
--- src/components/contact-bubble.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/components/contact-bubble.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -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: src/components/exams.tsx
===================================================================
--- src/components/exams.tsx	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/components/exams.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -290,6 +290,6 @@
                 <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">{exam.subject}</td>
-                  <td className="py-4 px-4 text-sm text-muted-foreground">{exam.semester}</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>
Index: src/lib/pdf-fonts.ts
===================================================================
--- src/lib/pdf-fonts.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/lib/pdf-fonts.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -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: src/lib/pdf-generators.ts
===================================================================
--- src/lib/pdf-generators.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/lib/pdf-generators.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -0,0 +1,1206 @@
+import { jsPDF } from 'jspdf';
+import autoTable from 'jspdf-autotable';
+import { loadCyrillicFonts } from './pdf-fonts';
+
+/* ---------- 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('https://iknow-api.onrender.com/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('https://iknow-api.onrender.com/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: src/locales/en/translation.json
===================================================================
--- src/locales/en/translation.json	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/locales/en/translation.json	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -7,7 +7,4 @@
   "student_id_placeholder": "e.g. 20001",
   "no_students_found": "No students found.",
-  "Забелешка": "Note",
-  "Завршени": "Completed",
-  "Останати": "Remaining",
   "taxes": "Taxes",
   "signatures": "Signatures",
@@ -24,4 +21,11 @@
   "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",
@@ -42,5 +46,6 @@
   "mkd": "MKD",
   "free": "0.00",
-  "university": "University 'St. Cyril and Methodius' - Skopje",
+  "download": "Download",
+  "university": "University ‘St. Cyril and Methodius’ - Skopje",
   "faculty": "Faculty of Computer Science and Engineering",
   "logout": "Logout",
@@ -140,5 +145,29 @@
   "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)",
@@ -158,4 +187,7 @@
   "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",
@@ -168,8 +200,7 @@
   "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\":\"boris@example.com\",\n\"password\":\"your-password-here\",",
-  "login_note_slow": "May take up to 30 seconds after long inactivity.",
+  "login_student_example": "Email: boris@example.com\nPassword: your-password-here",
   "login_professor_title": "Login for Professor",
-  "login_professor_example": "\"email\":\"andonov@gmail.com\",\n\"password\":\"123lol456\",",
+  "login_professor_example": "Email: andonov@gmail.com\nPassword: 123lol456",
   "login_welcome": "Welcome",
   "login_subtitle": "Sign in to your IKnow account",
@@ -184,35 +215,46 @@
   "login_no_account": "Don't have an account?",
   "login_contact_admin": "Contact administration",
-  "login_footer": "Student Information System"
-  ,
-  "debt": "Debt",
-  "status": "Status"
-  ,
-  "debt_from_documents": "Debt from documents",
-  "status": "Status",
-  "subjects_overview": "Overview of your enrolled subjects and their status."
-  ,
-  "electronic_registration": "Electronic registration",
-  "eukim": "eUKIM",
-  "bank_provision": "Bank provision"
-  ,
-  "failed_to_load_subjects": "Failed to load subjects."
-  ,
-  "debt_from_documents": "Debt from documents",
-  "ticket_number": "Ticket number",
-  "serial_number": "Serial 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.",
-  "which_time": "Which time",
-  "signature": "Signature",
-  "group": "Group",
-  "professor": "Professor",
-  "subjects_list": "Subjects list",
-  "mandatory_short": "Mand.",
-  "elective_short": "Elect.",
-  "enrolled_by_student": "Enrolled by student",
-  "due": "Debt"
+  "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."
 }
Index: src/locales/mk/translation.json
===================================================================
--- src/locales/mk/translation.json	(revision d7deae59461c29e9dd209dd391ce311c8eae7b63)
+++ src/locales/mk/translation.json	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
@@ -14,46 +14,30 @@
   "edit_grade": "Измени оценка",
   "remove_grade": "Избриши оценка",
+  "taxes": "Такси",
+  "signatures": "Потписи",
+  "valid": "Валидно",
+  "completed_semester": "Завршени семестри",
+  "verified_semesters": "Потврдени семестри",
+  "total_semesters": "Вкупно семестри",
+  "completed_semesters": "Завршени семестри",
   "documents_overview": "Преглед на вашите документи и нивниот статус.",
   "new_document_request": "Ново барање за документ",
-  "select_document": "Избери документ",
+  "select_document": "Изберете документ",
   "price": "Цена",
   "comment": "Коментар",
-  "subjects_overview": "Преглед на вашите запишани предмети и нивниот статус.",
-  "enrolled_by_student": "Запишан од студентот",
-  "financial_info": "Финансиски информации",
-  "electronic_registration": "Електронска регистрација",
-  "eukim": "еУКИМ",
-  "bank_provision": "Банкарска провизија",
-  "debt_from_documents": "Долг од документи",
-  "debt": "Долг",
-  "select_semester": "Избери семестар",
-  "enrolled_subjects": "Запишани предмети",
-  "subjects_list": "Листа на предмети",
-  "hours": "Часови",
-  "which_time": "Кој пат",
-  "signature": "Потпис",
-  "group": "Група",
-  "professor": "Професор",
-  "ticket_number": "Број на тикет",
-    "due": "Долг",
-    "material_costs": "Материјални трошоци",
-    "material_costs_info": "Материјалните трошоци ги вклучуваат сите задолжителни надоместоци за материјали и ресурси за предметите.",
-  "Download": "Преземи",
-  "ДА": "ДА",
-  "Не": "Не",
-  "approved": "Одобрено",
-  "Онлајн плаќањата имаат банкарска провизија за безготовинско плаќање од 1,14% од оригиналната сума (минималната провизија 3,00, максималната 300,00 мкд)": "Онлајн плаќањата имаат банкарска провизија за безготовинско плаќање од 1,14% од оригиналната сума (минималната провизија 3,00, максималната 300,00 мкд)",
   "add_comment": "Додај коментар",
   "submit": "Поднеси",
+  "submitting": "Се поднесува...",
+  "document_submitted": "Барањето за документ е успешно поднесено!",
+  "document_submit_error": "Грешка при поднесување на барањето.",
+  "not_authenticated": "Не сте најавени. Ве молиме најавете се повторно.",
+  "pdf_error": "Грешка при генерирање на документот. Обидете се повторно.",
+  "generating": "Генерира...",
+  "pending": "Во обработка",
   "my_documents": "Мои документи",
   "archive": "Архива",
   "request": "Барање",
-  "paid": "Платено",
-  "ДА": "ДА",
-  "Не": "Не",
   "document": "Документ",
-  "Download": "Преземи",
   "pay_online": "Плати онлајн",
-  "status": "Статус",
   "none": "—",
   "show_rows": "Прикажи редови",
@@ -65,10 +49,10 @@
   "documents_payment_info": "За повеќе информации за плаќање документи, обратете се во администрација.",
   "total_documents": "Вкупно документи",
-  "approved": "Одобрени",
+  "approved": "Одобрено",
   "total_price": "Вкупна цена",
   "mkd": "мкд",
   "free": "0,00",
+  "download": "Преземи",
   "choose_document": "Избери документ",
-  "applications_important_note_text": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички.",
   "university": "Универзитет „Св. КИРИЛ И МЕТОДИЈ“ - Скопје",
   "faculty": "Факултет за информатички науки и компјутерско инженерство",
@@ -147,4 +131,5 @@
   "decade": "Декада",
   "important_note": "Важна забелешка",
+  "applications_important_note": "Важна забелешка за испитните пријави",
   "yes": "Да",
   "no": "Не",
@@ -168,20 +153,27 @@
   "doc1": "Документ 1",
   "verified": "Потврдено",
-  "taxes": "Такси",
-  "signatures": "Потписи",
-  "valid": "Валидно",
-  "completed_semester": "Завршени семестри",
-  "verified_semesters": "Потврдени семестри",
-  "total_semesters": "Вкупно семестри",
-  "completed_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 (Зимска) Прва испитна сесија",
-  "select_document": "Изберете документ",
+  "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)",
@@ -220,4 +212,13 @@
   "Ѓорѓи Маџаров": "Ѓорѓи Маџаров",
   "Соња Гиевска": "Соња Гиевска",
+  "exams_overview": "Преглед на вашите положени испити и оценки.",
+  "failed_to_load_semesters": "Не успеавме да ги вчитаме семестрите.",
+  "Летна": "Летна",
+  "Зимска": "Зимска",
+  "Прва испитна сесија": "Прва испитна сесија",
+  "Втора испитна сесија": "Втора испитна сесија",
+  "Валидно": "Валидно",
+  "Да": "Да",
+  "Не": "Не",
   "2025_summer_session2": "2025 (Летна) Втора испитна сесија",
   "2025_summer_session1": "2025 (Летна) Прва испитна сесија",
@@ -230,8 +231,7 @@
   "applications_important_note_text": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички.",
   "login_student_title": "Најава за студент",
-  "login_student_example": "\"email\":\"boris@example.com\",\n\"password\":\"your-password-here\",",
-  "login_note_slow": "Може да потрае до 30 секунди по долга неактивност.",
+  "login_student_example": "Е-пошта: boris@example.com\nЛозинка: your-password-here",
   "login_professor_title": "Најава за професор",
-  "login_professor_example": "\"email\":\"andonov@gmail.com\",\n\"password\":\"123lol456\",",
+  "login_professor_example": "Е-пошта: andonov@gmail.com\nЛозинка: 123lol456",
   "login_welcome": "Добредојде",
   "login_subtitle": "Најавете се во вашиот IKnow акаунт",
@@ -246,10 +246,19 @@
   "login_no_account": "Немате акаунт?",
   "login_contact_admin": "Контактирајте ја администрацијата",
-  "login_footer": "Студентски информационен систем"
-  ,
-  "failed_to_load_subjects": "Не успеавме да ги вчитаме предметите."
-  ,
-  "serial_number": "Сериски број",
-  "mandatory_short": "Зад.",
-  "elective_short": "Изб."
+  "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": "Користете ги овие податоци за да го истражите системот."
 }
