@import "tailwindcss"; @import "tw-animate-css"; @import "./custom-fonts.css"; @plugin "@tailwindcss/typography"; @custom-variant dark (&:is(.dark *)); @theme inline { --color-background: hsl(var(--background)); --color-foreground: hsl(var(--foreground)); --color-border: hsl(var(--border)); --color-input: hsl(var(--input)); --color-ring: hsl(var(--ring)); --color-card: hsl(var(--card)); --color-card-foreground: hsl(var(--card-foreground)); --color-card-border: hsl(var(--card-border)); --color-popover: hsl(var(--popover)); --color-popover-foreground: hsl(var(--popover-foreground)); --color-popover-border: hsl(var(--popover-border)); --color-primary: hsl(var(--primary)); --color-primary-foreground: hsl(var(--primary-foreground)); --color-primary-border: var(--primary-border); --color-secondary: hsl(var(--secondary)); --color-secondary-foreground: hsl(var(--secondary-foreground)); --color-secondary-border: var(--secondary-border); --color-muted: hsl(var(--muted)); --color-muted-foreground: hsl(var(--muted-foreground)); --color-muted-border: var(--muted-border); --color-accent: hsl(var(--accent)); --color-accent-foreground: hsl(var(--accent-foreground)); --color-accent-border: var(--accent-border); --color-destructive: hsl(var(--destructive)); --color-destructive-foreground: hsl(var(--destructive-foreground)); --color-destructive-border: var(--destructive-border); --color-sidebar: hsl(var(--sidebar)); --color-sidebar-foreground: hsl(var(--sidebar-foreground)); --color-sidebar-border: hsl(var(--sidebar-border)); --color-sidebar-primary: hsl(var(--sidebar-primary)); --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground)); --color-sidebar-primary-border: var(--sidebar-primary-border); --color-sidebar-accent: hsl(var(--sidebar-accent)); --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground)); --color-sidebar-accent-border: var(--sidebar-accent-border); --color-sidebar-ring: hsl(var(--sidebar-ring)); --font-sans: var(--app-font-sans); --font-serif: var(--app-font-serif); --font-mono: var(--app-font-mono); --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); } :root { /* Light, calm, premium SaaS palette */ --background: 210 40% 98%; /* #F8FAFC */ --foreground: 222 47% 11%; /* slate-900 */ --card: 0 0% 100%; /* #FFFFFF */ --card-foreground: 222 47% 11%; --popover: 0 0% 100%; --popover-foreground: 222 47% 11%; --primary: 218 55% 32%; /* #2C4A8A */ --primary-foreground: 0 0% 100%; --secondary: 173 80% 40%; /* teal-500 */ --secondary-foreground: 0 0% 100%; --muted: 210 40% 96%; --muted-foreground: 215 16% 47%; /* slate-500 */ --accent: 210 40% 96%; /* slate-100 — matches sidebar hover */ --accent-foreground: 222 47% 11%; /* slate-900 */ --destructive: 0 84% 60%; --destructive-foreground: 0 0% 100%; --border: 214 32% 91%; /* #E2E8F0 */ --input: 214 32% 91%; --ring: 218 55% 32%; --sidebar: 0 0% 100%; --sidebar-foreground: 222 47% 11%; --sidebar-border: 214 32% 91%; --sidebar-primary: 218 55% 32%; --sidebar-primary-foreground: 0 0% 100%; --sidebar-accent: 210 40% 96%; --sidebar-accent-foreground: 222 47% 11%; --sidebar-ring: 218 55% 32%; /* * Site-wide default font. DIN Next LT Arabic ships locally via * `custom-fonts.css` (loaded on the line `@import "./custom-fonts.css"` * at the top of this file), so this resolves immediately without a * Google Fonts roundtrip. The remaining fallbacks are kept so the * page remains readable while the @font-face files are still being * fetched on a cold cache (font-display: swap). */ --app-font-sans: "DIN Next LT Arabic", "Tajawal", system-ui, sans-serif; --app-font-serif: Georgia, serif; --app-font-mono: Menlo, Consolas, monospace; --radius: 1rem; } @layer base { * { @apply border-border; } body { @apply font-sans antialiased text-foreground; background-color: #F8FAFC; } html, body { overflow-x: clip; } /* * #460: On iOS Safari (iPad/iPhone), the URL bar only auto-collapses * when the document is actually scrollable. Pages with short content * (Services grid, Notifications list, an empty Notes tab, etc.) fit * entirely within the viewport, so Safari has no scroll trigger and * the URL bar stays pinned — wasting screen real estate. * * We force the document to always be ~1px taller than the small * viewport (`100svh` = the viewport height *with* the URL bar * visible, so the +1px gap stays constant whether the bar is shown * or hidden). That tiny extra height is enough for Safari to enable * its URL-bar-collapse gesture on every page. * * Scoped to touch devices via `(hover: none) and (pointer: coarse)` * so desktop browsers never get a stray scrollbar on short pages. */ @media (hover: none) and (pointer: coarse) { html, body { min-height: calc(100svh + 1px); } } } /* Soft glassmorphism — light, very subtle blur */ .glass-panel { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(12px) saturate(140%); -webkit-backdrop-filter: blur(12px) saturate(140%); border: 1px solid #E2E8F0; box-shadow: 0 8px 30px rgba(15, 23, 42, 0.05); } /* Light gradient background with floating blobs (Apple / SaaS style) */ .os-bg { position: relative; background-color: #F8FAFC; } .os-bg::before, .os-bg::after { content: ""; position: fixed; pointer-events: none; z-index: 0; border-radius: 9999px; filter: blur(80px); opacity: 0.55; } .os-bg::before { width: 520px; height: 520px; top: -160px; left: -120px; background: radial-gradient(circle at 30% 30%, #C7D2FE 0%, #A5B4FC 40%, transparent 70%); animation: blobFloat 18s ease-in-out infinite alternate; } .os-bg::after { width: 560px; height: 560px; bottom: -200px; right: -160px; background: radial-gradient(circle at 60% 60%, #A7F3D0 0%, #99F6E4 35%, transparent 70%); animation: blobFloat 22s ease-in-out infinite alternate-reverse; } .os-bg > * { /* Was: position: relative; z-index: 1; `position: relative` was overriding `position: sticky` (and `fixed`) on direct children, so sticky headers detached on scroll. Use `isolation: isolate` to create a stacking context that lifts children above the floating ::before / ::after blobs WITHOUT forcing them to position:relative. */ isolation: isolate; } @keyframes blobFloat { 0% { transform: translate(0, 0) scale(1); } 50% { transform: translate(30px, -20px) scale(1.05); } 100% { transform: translate(-20px, 25px) scale(0.98); } } /* Gradient icon tile helpers */ .icon-tile { display: inline-flex; align-items: center; justify-content: center; border-radius: 1rem; box-shadow: 0 6px 18px rgba(11, 30, 63, 0.18); transition: transform 0.2s ease, box-shadow 0.2s ease; } .icon-tile:hover { transform: translateY(-2px); box-shadow: 0 10px 24px rgba(11, 30, 63, 0.22); } .icon-tile-blue { background: linear-gradient(135deg, #60A5FA, #3B82F6); } .icon-tile-purple { background: linear-gradient(135deg, #C084FC, #8B5CF6); } .icon-tile-green { background: linear-gradient(135deg, #34D399, #10B981); } .icon-tile-orange { background: linear-gradient(135deg, #FDBA74, #F59E0B); } .icon-tile-pink { background: linear-gradient(135deg, #F9A8D4, #EC4899); } .icon-tile-teal { background: linear-gradient(135deg, #5EEAD4, #14B8A6); } /* Top bar variant — flat very-light glass, no heavy border */ .topbar-glass { background: rgba(255, 255, 255, 0.75); backdrop-filter: blur(16px) saturate(160%); -webkit-backdrop-filter: blur(16px) saturate(160%); border-bottom: 1px solid rgba(226, 232, 240, 0.7); } /* Floating dock — macOS-like but lighter */ .dock-glass { background: rgba(255, 255, 255, 0.65); backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%); border: 1px solid rgba(226, 232, 240, 0.9); box-shadow: 0 12px 40px rgba(15, 23, 42, 0.08); } /* Card hover lift */ .card-hover { transition: transform 0.2s ease, box-shadow 0.2s ease; } .card-hover:hover { transform: translateY(-2px); box-shadow: 0 14px 36px rgba(15, 23, 42, 0.08); } /* Animated login art — flowing gradient lines + drifting orbs */ .art-gradient { background: radial-gradient(60% 80% at 20% 20%, hsl(217 91% 30% / 0.55), transparent 70%), radial-gradient(60% 80% at 80% 70%, hsl(262 83% 35% / 0.55), transparent 70%), radial-gradient(50% 70% at 50% 100%, hsl(172 70% 30% / 0.45), transparent 70%), linear-gradient(160deg, hsl(222 47% 8%), hsl(222 47% 14%)); animation: artBgShift 18s ease-in-out infinite alternate; } @keyframes artBgShift { 0% { filter: hue-rotate(0deg) saturate(1); } 100% { filter: hue-rotate(15deg) saturate(1.15); } } .art-orb { filter: blur(60px); opacity: 0.55; mix-blend-mode: screen; will-change: transform; } .art-orb-a { background: radial-gradient(circle, hsl(217 91% 60%), transparent 70%); animation: artOrbFloatA 14s ease-in-out infinite alternate; } .art-orb-b { background: radial-gradient(circle, hsl(262 83% 70%), transparent 70%); animation: artOrbFloatB 17s ease-in-out infinite alternate; } .art-orb-c { background: radial-gradient(circle, hsl(172 70% 55%), transparent 70%); animation: artOrbFloatC 20s ease-in-out infinite alternate; } @keyframes artOrbFloatA { 0% { transform: translate(0, 0) scale(1); } 100% { transform: translate(80px, 60px) scale(1.15); } } @keyframes artOrbFloatB { 0% { transform: translate(0, 0) scale(1); } 100% { transform: translate(-60px, -50px) scale(1.1); } } @keyframes artOrbFloatC { 0% { transform: translate(0, 0) scale(1); } 100% { transform: translate(40px, -70px) scale(1.2); } } .art-line { stroke-dasharray: 600; stroke-dashoffset: 600; stroke-width: 2.5; animation: artLineDraw 8s ease-in-out infinite; filter: drop-shadow(0 0 8px hsl(217 91% 60% / 0.9)); } .art-line-1 { animation-delay: 0s; } .art-line-2 { animation-delay: 1.2s; } .art-line-3 { animation-delay: 2.4s; } .art-line-4 { animation-delay: 3.6s; } .art-line-5 { animation-delay: 4.8s; } @keyframes artLineDraw { 0% { stroke-dashoffset: 600; opacity: 0; } 20% { opacity: 1; } 60% { stroke-dashoffset: 0; opacity: 1; } 100% { stroke-dashoffset: -600; opacity: 0; } } .art-particle { position: absolute; width: 4px; height: 4px; border-radius: 9999px; background: white; box-shadow: 0 0 12px 2px white; opacity: 0; animation: artParticleFloat 6s ease-in-out infinite; } @keyframes artParticleFloat { 0% { opacity: 0; transform: translateY(0) scale(0.8); } 50% { opacity: 0.9; transform: translateY(-30px) scale(1.1); } 100% { opacity: 0; transform: translateY(-60px) scale(0.8); } } @media (prefers-reduced-motion: reduce) { .art-gradient, .art-orb, .art-line, .art-particle { animation: none !important; } .art-line { stroke-dashoffset: 0; opacity: 1; } } /* Hide scrollbars site-wide while keeping scroll functionality */ * { scrollbar-width: none; -ms-overflow-style: none; } *::-webkit-scrollbar { width: 0; height: 0; display: none; } /* * Prevent iOS Safari from auto-zooming the page when the user taps into * a form field. iOS only triggers zoom when the focused control's * computed font-size is < 16px, so we force a 16px minimum on iOS. * * Scoped via `@supports (-webkit-touch-callout: none)`, which is only * true on iOS Safari (iPhone + iPad). Desktop, Android, and other * browsers are unaffected, so visual typography is unchanged elsewhere. */ @supports (-webkit-touch-callout: none) { input, textarea, select, [contenteditable="true"] { font-size: 16px !important; } } /* * #344: Attention-grabbing blink for the "starts in N minutes" headline * inside the floating UpcomingMeetingAlert. Tailwind's `animate-pulse` * only fades to opacity 0.5, which doesn't read as a true blink, so we * ship a dedicated keyframe that drops to 0.15 and back. Respects the * user's reduced-motion preference by stopping at full opacity. */ @keyframes em-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.15; } } .em-blink { animation: em-blink 1s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .em-blink { animation: none; opacity: 1; } } /* * #350 (browser print): When the user prints the Executive Meetings * schedule via the browser (Ctrl+P / "Save as PDF"), Chrome sometimes * falls back to a system font that has Arabic glyphs but no GSUB * shaping table. The result is Arabic text rendered as isolated, * unconnected letterforms — and because the browser then runs the * bidi algorithm on those isolated glyphs, the text appears reversed * (e.g. "قائمة" prints as "ةمئاق"). * * Fix: in print mode, force every element onto DIN Next LT Arabic * (the app's primary Arabic font, which has a full GSUB shaping * table). Combined with `font-display: block` in custom-fonts.css * and `` in index.html, this ensures Chrome * never falls back to a system font during the print snapshot. We * also explicitly enable common-ligatures and contextual-alternates * (`liga`, `calt`) which drive Arabic joining, and pin direction to * RTL when the page is in Arabic so Chrome doesn't mis-resolve bidi * for cells whose first glyph is Latin. */ @media print { html, body, body * { font-family: "DIN Next LT Arabic", sans-serif !important; font-feature-settings: "liga" 1, "calt" 1, "rlig" 1 !important; -webkit-font-feature-settings: "liga" 1, "calt" 1, "rlig" 1 !important; text-rendering: optimizeLegibility; } html[dir="rtl"] #executive-schedule-printable { direction: rtl; unicode-bidi: isolate; } } /* * Arabic dot/diacritic clipping fix for truncated text ( follow-up). * * `.truncate` uses `overflow: hidden` + `white-space: nowrap`. With Tailwind's * default tight line-heights on small text (text-xs / text-sm / text-[11px]), * the line-box is shorter than what Arabic glyphs actually paint — the dots * under ي / ب / ج and over ت / ن get sliced off, especially on iPad/WebKit * which rasterizes these faces a hair taller than desktop. * * Fix: when the document is in RTL, give every truncated element a roomier * line-height so the line-box covers the full glyph extent. 1.6 matches what * we shipped for the launcher tiles in #503 and is safe for single-line * (`white-space: nowrap`) layouts where vertical rhythm doesn't matter. */ html[dir="rtl"] .truncate { line-height: 1.6; }