diff --git a/docs/slides/README.md b/docs/slides/README.md
new file mode 100644
index 0000000..d2a2cc7
--- /dev/null
+++ b/docs/slides/README.md
@@ -0,0 +1,9 @@
+# ارائه WebSocket فارسی
+
+- فایل `index.html` را در مرورگر باز کنید.
+- با کلیدهای چپ/راست بین اسلایدها حرکت کنید.
+- کلید `N` یادداشت سخنران را نشان میدهد.
+- کلید `F` حالت تمامصفحه را فعال میکند.
+- فونت اصلی `Vazirmatn` است؛ فایل ارائه از Google Fonts / فونت نصبشده روی سیستم استفاده میکند.
+- در نمایشگرهای بزرگ، اسلایدها به صورت ۱۶:۹ تا جای ممکن ارتفاع صفحه را پر میکنند.
+- در نمایشگرهای کوچک، اندازه فونت و چینش اسلایدها کوچکتر و عمودیتر میشود.
diff --git a/docs/slides/assets/chatroom-architecture.svg b/docs/slides/assets/chatroom-architecture.svg
new file mode 100644
index 0000000..2f38f02
--- /dev/null
+++ b/docs/slides/assets/chatroom-architecture.svg
@@ -0,0 +1,49 @@
+
+ Chatroom architecture
+ A compact architecture diagram for the chatroom project.
+
+
+
+
+
+
+
+
+
+
+
+ Chatroom Architecture
+ Browser Clients - FastAPI - Room Manager
+
+
+
+
+
+
+
+ Client A
+ Browser tab
+ Client B
+ Browser tab
+ FastAPI
+ WebSocket Endpoint
+ ConnectionManager
+ /ws/{room}/{user}
+ Room: general
+ A - B - C
+ Room: class
+ D - E
+
+
+
+
+ WebSocket Frames
+ Broadcast by room
+
diff --git a/docs/slides/assets/home.png b/docs/slides/assets/home.png
new file mode 100644
index 0000000..9783380
Binary files /dev/null and b/docs/slides/assets/home.png differ
diff --git a/docs/slides/assets/websocket-handshake.svg b/docs/slides/assets/websocket-handshake.svg
new file mode 100644
index 0000000..a69eb6e
--- /dev/null
+++ b/docs/slides/assets/websocket-handshake.svg
@@ -0,0 +1,40 @@
+
+ WebSocket handshake
+ A compact HTTP Upgrade handshake diagram.
+
+
+
+
+
+
+
+
+
+
+
+
+ HTTP Upgrade Handshake
+ Starts with HTTP, continues with WebSocket Frames
+
+
+
+
+ Browser
+ JavaScript WebSocket
+ FastAPI Server
+ /ws/{room}/{user}
+
+ 1. GET + Upgrade
+
+ 2. 101 Switching Protocols
+
+
+ 3. Full-duplex WebSocket Frames
+
diff --git a/docs/slides/assets/websocket-history.svg b/docs/slides/assets/websocket-history.svg
new file mode 100644
index 0000000..2951da2
--- /dev/null
+++ b/docs/slides/assets/websocket-history.svg
@@ -0,0 +1,63 @@
+
+ WebSocket history
+ A compact Persian timeline with English technical names.
+
+
+
+
+
+
+
+
+
+ WebSocket History
+ From Classic HTTP to Real-time communication
+
+
+
+
+
+
+
+ 1
+ Classic HTTP
+ Request / Response
+ No Server Push
+
+
+
+ 2
+ Polling
+ Repeated request
+ More overhead
+
+
+
+ 3
+ Long Polling
+ Open request
+ Long wait
+
+
+
+ 4
+ WebSocket
+ Persistent connection
+ Full-duplex
+
+
+
+ 5
+ Real-time Web
+ Chat - Game
+ Dashboard - IoT
+
+
+
diff --git a/docs/slides/assets/websocket-osi.svg b/docs/slides/assets/websocket-osi.svg
new file mode 100644
index 0000000..60ea5be
--- /dev/null
+++ b/docs/slides/assets/websocket-osi.svg
@@ -0,0 +1,43 @@
+
+ WebSocket in OSI model
+ A compact OSI stack with English technical names and Persian supporting labels.
+
+
+
+
+
+
+
+ WebSocket in the OSI Model
+ Application Layer over TCP/IP
+
+
+
+
+
+ Layer 7 - Application
+ WebSocket - JSON - Chat
+
+ Layer 6 - Presentation
+ UTF-8 - Text
+
+ Layer 5 - Session
+ Long-lived conversation
+
+ Layer 4 - Transport
+ TCP reliable stream
+
+ Layer 3 - Network
+ IP routing
+
+ Layers 2-1 - Link / Physical
+ Ethernet - Wi-Fi
+
+
diff --git a/docs/slides/assets/websocket-pros-cons.svg b/docs/slides/assets/websocket-pros-cons.svg
new file mode 100644
index 0000000..80de71b
--- /dev/null
+++ b/docs/slides/assets/websocket-pros-cons.svg
@@ -0,0 +1,44 @@
+
+ WebSocket pros and cons
+ A compact pros and cons diagram for WebSocket.
+
+
+
+
+
+
+
+
+
+ WebSocket Trade-offs
+ Strengths and limitations at a glance
+
+
+
+
+ Pros
+ Low latency
+ Full-duplex
+ Less HTTP overhead
+ Good for Chat / Dashboard
+
+
+
+
+ Cons
+ Server state
+ Open socket memory
+ Reconnect handling
+ Scaling needs design
+
+
+
+
+
diff --git a/docs/slides/index.html b/docs/slides/index.html
new file mode 100644
index 0000000..69062c1
--- /dev/null
+++ b/docs/slides/index.html
@@ -0,0 +1,243 @@
+
+
+
+
+
+ ارائه WebSocket و Socket Programming
+
+
+
+
+
+ پروژه مهندسی اینترنت
+ چتروم ساده با WebSocket
+ نمایش Socket Programming و ارتباط Real-time در وب
+
+
+
+
+
مسیر ارائه
+
History → Polling → Handshake → OSI → Architecture → Demo
+
+
+
+ معرفی سریع پروژه و مسیر ارائه.
+
+
+
+ History
+ چرا WebSocket لازم شد؟
+ مسیر تکامل از HTTP کلاسیک تا اتصال پایدار دوطرفه
+
+
+
+
+
+
+
HTTP
+
AJAX Polling درخواست تکراری هزینه شبکه بیشتر
+
LONG
+
WS
+
+
+ توضیح کوتاه درباره نیاز به دریافت لحظهای داده.
+
+
+
+ Resource Cost
+ هزینه هر روش برای سرور
+ هر روش، فشار متفاوتی روی Network، CPU، memory و socket دارد
+
+
+
Classic HTTP درخواست جداگانه پردازش header پایان چرخه
+
Polling درخواست زیاد پاسخهای خالی سربار Network
+
Long Polling اتصال باز نگهداری state مصرف buffer
+
WebSocket یک اتصال پایدار فریم سبک state فعال
+
+
+ Polling → درخواست تکراری · Long Polling → انتظار طولانی · WebSocket → کانال پایدار
+
+
+
+
+ HTTP Upgrade Handshake
+ WebSocket چطور شروع میشود؟
+ ابتدا HTTP، سپس پاسخ 101 و بعد WebSocket Frames
+
+
+
Client Browser ساخت WebSocket درخواست Upgrade
+
+
1. GET + Upgrade
+
2. 101 Switching Protocols
+
3. WebSocket Frames
+
+
Server FastAPI پذیرش Upgrade نگهداری socket
+
+
+
+
+
+
+
+
GET /ws/general/ali HTTP/1.1
+Upgrade: websocket
+Connection: Upgrade
+Sec-WebSocket-Key: ...
+
HTTP/1.1 101 Switching Protocols
+Upgrade: websocket
+Connection: Upgrade
+
+
+ نمایش handshake و تبدیل HTTP به WebSocket.
+
+
+
+ HTTP Versions
+ WebSocket در نسخههای HTTP
+ مدل آموزشی پروژه روی HTTP/1.1 Upgrade تمرکز دارد
+
+
+
HTTP/1.1 Upgrade + 101 مدل کلاسیک یک TCP connection ساده برای آموزش
+
HTTP/2 Extended CONNECT روی یک stream بدون Upgrade کلاسیک پیچیدهتر
+
HTTP/3 QUIC + CONNECT
+
+ HTTP/1.1: Upgrade → 101 → WebSocket Frames
+ تفاوت نسخهها در یک نگاه.
+
+
+
+ OSI Model
+ جایگاه WebSocket در شبکه
+ WebSocket در لایه Application استفاده میشود؛ TCP/IP حمل داده را انجام میدهد
+
+
+
+
Layer 7 WebSocket + JSON
+
Layer 6 UTF-8 text
+
Layer 5 Long-lived session
+
Layer 4 TCP reliable stream
+
Layer 3 IP routing
+
Layer 2/1 Ethernet / Wi-Fi
+
+
+
+ تفکیک لایه کاربرد از لایههای انتقال و شبکه.
+
+
+
+ Project Architecture
+ معماری پروژه چتروم
+ هر تب مرورگر یک WebSocket connection دارد
+
+
+
+
Client A Browser tab
+
Client B Browser tab
+
+
+
FastAPI WebSocket Endpoint
+
/ws/{room}/{user}
+
ConnectionManager
+
Broadcast داخل همان room
+
+
+
Room: general A · B · C
+
Room: class D · E
+
+
+
+
+ Browser UI
+ FastAPI endpoint
+ Room Manager
+ Broadcast
+
+ نمای معماری و نقش ConnectionManager.
+
+
+
+ Message Flow
+ جریان پیام در پروژه
+ از ورود کاربر تا نمایش پیام بدون refresh
+
+
+
1 Join name + room
+
2 Upgrade HTTP → WebSocket
+
3 Send JSON content
+
4 Broadcast room sockets
+
5 Render بدون refresh
+
+
+
+
نام و اتاق
+
WebSocket در JS
+
HTTP Upgrade
+
قبول در FastAPI
+
Room Manager
+
JSON message
+
Broadcast
+
نمایش پیام
+
+ جریان اجرایی پیام در پروژه.
+
+
+
+ Trade-offs
+ مزایا و محدودیتها
+ WebSocket برای Real-time عالی است، اما state سرور را بیشتر میکند
+
+
+
↔ Full-duplex ارسال دوطرفه بدون انتظار request بعدی
+
↓ Low latency
+
! Server state socket باز مدیریت disconnect
+
+
+
+ Chat
+ Notifications
+ Live dashboard
+ Online game
+
+ مزایا و هزینههای عملیاتی.
+
+
+
+ Demo
+ برنامه اجرای دمو
+ دو تب، یک room، پیام Real-time
+
+
+
+
+ اجرای uvicorn app.main:app --reload
+ باز کردن دو tab
+ ورود دو user به یک room
+ ارسال message
+ نمایش بدون refresh
+ تغییر online users
+
+
+
+
+
+
+
+ ‹
+ 1 / 10
+ ›
+
+ ← → حرکت · N یادداشت · F تمامصفحه
+
+
+
+
+
diff --git a/docs/slides/script.js b/docs/slides/script.js
new file mode 100644
index 0000000..21a8089
--- /dev/null
+++ b/docs/slides/script.js
@@ -0,0 +1,69 @@
+const slides = [...document.querySelectorAll('.slide')];
+const counter = document.getElementById('counter');
+const progressBar = document.getElementById('progressBar');
+const notesBox = document.getElementById('speakerNotes');
+let index = 0;
+
+function fitDeck() {
+ const vw = window.innerWidth;
+ const vh = window.innerHeight;
+ const root = document.documentElement;
+
+ // Mobile uses normal document flow, so text can shrink and content can scroll.
+ if (vw <= 900) {
+ const mobileScale = Math.max(0.64, Math.min(0.9, vw / 900));
+ root.style.setProperty('--slide-scale', mobileScale.toFixed(3));
+ root.style.removeProperty('--slide-w');
+ root.style.removeProperty('--slide-h');
+ return;
+ }
+
+ // Desktop/tablet: keep a 16:9 slide and fill as much height as the viewport allows.
+ const pad = Math.max(24, Math.min(72, Math.min(vw, vh) * 0.065));
+ const availableW = vw - pad;
+ const availableH = vh - pad;
+ let slideW = Math.min(availableW, availableH * (16 / 9));
+ let slideH = slideW * (9 / 16);
+
+ // If the width-bound calculation is too tall, bind by height instead.
+ if (slideH > availableH) {
+ slideH = availableH;
+ slideW = slideH * (16 / 9);
+ }
+
+ const scale = Math.max(0.78, Math.min(1.55, Math.min(slideW / 1200, slideH / 675)));
+ root.style.setProperty('--slide-w', `${Math.floor(slideW)}px`);
+ root.style.setProperty('--slide-h', `${Math.floor(slideH)}px`);
+ root.style.setProperty('--slide-scale', scale.toFixed(3));
+}
+
+function update() {
+ slides.forEach((slide, i) => slide.classList.toggle('active', i === index));
+ counter.textContent = `${index + 1} / ${slides.length}`;
+ progressBar.style.width = `${((index + 1) / slides.length) * 100}%`;
+ const note = slides[index].querySelector('.notes')?.textContent.trim() || '';
+ notesBox.textContent = note;
+}
+
+function go(delta) {
+ index = Math.min(slides.length - 1, Math.max(0, index + delta));
+ update();
+}
+
+document.getElementById('prev').addEventListener('click', () => go(-1));
+document.getElementById('next').addEventListener('click', () => go(1));
+
+document.addEventListener('keydown', (e) => {
+ if (['ArrowRight', 'PageUp'].includes(e.key)) go(-1);
+ if (['ArrowLeft', 'PageDown', ' '].includes(e.key)) go(1);
+ if (e.key.toLowerCase() === 'n') notesBox.classList.toggle('show');
+ if (e.key.toLowerCase() === 'f') {
+ if (!document.fullscreenElement) document.documentElement.requestFullscreen?.();
+ else document.exitFullscreen?.();
+ }
+});
+
+window.addEventListener('resize', fitDeck);
+window.addEventListener('orientationchange', fitDeck);
+fitDeck();
+update();
diff --git a/docs/slides/styles.css b/docs/slides/styles.css
new file mode 100644
index 0000000..56c853d
--- /dev/null
+++ b/docs/slides/styles.css
@@ -0,0 +1,738 @@
+@font-face {
+ font-family: "Vazirmatn";
+ src: url("../../app/static/Vazirmatn[wght].woff2") format("woff2");
+ font-weight: 100 900;
+ font-style: normal;
+ font-display: swap;
+}
+
+:root {
+ --bg: #171a22;
+ --paper: rgba(43, 43, 59, .86);
+ --ink: #f8fafc;
+ --muted: #a8adbd;
+ --blue: #6d8cff;
+ --blue-2: rgba(109, 140, 255, .16);
+ --green: #43d9a3;
+ --green-2: rgba(67, 217, 163, .16);
+ --amber: #f4b740;
+ --amber-2: rgba(244, 183, 64, .18);
+ --red: #fb7185;
+ --red-2: rgba(251, 113, 133, .16);
+ --line: rgba(255, 255, 255, .13);
+ --glass: rgba(255, 255, 255, .075);
+ --glass-strong: rgba(255, 255, 255, .12);
+ --soft: rgba(255, 255, 255, .06);
+ --shadow: 0 28px 90px rgba(0, 0, 0, .38);
+ --slide-w: min(1200px, calc(100vw - 72px));
+ --slide-h: min(675px, calc(100svh - 72px));
+ --slide-scale: 1;
+}
+
+* { box-sizing: border-box; }
+html, body { min-height: 100%; margin: 0; }
+body {
+ font-family: "Vazirmatn", "Segoe UI", Tahoma, Arial, sans-serif;
+ background:
+ linear-gradient(120deg, rgba(244, 183, 64, .12), transparent 28%),
+ linear-gradient(300deg, rgba(109, 140, 255, .12), transparent 34%),
+ var(--bg);
+ color: var(--ink);
+ overflow: hidden;
+}
+
+.deck {
+ min-height: 100svh;
+ width: 100vw;
+ position: relative;
+ display: grid;
+ place-items: center;
+ padding: 0;
+}
+.slide {
+ display: none;
+ width: var(--slide-w);
+ height: var(--slide-h);
+ background: var(--paper);
+ border: 1px solid rgba(255, 255, 255, .10);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 20px);
+ box-shadow: var(--shadow);
+ backdrop-filter: blur(22px) saturate(130%);
+ padding: clamp(28px, calc(48px * var(--slide-scale)), 66px) clamp(32px, calc(58px * var(--slide-scale)), 80px);
+ position: relative;
+ overflow: hidden;
+}
+.slide::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ background:
+ linear-gradient(90deg, rgba(255, 255, 255, .035) 1px, transparent 1px),
+ linear-gradient(180deg, rgba(255, 255, 255, .028) 1px, transparent 1px);
+ background-size: 42px 42px;
+ mask-image: linear-gradient(180deg, rgba(0,0,0,.7), transparent 55%);
+}
+.slide::after {
+ content: "";
+ position: absolute;
+ width: 420px;
+ height: 180px;
+ left: -110px;
+ bottom: 34px;
+ border-radius: 40px;
+ background: linear-gradient(135deg, rgba(244, 183, 64, .18), rgba(109, 140, 255, .08));
+ transform: rotate(-24deg);
+ pointer-events: none;
+}
+.slide > * { position: relative; z-index: 1; }
+.slide.active { display: block; animation: fadeUp .28s ease-out; }
+@keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
+
+.kicker {
+ font-size: clamp(13px, calc(17px * var(--slide-scale)), 24px);
+ font-weight: 900;
+ color: var(--amber);
+ margin-bottom: clamp(5px, calc(8px * var(--slide-scale)), 14px);
+ letter-spacing: -.2px;
+}
+h1, h2 { margin: 0; line-height: 1.08; letter-spacing: -1px; }
+h1 { font-size: clamp(34px, calc(58px * var(--slide-scale)), 82px); }
+h2 { font-size: clamp(27px, calc(46px * var(--slide-scale)), 66px); }
+.subtitle {
+ color: var(--muted);
+ font-size: clamp(16px, calc(22px * var(--slide-scale)), 32px);
+ margin: clamp(10px, calc(16px * var(--slide-scale)), 24px) 0 clamp(16px, calc(26px * var(--slide-scale)), 36px);
+}
+
+.hero-grid {
+ display: grid;
+ grid-template-columns: 1.18fr .82fr;
+ gap: clamp(16px, calc(28px * var(--slide-scale)), 42px);
+ align-items: stretch;
+ margin-top: clamp(14px, calc(26px * var(--slide-scale)), 38px);
+}
+.hero-img, .demo-layout img {
+ width: 100%;
+ border: 1px solid rgba(255, 255, 255, .12);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ box-shadow: 0 22px 54px rgba(0, 0, 0, .28);
+ background: #202332;
+}
+.glass-panel,
+.glass-media {
+ background: var(--glass);
+ border: 1px solid rgba(255, 255, 255, .12);
+ box-shadow: 0 22px 58px rgba(0, 0, 0, .24);
+ backdrop-filter: blur(18px) saturate(135%);
+}
+.talk-track {
+ background: var(--glass);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(20px, calc(30px * var(--slide-scale)), 44px);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: clamp(8px, calc(14px * var(--slide-scale)), 20px);
+}
+.talk-track span {
+ color: var(--muted);
+ font-weight: 900;
+ font-size: clamp(15px, calc(22px * var(--slide-scale)), 32px);
+}
+.talk-track strong {
+ font-size: clamp(20px, calc(28px * var(--slide-scale)), 42px);
+ direction: ltr;
+ text-align: left;
+ line-height: 1.5;
+}
+
+.signal-board {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 10px;
+ margin-top: 22px;
+}
+.signal {
+ min-height: 74px;
+ border: 1px solid rgba(255,255,255,.11);
+ border-radius: 10px;
+ background: rgba(255,255,255,.055);
+ padding: 14px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ direction: ltr;
+}
+.signal i,
+.step-dot,
+.metric-icon {
+ width: 34px;
+ height: 34px;
+ border-radius: 50%;
+ display: inline-grid;
+ place-items: center;
+ background: var(--amber);
+ color: #1f2937;
+ font-style: normal;
+ font-weight: 900;
+ flex: 0 0 auto;
+}
+.signal b {
+ display: block;
+ color: var(--ink);
+ font-size: 15px;
+}
+.signal span {
+ color: var(--muted);
+ font-size: 13px;
+}
+
+.image-focus {
+ margin-top: clamp(16px, calc(28px * var(--slide-scale)), 44px);
+ background: var(--glass);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(12px, calc(18px * var(--slide-scale)), 26px);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: clamp(260px, calc(365px * var(--slide-scale)), 560px);
+}
+.image-focus.compact { height: clamp(290px, calc(390px * var(--slide-scale)), 590px); }
+.image-focus img { max-width: 100%; max-height: 100%; object-fit: contain; }
+
+.mini-points {
+ position: absolute;
+ right: clamp(32px, calc(58px * var(--slide-scale)), 86px);
+ left: clamp(32px, calc(58px * var(--slide-scale)), 86px);
+ bottom: clamp(24px, calc(36px * var(--slide-scale)), 56px);
+ display: flex;
+ flex-wrap: wrap;
+ gap: clamp(8px, calc(12px * var(--slide-scale)), 18px);
+ justify-content: center;
+}
+.mini-points span {
+ background: rgba(255,255,255,.08);
+ border: 1px solid rgba(255,255,255,.13);
+ color: #f8fafc;
+ border-radius: 10px;
+ padding: clamp(7px, calc(10px * var(--slide-scale)), 14px) clamp(11px, calc(16px * var(--slide-scale)), 22px);
+ font-size: clamp(12px, calc(16px * var(--slide-scale)), 22px);
+ font-weight: 800;
+}
+
+.timeline-panel {
+ display: grid;
+ grid-template-columns: 1.1fr .9fr;
+ gap: clamp(16px, calc(22px * var(--slide-scale)), 30px);
+ margin-top: clamp(16px, calc(28px * var(--slide-scale)), 42px);
+ align-items: stretch;
+}
+.timeline-panel .image-focus {
+ margin: 0;
+ height: auto;
+}
+.timeline-cards {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 12px;
+}
+.timeline-cards article {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 10px;
+ padding: 16px 18px;
+ display: grid;
+ grid-template-columns: auto 1fr;
+ gap: 12px;
+ align-items: center;
+}
+.timeline-cards small {
+ min-width: 58px;
+ color: var(--amber);
+ font-weight: 900;
+ direction: ltr;
+ text-align: left;
+}
+.timeline-cards b {
+ display: block;
+ margin-bottom: 3px;
+}
+ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+li {
+ margin: 0;
+ color: var(--muted);
+ font-size: clamp(12px, calc(15px * var(--slide-scale)), 21px);
+ line-height: 1.65;
+}
+li::before {
+ content: "";
+ display: inline-block;
+ width: .46em;
+ height: .46em;
+ margin-left: .55em;
+ border-radius: 50%;
+ background: var(--amber);
+ vertical-align: .08em;
+}
+
+.resource-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: clamp(12px, calc(18px * var(--slide-scale)), 26px);
+ margin-top: clamp(24px, calc(44px * var(--slide-scale)), 62px);
+}
+.resource-grid article,
+.version-row article {
+ min-height: clamp(170px, calc(250px * var(--slide-scale)), 350px);
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(16px, calc(24px * var(--slide-scale)), 34px);
+ position: relative;
+ overflow: hidden;
+}
+.resource-grid article::before,
+.version-row article::before {
+ content: "";
+ display: block;
+ width: 42px;
+ height: 6px;
+ border-radius: 999px;
+ background: var(--amber);
+ margin-bottom: 18px;
+}
+.resource-grid b,
+.version-row b {
+ display: block;
+ font-size: clamp(18px, calc(25px * var(--slide-scale)), 36px);
+ margin-bottom: clamp(8px, calc(14px * var(--slide-scale)), 22px);
+}
+.quote {
+ position: absolute;
+ right: clamp(32px, calc(58px * var(--slide-scale)), 86px);
+ left: clamp(32px, calc(58px * var(--slide-scale)), 86px);
+ bottom: clamp(28px, calc(42px * var(--slide-scale)), 64px);
+ text-align: center;
+ font-weight: 900;
+ color: #f8fafc;
+ font-size: clamp(16px, calc(22px * var(--slide-scale)), 32px);
+ margin: 0;
+}
+
+.split {
+ display: grid;
+ grid-template-columns: 1.06fr .94fr;
+ gap: clamp(16px, calc(24px * var(--slide-scale)), 36px);
+ margin-top: clamp(20px, calc(34px * var(--slide-scale)), 48px);
+ align-items: stretch;
+}
+.diagram-card {
+ background: var(--glass);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(12px, calc(18px * var(--slide-scale)), 26px);
+ display: flex;
+ align-items: center;
+}
+.diagram-card img { width: 100%; max-height: 100%; object-fit: contain; }
+.code-stack {
+ display: flex;
+ flex-direction: column;
+ gap: clamp(12px, calc(18px * var(--slide-scale)), 26px);
+ justify-content: center;
+}
+pre {
+ margin: 0;
+ background: rgba(9, 12, 22, .78);
+ color: #e5edff;
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(14px, calc(22px * var(--slide-scale)), 32px);
+ overflow: hidden;
+ white-space: pre-wrap;
+ font-size: clamp(11px, calc(16px * var(--slide-scale)), 22px);
+ line-height: 1.65;
+ box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
+}
+.ltr { direction: ltr; text-align: left; }
+
+.version-row {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: clamp(14px, calc(22px * var(--slide-scale)), 32px);
+ margin-top: clamp(28px, calc(52px * var(--slide-scale)), 78px);
+}
+.version-row article { min-height: clamp(210px, calc(300px * var(--slide-scale)), 430px); }
+.version-row span {
+ display: inline-block;
+ background: var(--amber-2);
+ color: #ffe8aa;
+ border-radius: 999px;
+ padding: clamp(5px, calc(7px * var(--slide-scale)), 10px) clamp(10px, calc(14px * var(--slide-scale)), 20px);
+ font-size: clamp(12px, calc(16px * var(--slide-scale)), 22px);
+ font-weight: 900;
+ margin-bottom: clamp(12px, calc(20px * var(--slide-scale)), 30px);
+}
+.focus-line {
+ margin-top: clamp(18px, calc(30px * var(--slide-scale)), 44px);
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ color: #f8fafc;
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(12px, calc(18px * var(--slide-scale)), 26px) clamp(16px, calc(22px * var(--slide-scale)), 34px);
+ font-size: clamp(15px, calc(22px * var(--slide-scale)), 32px);
+ text-align: center;
+}
+
+.flow {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: clamp(12px, calc(18px * var(--slide-scale)), 26px);
+ margin-top: clamp(28px, calc(48px * var(--slide-scale)), 72px);
+}
+.flow div {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: clamp(10px, calc(14px * var(--slide-scale)), 18px);
+ padding: clamp(14px, calc(22px * var(--slide-scale)), 32px) clamp(10px, calc(14px * var(--slide-scale)), 22px);
+ min-height: clamp(80px, calc(105px * var(--slide-scale)), 155px);
+ display: grid;
+ place-items: center;
+ text-align: center;
+ font-weight: 900;
+ font-size: clamp(13px, calc(18px * var(--slide-scale)), 25px);
+ position: relative;
+}
+.flow div:not(:nth-child(4n))::after {
+ content: "←";
+ position: absolute;
+ left: clamp(-18px, calc(-16px * var(--slide-scale)), -10px);
+ top: 38%;
+ color: var(--amber);
+ font-size: clamp(18px, calc(24px * var(--slide-scale)), 34px);
+}
+
+.upgrade-map {
+ display: grid;
+ grid-template-columns: 1fr auto 1fr;
+ gap: 16px;
+ align-items: center;
+ margin-top: 18px;
+}
+.endpoint {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 14px;
+ padding: 20px;
+ min-height: 138px;
+}
+.endpoint span {
+ display: block;
+ color: var(--muted);
+ font-weight: 800;
+ margin-bottom: 8px;
+}
+.endpoint b {
+ font-size: 26px;
+}
+.upgrade-steps {
+ width: min(410px, 34vw);
+ display: grid;
+ gap: 12px;
+}
+.upgrade-steps div {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 10px;
+ padding: 12px 14px;
+ direction: ltr;
+ text-align: center;
+ font-weight: 900;
+ color: #f7c75f;
+}
+.upgrade-steps div:nth-child(2) { color: #43d9a3; }
+.upgrade-steps div:nth-child(3) { color: #aebdff; }
+
+.osi-board {
+ display: grid;
+ grid-template-columns: 1.05fr .95fr;
+ gap: 20px;
+ align-items: stretch;
+ margin-top: 24px;
+}
+.osi-stack {
+ display: grid;
+ gap: 9px;
+}
+.osi-layer {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 10px;
+ padding: 12px 16px;
+ display: grid;
+ grid-template-columns: 150px 1fr;
+ gap: 14px;
+ align-items: center;
+ direction: ltr;
+}
+.osi-layer.active {
+ background: rgba(109, 140, 255, .34);
+ border-color: rgba(109, 140, 255, .50);
+ color: #fff;
+}
+.osi-layer.transport {
+ background: rgba(67, 217, 163, .26);
+ border-color: rgba(67, 217, 163, .44);
+ color: #fff;
+}
+.osi-layer b { font-size: 16px; }
+.osi-layer span { color: inherit; opacity: .85; font-size: 14px; }
+.layer-note {
+ background: var(--glass);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 14px;
+ padding: 22px;
+ display: grid;
+ align-content: center;
+ gap: 14px;
+}
+.layer-note div {
+ display: flex;
+ gap: 12px;
+ align-items: center;
+}
+.layer-note i { background: var(--green); }
+
+.topology {
+ display: grid;
+ grid-template-columns: 1fr 1.1fr 1fr;
+ gap: 20px;
+ align-items: center;
+ margin-top: 28px;
+}
+.node-column {
+ display: grid;
+ gap: 14px;
+}
+.node {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 12px;
+ padding: 16px;
+ text-align: center;
+ min-height: 86px;
+}
+.node b { display: block; font-size: 18px; }
+.node span { color: var(--muted); font-size: 14px; }
+.server-node {
+ background: linear-gradient(145deg, rgba(244, 183, 64, .34), rgba(109, 140, 255, .20));
+ color: #fff;
+ border-radius: 16px;
+ padding: 28px 18px;
+ text-align: center;
+ box-shadow: 0 18px 44px rgba(37, 99, 235, .22);
+}
+.server-node span { color: #dbeafe; }
+.room-badge {
+ margin-top: 12px;
+ display: inline-block;
+ border-radius: 999px;
+ padding: 7px 12px;
+ background: rgba(255,255,255,.12);
+ color: #fff;
+ font-weight: 900;
+}
+
+.pipeline {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 12px;
+ margin-top: 28px;
+ direction: ltr;
+}
+.pipe-step {
+ min-height: 132px;
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 12px;
+ padding: 16px;
+ display: grid;
+ align-content: center;
+ gap: 10px;
+ text-align: center;
+ position: relative;
+}
+.pipe-step:not(:last-child)::after {
+ content: "→";
+ position: absolute;
+ right: -17px;
+ top: 44%;
+ color: var(--amber);
+ font-size: 25px;
+ font-weight: 900;
+}
+.pipe-step b { font-size: 15px; }
+.pipe-step span { color: var(--muted); font-size: 13px; }
+
+.metrics {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+ margin-top: 24px;
+}
+.metric-card {
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 14px;
+ padding: 18px;
+ display: grid;
+ gap: 10px;
+ min-height: 130px;
+}
+.metric-card b { font-size: 20px; }
+.metric-card:nth-child(2) .metric-icon { background: var(--green); }
+.metric-card:nth-child(3) .metric-icon { background: var(--amber); }
+
+.demo-layout {
+ display: grid;
+ grid-template-columns: 1fr .9fr;
+ gap: clamp(20px, calc(36px * var(--slide-scale)), 52px);
+ margin-top: clamp(22px, calc(38px * var(--slide-scale)), 56px);
+ align-items: start;
+}
+ol {
+ margin: 0;
+ padding-right: clamp(20px, calc(28px * var(--slide-scale)), 42px);
+ font-size: clamp(15px, calc(21px * var(--slide-scale)), 30px);
+ line-height: 2;
+ color: #23324a;
+ background: rgba(255,255,255,.075);
+ border: 1px solid rgba(255,255,255,.12);
+ border-radius: 14px;
+ padding-top: 22px;
+ padding-bottom: 22px;
+}
+code {
+ direction: ltr;
+ unicode-bidi: embed;
+ background: rgba(255,255,255,.10);
+ padding: 3px 7px;
+ border-radius: 8px;
+ color: #f7c75f;
+}
+
+.controls {
+ position: fixed;
+ left: 28px;
+ bottom: 24px;
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ z-index: 5;
+ direction: ltr;
+}
+.controls button {
+ width: 42px;
+ height: 42px;
+ border: 0;
+ border-radius: 50%;
+ background: rgba(255,255,255,.10);
+ color: #fff;
+ box-shadow: 0 10px 28px rgba(0, 0, 0, .26);
+ font-size: 28px;
+ cursor: pointer;
+}
+.controls span { font-weight: 800; color: var(--muted); min-width: 58px; text-align: center; }
+.hint {
+ position: fixed;
+ right: 28px;
+ bottom: 31px;
+ color: var(--muted);
+ font-weight: 700;
+ font-size: 14px;
+}
+.progress {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ height: 5px;
+ background: rgba(37, 99, 235, .08);
+}
+.progress span { display: block; height: 100%; width: 10%; background: var(--amber); transition: width .2s ease; }
+.speaker-notes {
+ display: none;
+ position: fixed;
+ right: 50%;
+ transform: translateX(50%);
+ bottom: 84px;
+ width: min(900px, calc(100vw - 64px));
+ background: rgba(15, 23, 42, .92);
+ color: #fff;
+ border-radius: 22px;
+ padding: 20px 24px;
+ line-height: 1.8;
+ font-size: clamp(14px, 1.45vw, 19px);
+ z-index: 6;
+ box-shadow: 0 22px 80px rgba(15,23,42,.35);
+}
+.speaker-notes.show { display: block; }
+.notes { display: none; }
+
+@media print {
+ body { overflow: visible; background: #fff; }
+ .deck { height: auto; display: block; }
+ .slide { display: block !important; box-shadow: none; margin: 0; page-break-after: always; width: 100vw; height: 56.25vw; border: 0; border-radius: 0; }
+ .controls, .hint, .progress, .speaker-notes { display: none !important; }
+}
+
+@media (max-width: 900px) {
+ body { overflow: auto; }
+ .deck { width: 100%; min-height: auto; display: block; padding: 12px; }
+ .slide {
+ width: 100%;
+ height: auto;
+ min-height: calc(100svh - 24px);
+ margin: 0 auto;
+ padding: clamp(18px, 5vw, 28px);
+ border-radius: 22px;
+ overflow: visible;
+ }
+ h1 { font-size: clamp(30px, 8.4vw, 42px); }
+ h2 { font-size: clamp(24px, 7vw, 34px); }
+ .subtitle { font-size: clamp(14px, 4vw, 18px); }
+ .kicker { font-size: clamp(12px, 3.7vw, 16px); }
+ .hero-grid, .split, .demo-layout, .version-row, .resource-grid { grid-template-columns: 1fr; }
+ .hero-grid, .split, .demo-layout { gap: 18px; }
+ .resource-grid, .version-row { gap: 12px; margin-top: 22px; }
+ .resource-grid article, .version-row article { min-height: auto; padding: 16px; }
+ .resource-grid b, .version-row b { font-size: 18px; }
+ .resource-grid p, .version-row p { font-size: 13px; }
+ .image-focus, .image-focus.compact { height: auto; min-height: 0; padding: 10px; }
+ .image-focus img { width: 100%; height: auto; }
+ .flow { grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 22px; }
+ .flow div { min-height: 72px; font-size: 13px; padding: 12px 8px; }
+ .flow div::after { display: none; }
+ .mini-points, .quote { position: static; margin-top: 18px; }
+ .mini-points { gap: 8px; }
+ .mini-points span { font-size: 12px; padding: 7px 10px; }
+ .quote { font-size: 15px; }
+ pre { font-size: clamp(10px, 2.8vw, 13px); padding: 14px; }
+ ol { font-size: 14px; line-height: 1.9; }
+ .controls { left: 14px; bottom: 14px; }
+ .controls button { width: 36px; height: 36px; font-size: 24px; }
+ .hint { display: none; }
+ .speaker-notes { bottom: 64px; width: calc(100vw - 28px); font-size: 14px; }
+}
+
+@media (max-width: 560px) {
+ .slide { padding: 18px; }
+ .flow { grid-template-columns: 1fr; }
+ .talk-track strong { font-size: 17px; }
+}