Spaces:
Paused
Paused
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Sanctuary — Initializing</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link | |
| href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" | |
| rel="stylesheet"> | |
| <style> | |
| *, | |
| *::before, | |
| *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| :root { | |
| --bg: #070510; | |
| --surface: rgba(16, 12, 32, 0.72); | |
| --border: rgba(139, 92, 246, 0.18); | |
| --border-hi: rgba(139, 92, 246, 0.45); | |
| --purple: #8b5cf6; | |
| --violet: #6d28d9; | |
| --lavender: #c4b5fd; | |
| --indigo: #6366f1; | |
| --text-1: #f3f0ff; | |
| --text-2: #9d94bb; | |
| --text-3: #5d5478; | |
| --green: #34d399; | |
| --amber: #fbbf24; | |
| --red: #f87171; | |
| } | |
| html, | |
| body { | |
| height: 100%; | |
| font-family: 'Inter', sans-serif; | |
| background: var(--bg); | |
| color: var(--text-1); | |
| overflow: hidden; | |
| } | |
| /* ── Canvas particle layer ── */ | |
| #canvas { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 0; | |
| opacity: 0.55; | |
| } | |
| /* ── Radial vignette ── */ | |
| .vignette { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 1; | |
| background: radial-gradient(ellipse 80% 80% at 50% 50%, transparent 30%, var(--bg) 100%); | |
| pointer-events: none; | |
| } | |
| /* ── Layout ── */ | |
| .shell { | |
| position: relative; | |
| z-index: 10; | |
| height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 24px; | |
| } | |
| /* ── Card ── */ | |
| .card { | |
| width: 100%; | |
| max-width: 480px; | |
| background: var(--surface); | |
| backdrop-filter: blur(24px) saturate(160%); | |
| -webkit-backdrop-filter: blur(24px) saturate(160%); | |
| border: 1px solid var(--border); | |
| border-radius: 24px; | |
| padding: 40px 36px 32px; | |
| box-shadow: | |
| 0 0 0 1px rgba(139, 92, 246, 0.06), | |
| 0 24px 64px rgba(0, 0, 0, 0.55), | |
| inset 0 1px 0 rgba(255, 255, 255, 0.07); | |
| animation: card-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) both; | |
| } | |
| @keyframes card-in { | |
| from { | |
| opacity: 0; | |
| transform: translateY(18px) scale(0.97); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0) scale(1); | |
| } | |
| } | |
| /* ── Orbital logo ── */ | |
| .logo-wrap { | |
| display: flex; | |
| justify-content: center; | |
| margin-bottom: 28px; | |
| } | |
| .orbital { | |
| position: relative; | |
| width: 88px; | |
| height: 88px; | |
| } | |
| .orbital svg { | |
| position: absolute; | |
| inset: 0; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .ring-outer { | |
| animation: spin 3s linear infinite; | |
| transform-origin: center; | |
| } | |
| .ring-inner { | |
| animation: spin-rev 2s linear infinite; | |
| transform-origin: center; | |
| } | |
| @keyframes spin { | |
| to { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| @keyframes spin-rev { | |
| to { | |
| transform: rotate(-360deg); | |
| } | |
| } | |
| .logo-core { | |
| position: absolute; | |
| inset: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .logo-glyph { | |
| width: 46px; | |
| height: 46px; | |
| border-radius: 14px; | |
| background: linear-gradient(135deg, #8b5cf6, #6d28d9); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 22px; | |
| font-weight: 700; | |
| color: #fff; | |
| letter-spacing: -1px; | |
| box-shadow: 0 0 28px rgba(139, 92, 246, 0.55); | |
| animation: logo-pulse 2.4s ease-in-out infinite alternate; | |
| } | |
| @keyframes logo-pulse { | |
| from { | |
| box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); | |
| } | |
| to { | |
| box-shadow: 0 0 40px rgba(139, 92, 246, 0.8); | |
| } | |
| } | |
| /* ── Heading ── */ | |
| .heading { | |
| text-align: center; | |
| margin-bottom: 6px; | |
| } | |
| h1 { | |
| font-size: 22px; | |
| font-weight: 700; | |
| letter-spacing: -0.4px; | |
| background: linear-gradient(120deg, #fff 0%, var(--lavender) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .sub { | |
| font-size: 13px; | |
| color: var(--text-2); | |
| font-weight: 400; | |
| margin-top: 6px; | |
| line-height: 1.55; | |
| } | |
| /* ── Divider ── */ | |
| .divider { | |
| height: 1px; | |
| background: linear-gradient(90deg, transparent, var(--border), transparent); | |
| margin: 24px 0 20px; | |
| } | |
| /* ── Boot log ── */ | |
| .boot-log { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| margin-bottom: 24px; | |
| } | |
| .boot-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| font-size: 13px; | |
| opacity: 0; | |
| transform: translateX(-6px); | |
| animation: row-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards; | |
| } | |
| .boot-row:nth-child(1) { | |
| animation-delay: 0.25s; | |
| } | |
| .boot-row:nth-child(2) { | |
| animation-delay: 0.45s; | |
| } | |
| .boot-row:nth-child(3) { | |
| animation-delay: 0.65s; | |
| } | |
| .boot-row:nth-child(4) { | |
| animation-delay: 0.85s; | |
| } | |
| @keyframes row-in { | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| .boot-icon { | |
| flex-shrink: 0; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 10px; | |
| } | |
| .icon-ok { | |
| background: rgba(52, 211, 153, 0.15); | |
| color: var(--green); | |
| } | |
| .icon-spin { | |
| background: rgba(251, 191, 36, 0.12); | |
| color: var(--amber); | |
| animation: icon-blink 1.2s ease-in-out infinite alternate; | |
| } | |
| .icon-wait { | |
| background: rgba(255, 255, 255, 0.05); | |
| color: var(--text-3); | |
| } | |
| @keyframes icon-blink { | |
| from { | |
| opacity: 0.5; | |
| } | |
| to { | |
| opacity: 1; | |
| } | |
| } | |
| .boot-label { | |
| flex: 1; | |
| color: var(--text-2); | |
| } | |
| .boot-status { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 11px; | |
| font-weight: 500; | |
| letter-spacing: 0.04em; | |
| } | |
| .s-ok { | |
| color: var(--green); | |
| } | |
| .s-warm { | |
| color: var(--amber); | |
| } | |
| .s-wait { | |
| color: var(--text-3); | |
| } | |
| /* ── Progress bar ── */ | |
| .progress-wrap { | |
| position: relative; | |
| height: 3px; | |
| background: rgba(255, 255, 255, 0.06); | |
| border-radius: 99px; | |
| overflow: hidden; | |
| margin-bottom: 24px; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| width: 0%; | |
| border-radius: 99px; | |
| background: linear-gradient(90deg, var(--violet), var(--purple), var(--indigo)); | |
| animation: progress-grow 8s cubic-bezier(0.25, 1, 0.5, 1) forwards; | |
| } | |
| .progress-shimmer { | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.35) 50%, transparent 100%); | |
| background-size: 200% 100%; | |
| animation: shimmer 1.8s ease-in-out infinite; | |
| } | |
| @keyframes progress-grow { | |
| 0% { | |
| width: 0%; | |
| } | |
| 20% { | |
| width: 22%; | |
| } | |
| 50% { | |
| width: 55%; | |
| } | |
| 80% { | |
| width: 78%; | |
| } | |
| 100% { | |
| width: 92%; | |
| } | |
| } | |
| @keyframes shimmer { | |
| 0% { | |
| background-position: -200% 0; | |
| } | |
| 100% { | |
| background-position: 200% 0; | |
| } | |
| } | |
| /* ── CTA button ── */ | |
| .btn { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| width: 100%; | |
| padding: 12px 20px; | |
| font-family: 'Inter', sans-serif; | |
| font-size: 13.5px; | |
| font-weight: 600; | |
| border-radius: 12px; | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| background: rgba(255, 255, 255, 0.05); | |
| color: var(--text-2); | |
| cursor: pointer; | |
| text-decoration: none; | |
| transition: background 0.2s, border-color 0.2s, color 0.2s, transform 0.15s; | |
| margin-bottom: 14px; | |
| } | |
| .btn:hover { | |
| background: rgba(139, 92, 246, 0.12); | |
| border-color: var(--border-hi); | |
| color: var(--lavender); | |
| transform: translateY(-1px); | |
| } | |
| .btn:active { | |
| transform: translateY(0); | |
| } | |
| .btn-icon { | |
| opacity: 0.6; | |
| font-size: 12px; | |
| } | |
| /* ── Footer ── */ | |
| .footer { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 6px; | |
| font-size: 11.5px; | |
| color: var(--text-3); | |
| font-family: 'JetBrains Mono', monospace; | |
| } | |
| .dot-live { | |
| width: 6px; | |
| height: 6px; | |
| border-radius: 50%; | |
| background: var(--green); | |
| box-shadow: 0 0 6px var(--green); | |
| animation: live-pulse 1.4s ease-in-out infinite; | |
| } | |
| @keyframes live-pulse { | |
| 0%, | |
| 100% { | |
| opacity: 1; | |
| } | |
| 50% { | |
| opacity: 0.3; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="canvas"></canvas> | |
| <div class="vignette"></div> | |
| <div class="shell"> | |
| <div class="card"> | |
| <!-- Orbital logo --> | |
| <div class="logo-wrap"> | |
| <div class="orbital"> | |
| <!-- Outer ring --> | |
| <svg viewBox="0 0 88 88" class="ring-outer" fill="none"> | |
| <circle cx="44" cy="44" r="40" stroke="url(#g1)" stroke-width="1.5" stroke-dasharray="6 4" | |
| stroke-linecap="round" /> | |
| <defs> | |
| <linearGradient id="g1" x1="0" y1="0" x2="88" y2="88" gradientUnits="userSpaceOnUse"> | |
| <stop stop-color="#8b5cf6" /> | |
| <stop offset="1" stop-color="#6366f1" stop-opacity="0.2" /> | |
| </linearGradient> | |
| </defs> | |
| </svg> | |
| <!-- Inner ring --> | |
| <svg viewBox="0 0 88 88" class="ring-inner" fill="none"> | |
| <circle cx="44" cy="44" r="30" stroke="url(#g2)" stroke-width="1" stroke-dasharray="3 6" | |
| stroke-linecap="round" /> | |
| <defs> | |
| <linearGradient id="g2" x1="88" y1="0" x2="0" y2="88" gradientUnits="userSpaceOnUse"> | |
| <stop stop-color="#c4b5fd" stop-opacity="0.6" /> | |
| <stop offset="1" stop-color="#6d28d9" stop-opacity="0.1" /> | |
| </linearGradient> | |
| </defs> | |
| </svg> | |
| <div class="logo-core"> | |
| <div class="logo-glyph">S</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Heading --> | |
| <div class="heading"> | |
| <h1>Initializing Sanctuary</h1> | |
| <p class="sub">Neural engine warming up. This usually takes 15–30 seconds.</p> | |
| </div> | |
| <div class="divider"></div> | |
| <!-- Boot log --> | |
| <div class="boot-log"> | |
| <div class="boot-row"> | |
| <span class="boot-icon icon-ok">✓</span> | |
| <span class="boot-label">Caddy reverse proxy</span> | |
| <span class="boot-status s-ok">ONLINE</span> | |
| </div> | |
| <div class="boot-row"> | |
| <span class="boot-icon icon-ok">✓</span> | |
| <span class="boot-label">LiteLLM API proxy</span> | |
| <span class="boot-status s-ok">ONLINE</span> | |
| </div> | |
| <div class="boot-row"> | |
| <span class="boot-icon icon-spin">⟳</span> | |
| <span class="boot-label">Gradio interface</span> | |
| <span class="boot-status s-warm">WARMING UP</span> | |
| </div> | |
| <div class="boot-row"> | |
| <span class="boot-icon icon-wait">·</span> | |
| <span class="boot-label">Primary route :7860</span> | |
| <span class="boot-status s-wait" id="route-status">PENDING</span> | |
| </div> | |
| </div> | |
| <!-- Progress bar --> | |
| <div class="progress-wrap"> | |
| <div class="progress-fill"></div> | |
| <div class="progress-shimmer"></div> | |
| </div> | |
| <!-- CTA --> | |
| <a href="/" class="btn" id="refresh-btn"> | |
| <span class="btn-icon">↻</span> | |
| Retry Now | |
| </a> | |
| <!-- Footer --> | |
| <div class="footer"> | |
| <span class="dot-live"></span> | |
| <span id="poll-label">polling every 2s</span> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| /* ── Particle canvas ── */ | |
| (function () { | |
| const canvas = document.getElementById('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| let W, H, particles; | |
| function resize() { | |
| W = canvas.width = window.innerWidth; | |
| H = canvas.height = window.innerHeight; | |
| } | |
| function mkParticle() { | |
| return { | |
| x: Math.random() * W, | |
| y: Math.random() * H, | |
| r: Math.random() * 1.4 + 0.3, | |
| vx: (Math.random() - 0.5) * 0.18, | |
| vy: (Math.random() - 0.5) * 0.18, | |
| a: Math.random(), | |
| da: (Math.random() * 0.004 + 0.001) * (Math.random() < 0.5 ? 1 : -1), | |
| }; | |
| } | |
| function init() { | |
| resize(); | |
| const N = Math.floor((W * H) / 8000); | |
| particles = Array.from({ length: N }, mkParticle); | |
| } | |
| function frame() { | |
| ctx.clearRect(0, 0, W, H); | |
| for (const p of particles) { | |
| p.x += p.vx; p.y += p.vy; p.a += p.da; | |
| if (p.x < 0) p.x = W; if (p.x > W) p.x = 0; | |
| if (p.y < 0) p.y = H; if (p.y > H) p.y = 0; | |
| if (p.a < 0 || p.a > 1) p.da *= -1; | |
| ctx.beginPath(); | |
| ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); | |
| ctx.fillStyle = `rgba(139,92,246,${p.a * 0.7})`; | |
| ctx.fill(); | |
| } | |
| requestAnimationFrame(frame); | |
| } | |
| window.addEventListener('resize', () => { resize(); }); | |
| init(); | |
| frame(); | |
| })(); | |
| /* ── Status polling ── */ | |
| let attempts = 0; | |
| const routeStatus = document.getElementById('route-status'); | |
| const pollLabel = document.getElementById('poll-label'); | |
| async function checkStatus() { | |
| attempts++; | |
| pollLabel.textContent = `attempt ${attempts} · polling every 2s`; | |
| try { | |
| const res = await fetch('/?_t=' + Date.now(), { cache: 'no-store' }); | |
| if (res.status !== 502 && res.status !== 503 && res.status !== 504) { | |
| routeStatus.textContent = 'READY'; | |
| routeStatus.className = 'boot-status s-ok'; | |
| pollLabel.textContent = 'redirecting…'; | |
| setTimeout(() => window.location.reload(), 300); | |
| } | |
| } catch (_) { /* network not yet up, keep polling */ } | |
| } | |
| setTimeout(checkStatus, 600); | |
| setInterval(checkStatus, 2000); | |
| </script> | |
| </body> | |
| </html> |