Spaces:
Running
Running
| <html lang="en" data-theme="dark"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Project Prism</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> | |
| <style> | |
| /* ============ TOKENS ============ */ | |
| :root{ | |
| --bg:#05060a; | |
| --bg-2:#0b0d15; | |
| --text:#f2f3f7; | |
| --text-2:#a8adbf; | |
| --text-3:#6b7186; | |
| --glass:rgba(255,255,255,.06); | |
| --glass-2:rgba(255,255,255,.10); | |
| --glass-border:rgba(255,255,255,.12); | |
| --glass-border-2:rgba(255,255,255,.22); | |
| --accent:#8b7cff; | |
| --accent-2:#5ee7ff; | |
| --accent-3:#ff6ad5; | |
| --shadow:0 20px 60px rgba(0,0,0,.55); | |
| --ease:cubic-bezier(.4,0,.2,1); | |
| --spring:cubic-bezier(.34,1.56,.64,1); | |
| --effort-color:#a97bff; | |
| --effort-color-2:#5ee7ff; | |
| --effort-rgb:169,123,255; | |
| } | |
| [data-theme="light"]{ | |
| --bg:#eef0f7; | |
| --bg-2:#e2e5f0; | |
| --text:#101322; | |
| --text-2:#4a4f63; | |
| --text-3:#8a8fa3; | |
| --glass:rgba(255,255,255,.55); | |
| --glass-2:rgba(255,255,255,.75); | |
| --glass-border:rgba(0,0,0,.08); | |
| --glass-border-2:rgba(0,0,0,.16); | |
| --shadow:0 20px 60px rgba(30,40,90,.15); | |
| } | |
| *{box-sizing:border-box;margin:0;padding:0} | |
| html,body{height:100%} | |
| body{ | |
| font-family:'Inter',system-ui,sans-serif; | |
| background:var(--bg); | |
| color:var(--text); | |
| overflow:hidden; | |
| transition:background .5s var(--ease),color .5s var(--ease); | |
| -webkit-font-smoothing:antialiased; | |
| } | |
| button{font:inherit;color:inherit;background:none;border:0;cursor:pointer} | |
| /* ambient background blobs */ | |
| .ambient{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;opacity:0;transition:opacity 1.2s var(--ease)} | |
| .ambient.on{opacity:1} | |
| .blob{position:absolute;border-radius:50%;filter:blur(90px);opacity:.35;animation:drift 22s ease-in-out infinite alternate} | |
| .blob.a{width:55vw;height:55vw;background:var(--accent);top:-20%;left:-15%} | |
| .blob.b{width:45vw;height:45vw;background:var(--accent-2);bottom:-20%;right:-10%;animation-delay:-8s} | |
| .blob.c{width:35vw;height:35vw;background:var(--accent-3);top:40%;left:45%;animation-delay:-14s;opacity:.2} | |
| [data-theme="light"] .blob{opacity:.25} | |
| @keyframes drift{ | |
| 0%{transform:translate(0,0) scale(1) rotate(0deg)} | |
| 50%{transform:translate(3vw,-2vh) scale(1.08) rotate(4deg)} | |
| 100%{transform:translate(6vw,-5vh) scale(1.15) rotate(-3deg)} | |
| } | |
| @keyframes breathe{0%,100%{filter:blur(90px) saturate(110%)}50%{filter:blur(105px) saturate(150%)}} | |
| .ambient.on .blob{animation-name:drift,breathe;animation-duration:22s,8s;animation-timing-function:ease-in-out,ease-in-out;animation-iteration-count:infinite,infinite;animation-direction:alternate,normal} | |
| /* glass utility */ | |
| .glass{ | |
| background:var(--glass); | |
| border:1px solid var(--glass-border); | |
| backdrop-filter:blur(28px) saturate(160%); | |
| -webkit-backdrop-filter:blur(28px) saturate(160%); | |
| box-shadow:var(--shadow), inset 0 1px 0 rgba(255,255,255,.08); | |
| } | |
| /* ============ SCREENS ============ */ | |
| .screen{position:fixed;inset:0;z-index:1;display:none;opacity:0;transition:opacity .6s var(--ease)} | |
| .screen.active{display:flex} | |
| .screen.show{opacity:1} | |
| /* ---- Splash ---- */ | |
| #splash{align-items:center;justify-content:center;background:#000;z-index:50; | |
| transition:transform .9s cubic-bezier(.7,0,.3,1),opacity .6s} | |
| #splash.slide-up{transform:translateY(-100%)} | |
| .splash-title{ | |
| font-weight:800;font-size:clamp(40px,7vw,96px);letter-spacing:-.03em;text-align:center;line-height:1.05; | |
| animation:titleIn 1.1s var(--ease) both; | |
| } | |
| .splash-title small{display:block;font-size:.28em;font-weight:400;letter-spacing:.35em;text-transform:uppercase;color:var(--text-3);margin-bottom:.4em} | |
| .splash-title .prism{ | |
| background:linear-gradient(90deg,#ff6ad5,#8b7cff,#5ee7ff,#8b7cff,#ff6ad5); | |
| background-size:300% 100%; | |
| -webkit-background-clip:text;background-clip:text;color:transparent; | |
| animation:shimmer 3s linear infinite; | |
| } | |
| @keyframes titleIn{from{opacity:0;transform:translateY(20px) scale(.97);filter:blur(10px)}to{opacity:1;transform:none;filter:none}} | |
| @keyframes shimmer{to{background-position:300% 0}} | |
| /* ---- Auth ---- */ | |
| #auth{align-items:center;justify-content:center;padding:24px} | |
| .auth-card{ | |
| width:min(520px,100%);padding:56px 44px;border-radius:28px;text-align:center; | |
| transform:translateY(20px);opacity:0;transition:all .9s var(--ease) | |
| } | |
| #auth.show .auth-card{transform:none;opacity:1;animation:authFloat 6s 1s ease-in-out infinite} | |
| @keyframes authFloat{0%,100%{translate:0 0}50%{translate:0 -5px}} | |
| .auth-card h1{font-size:30px;font-weight:700;letter-spacing:-.02em;margin-bottom:12px} | |
| .auth-card p{color:var(--text-2);line-height:1.6;font-size:15px;margin-bottom:36px} | |
| .auth-card p code{background:var(--glass-2);padding:2px 8px;border-radius:6px;font-family:ui-monospace,monospace;font-size:13px;color:var(--text)} | |
| .btn-hf{ | |
| display:inline-flex;align-items:center;gap:12px;padding:14px 26px;border-radius:14px;font-weight:600;font-size:15px; | |
| background:linear-gradient(135deg,#ffd21e,#ff9d00);color:#1a1200; | |
| box-shadow:0 10px 30px rgba(255,180,0,.25);transition:transform .25s var(--spring),box-shadow .25s | |
| } | |
| .btn-hf:hover{transform:translateY(-2px) scale(1.02);box-shadow:0 16px 40px rgba(255,180,0,.35)} | |
| .btn-hf:active{transform:scale(.98)} | |
| /* ---- Dashboard ---- */ | |
| #dash{flex-direction:column;align-items:center;padding:0 40px 40px} | |
| .prism-stage{position:relative;height:38vh;min-height:220px;width:100%;display:flex;align-items:center;justify-content:center;flex:none} | |
| .prism-stage svg{height:100%;max-height:300px;overflow:visible} | |
| .beam-in{stroke:#fff;stroke-width:3;stroke-linecap:round;stroke-dasharray:260;stroke-dashoffset:260;animation:beam 1.2s .3s var(--ease) forwards;filter:drop-shadow(0 0 6px #fff)} | |
| .beam-out{stroke-width:3;stroke-linecap:round;stroke-dasharray:300;stroke-dashoffset:300;opacity:.95;animation:beam 1.1s var(--ease) forwards} | |
| .beam-out:nth-child(1){animation-delay:1.25s} | |
| .beam-out:nth-child(2){animation-delay:1.32s} | |
| .beam-out:nth-child(3){animation-delay:1.39s} | |
| .beam-out:nth-child(4){animation-delay:1.46s} | |
| .beam-out:nth-child(5){animation-delay:1.53s} | |
| .beam-out:nth-child(6){animation-delay:1.6s} | |
| @keyframes beam{to{stroke-dashoffset:0}} | |
| .prism-body{fill:url(#prismFill);stroke:rgba(255,255,255,.5);stroke-width:1.5;opacity:0;animation:fadeIn .8s .1s forwards} | |
| .prism-glow{opacity:0;animation:fadeIn 1s 1.3s forwards,prismBreathe 4s 2.2s ease-in-out infinite} | |
| @keyframes prismBreathe{0%,100%{transform:scale(.96);filter:blur(28px)}50%{transform:scale(1.12);filter:blur(36px)}} | |
| @keyframes fadeIn{to{opacity:1}} | |
| .dash-content{width:min(1180px,100%);opacity:0;transform:translateY(24px);transition:all .9s .1s var(--ease)} | |
| #dash.reveal .dash-content{opacity:1;transform:none} | |
| #dash.reveal .card{animation:dashCardIn .72s both var(--spring)} | |
| #dash.reveal .card:nth-child(1){animation-delay:.08s} | |
| #dash.reveal .card:nth-child(2){animation-delay:.16s} | |
| #dash.reveal .card:nth-child(3){animation-delay:.24s} | |
| @keyframes dashCardIn{from{opacity:0;transform:translateY(22px) scale(.965);filter:blur(8px)}to{opacity:1;transform:none;filter:none}} | |
| .dash-head{text-align:center;margin-bottom:36px} | |
| .dash-head h1{font-size:clamp(30px,4vw,48px);font-weight:800;letter-spacing:-.03em} | |
| .dash-head h1 span{background:linear-gradient(90deg,var(--accent),var(--accent-2));-webkit-background-clip:text;background-clip:text;color:transparent} | |
| .dash-head p{color:var(--text-2);margin-top:8px} | |
| .dash-grid{display:grid;grid-template-columns:1.3fr 1fr .9fr;gap:20px} | |
| @media (max-width:900px){.dash-grid{grid-template-columns:1fr}} | |
| .card{border-radius:24px;padding:26px;transition:transform .35s var(--ease),border-color .35s} | |
| .card:hover{transform:translateY(-3px);border-color:var(--glass-border-2)} | |
| .card h3{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);font-weight:600;margin-bottom:18px} | |
| .news-item{padding:14px 0;border-top:1px solid var(--glass-border);display:flex;gap:14px;align-items:flex-start} | |
| .news-item:first-of-type{border-top:0;padding-top:0} | |
| .news-dot{width:8px;height:8px;border-radius:50%;margin-top:6px;flex:none;background:var(--accent)} | |
| .news-item:nth-child(3) .news-dot{background:var(--accent-2)} | |
| .news-item:nth-child(4) .news-dot{background:var(--accent-3)} | |
| .news-item b{display:block;font-weight:600;font-size:15px;margin-bottom:3px} | |
| .news-item span{color:var(--text-2);font-size:13.5px;line-height:1.5} | |
| .news-item time{margin-left:auto;font-size:12px;color:var(--text-3);white-space:nowrap} | |
| .enter-card{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:20px} | |
| .enter-card p{color:var(--text-2);font-size:14.5px;max-width:260px;line-height:1.5} | |
| .enter-card h2{font-size:24px;font-weight:700;letter-spacing:-.02em} | |
| .btn-enter{ | |
| display:flex;align-items:center;gap:12px;padding:16px 28px;border-radius:999px;font-weight:600;font-size:16px; | |
| background:linear-gradient(135deg,var(--accent),var(--accent-2));color:#fff; | |
| box-shadow:0 12px 34px rgba(139,124,255,.35);transition:transform .3s var(--spring),box-shadow .3s | |
| } | |
| .btn-enter:hover{transform:translateY(-2px) scale(1.03);box-shadow:0 18px 44px rgba(139,124,255,.5)} | |
| .btn-enter .arrow{transition:transform .3s} | |
| .btn-enter:hover .arrow{transform:translateX(4px)} | |
| .usage-card{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center} | |
| .ring{position:relative;width:170px;height:170px} | |
| .ring svg{width:100%;height:100%;transform:rotate(-90deg)} | |
| .ring .track{fill:none;stroke:var(--glass-2);stroke-width:12} | |
| .ring .fill{fill:none;stroke:url(#ringGrad);stroke-width:12;stroke-linecap:round;stroke-dasharray:440;stroke-dashoffset:440;transition:stroke-dashoffset 1.6s .4s var(--ease)} | |
| #dash.reveal .ring .fill{stroke-dashoffset:calc(440 - 440 * .97)} | |
| .ring .num{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center} | |
| .ring .num b{font-size:40px;font-weight:800;letter-spacing:-.04em} | |
| .ring .num span{font-size:12px;color:var(--text-3)} | |
| .usage-card small{margin-top:16px;color:var(--text-2);font-size:13px} | |
| /* ---- Chat ---- */ | |
| #chat{ | |
| flex-direction:row; | |
| --effort-color:#a97bff; | |
| --effort-color-2:#5ee7ff; | |
| --effort-rgb:169,123,255; | |
| } | |
| #chat .chat-main{isolation:isolate} | |
| #chat .chat-main::before{ | |
| content:"";position:absolute;inset:-18%;z-index:-2;pointer-events:none; | |
| background: | |
| radial-gradient(circle at 72% 18%,rgba(var(--effort-rgb),.17),transparent 30%), | |
| radial-gradient(circle at 30% 72%,rgba(var(--effort-rgb),.10),transparent 32%); | |
| filter:blur(18px);opacity:.9;transition:background .65s var(--ease),opacity .65s var(--ease); | |
| } | |
| #chat .chat-main::after{ | |
| content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:.18; | |
| background:linear-gradient(115deg,transparent 0 42%,rgba(var(--effort-rgb),.10) 49%,transparent 56%); | |
| background-size:220% 100%;animation:chatSheen 9s linear infinite; | |
| } | |
| @keyframes chatSheen{to{background-position:-220% 0}} | |
| @keyframes effortFlash{0%{opacity:.35;transform:scale(.985)}55%{opacity:1;transform:scale(1.015)}100%{opacity:.9;transform:none}} | |
| #chat.effort-shift .chat-main::before{animation:effortFlash .55s var(--spring)} | |
| #chat.show .topbar{animation:topbarIn .65s .05s both var(--ease)} | |
| #chat.show .sidebar{animation:sidebarIn .7s .08s both var(--ease)} | |
| #chat.show .chat-body>*{animation:chatItemIn .7s both var(--spring)} | |
| #chat.show .chat-body>*:nth-child(1){animation-delay:.08s} | |
| #chat.show .chat-body>*:nth-child(2){animation-delay:.14s} | |
| #chat.show .chat-body>*:nth-child(3){animation-delay:.20s} | |
| #chat.show .chat-body>*:nth-child(4){animation-delay:.26s} | |
| #chat.show .composer-wrap{animation:composerIn .75s .18s both var(--spring)} | |
| @keyframes topbarIn{from{opacity:0;transform:translateY(-14px);filter:blur(6px)}to{opacity:1;transform:none;filter:none}} | |
| @keyframes sidebarIn{from{opacity:0;transform:translateX(-18px);filter:blur(6px)}to{opacity:1;transform:none;filter:none}} | |
| @keyframes chatItemIn{from{opacity:0;transform:translateY(18px) scale(.97);filter:blur(8px)}to{opacity:1;transform:none;filter:none}} | |
| @keyframes composerIn{from{opacity:0;transform:translateY(28px) scale(.97)}to{opacity:1;transform:none}} | |
| .sidebar{ | |
| width:280px;flex:none;height:100%;padding:20px 16px;display:flex;flex-direction:column;gap:8px; | |
| border-right:1px solid var(--glass-border);transition:margin .45s var(--ease),opacity .4s,border-color .45s,box-shadow .45s; | |
| box-shadow:inset -1px 0 rgba(var(--effort-rgb),.04) | |
| } | |
| .sidebar.collapsed{margin-left:-280px;opacity:0} | |
| .sidebar .logo{display:flex;align-items:center;gap:10px;padding:8px 10px 20px;font-weight:700;letter-spacing:-.01em} | |
| .logo-gem{width:26px;height:26px;border-radius:8px;background:linear-gradient(135deg,var(--accent-3),var(--accent),var(--accent-2))} | |
| .btn-new{display:flex;align-items:center;gap:10px;padding:12px 14px;border-radius:14px;background:var(--glass-2);border:1px solid var(--glass-border);font-weight:500;transition:.25s} | |
| .btn-new:hover{border-color:var(--glass-border-2)} | |
| .sb-label{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);padding:18px 10px 6px;font-weight:600} | |
| .sb-item{padding:10px 12px;border-radius:12px;font-size:14px;color:var(--text-2);text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:.2s} | |
| .sb-item:hover{background:var(--glass);color:var(--text);transform:translateX(4px)} | |
| .sb-item.on{background:var(--glass-2);color:var(--text);box-shadow:inset 3px 0 0 var(--effort-color)} | |
| #chat .btn-new:hover{transform:translateY(-1px);box-shadow:0 8px 24px rgba(var(--effort-rgb),.12)} | |
| .sb-foot{margin-top:auto;display:flex;align-items:center;gap:10px;padding:10px;border-radius:14px;font-size:14px} | |
| .avatar{width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#ffd21e,#ff6ad5);flex:none} | |
| .chat-main{flex:1;display:flex;flex-direction:column;min-width:0;position:relative} | |
| .topbar{display:flex;align-items:center;gap:12px;padding:16px 22px} | |
| .icon-btn{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;color:var(--text-2);transition:.25s} | |
| .icon-btn:hover{background:var(--glass);color:var(--text)} | |
| .icon-btn svg{width:20px;height:20px} | |
| .pill{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:999px;font-size:14px;font-weight:500;transition:.25s;position:relative} | |
| .pill:hover{border-color:var(--glass-border-2)} | |
| .pill .chev{transition:transform .3s} | |
| .pill.open .chev{transform:rotate(180deg)} | |
| .mini-ring{width:22px;height:22px;position:relative} | |
| .mini-ring svg{transform:rotate(-90deg);width:100%;height:100%} | |
| .mini-ring circle{fill:none;stroke-width:3} | |
| .mini-ring .t{stroke:var(--glass-2)} | |
| .mini-ring .f{stroke:var(--effort-color);stroke-dasharray:56.5;stroke-dashoffset:calc(56.5*.03);stroke-linecap:round;transition:stroke .5s var(--ease)} | |
| #chat .pill{transition:transform .25s var(--spring),border-color .35s,box-shadow .35s,background .35s} | |
| #chat .pill:hover{transform:translateY(-1px);box-shadow:0 10px 30px rgba(var(--effort-rgb),.10)} | |
| #chat .dd-item.selected{box-shadow:inset 0 0 0 1px rgba(var(--effort-rgb),.45),0 8px 24px rgba(var(--effort-rgb),.08)} | |
| #chat .dd-check{color:var(--effort-color)} | |
| .spacer{flex:1} | |
| /* theme toggle */ | |
| .theme-toggle{width:64px;height:34px;border-radius:999px;position:relative;padding:3px;transition:.3s} | |
| .theme-toggle .knob{width:26px;height:26px;border-radius:50%;background:linear-gradient(135deg,var(--accent),var(--accent-2));display:grid;place-items:center;transition:transform .45s var(--spring)} | |
| [data-theme="light"] .theme-toggle .knob{transform:translateX(30px);background:linear-gradient(135deg,#ffd21e,#ff9d00)} | |
| .theme-toggle svg{width:14px;height:14px;color:#fff} | |
| .theme-toggle .sun{display:none} | |
| [data-theme="light"] .theme-toggle .sun{display:block} | |
| [data-theme="light"] .theme-toggle .moon{display:none} | |
| /* dropdown */ | |
| .dropdown{ | |
| position:absolute;top:calc(100% + 10px);left:0;width:380px;border-radius:20px;padding:8px;z-index:20; | |
| opacity:0;transform:translateY(-8px) scale(.98);pointer-events:none;transition:all .3s var(--spring);transform-origin:top left | |
| } | |
| .dropdown.open{opacity:1;transform:none;pointer-events:auto} | |
| .dd-item{display:flex;flex-direction:column;gap:6px;padding:14px 16px;border-radius:14px;text-align:left;width:100%;transition:.2s;position:relative} | |
| .dd-item + .dd-item{margin-top:4px} | |
| .dd-item:hover{background:var(--glass-2)} | |
| .dd-item.selected{background:var(--glass-2);box-shadow:inset 0 0 0 1px var(--glass-border-2)} | |
| .dd-item.disabled{opacity:.5;cursor:not-allowed} | |
| .dd-item.disabled:hover{background:none} | |
| .dd-title{display:flex;align-items:center;gap:8px;font-weight:600;font-size:15px} | |
| .dd-tag{font-size:10.5px;padding:3px 8px;border-radius:999px;background:linear-gradient(135deg,var(--accent-3),var(--accent));color:#fff;font-weight:600;letter-spacing:.04em;text-transform:uppercase} | |
| .dd-tag.soon{background:var(--glass-2);color:var(--text-2)} | |
| .dd-row{display:flex;gap:12px;align-items:flex-start} | |
| .dd-icons{display:flex;gap:6px;flex:none} | |
| .dd-icons span{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;background:var(--glass-2);border:1px solid var(--glass-border);color:var(--text-2)} | |
| .dd-icons svg{width:15px;height:15px} | |
| .dd-desc{font-size:13px;color:var(--text-2);line-height:1.5;font-weight:400} | |
| .dd-check{position:absolute;right:14px;top:14px;color:var(--accent-2);opacity:0} | |
| .dd-item.selected .dd-check{opacity:1} | |
| /* chat body */ | |
| .chat-body{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:24px} | |
| .hero-gem{ | |
| width:64px;height:64px;border-radius:20px;margin-bottom:24px;position:relative; | |
| background:linear-gradient(135deg,var(--effort-color-2),var(--effort-color)); | |
| box-shadow:0 20px 60px rgba(var(--effort-rgb),.4),inset 0 1px 1px rgba(255,255,255,.35); | |
| animation:floaty 5s ease-in-out infinite;transition:background .6s var(--ease),box-shadow .6s var(--ease) | |
| } | |
| .hero-gem::before,.hero-gem::after{content:"";position:absolute;border-radius:inherit;pointer-events:none} | |
| .hero-gem::before{inset:-10px;border:1px solid rgba(var(--effort-rgb),.28);animation:gemPulse 2.8s ease-in-out infinite} | |
| .hero-gem::after{inset:7px;background:linear-gradient(145deg,rgba(255,255,255,.34),transparent 48%);filter:blur(.2px)} | |
| @keyframes floaty{0%,100%{transform:translateY(0) rotate(-3deg)}50%{transform:translateY(-10px) rotate(3deg)}} | |
| @keyframes gemPulse{0%,100%{transform:scale(.92) rotate(0);opacity:.15}50%{transform:scale(1.24) rotate(12deg);opacity:.65}} | |
| .chat-body h1{font-size:clamp(28px,3.4vw,42px);font-weight:800;letter-spacing:-.03em} | |
| .chat-body h1 span{background:linear-gradient(90deg,var(--effort-color-2),var(--effort-color),var(--effort-color-2));background-size:220% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;animation:titleFlow 4s linear infinite;transition:filter .5s} | |
| @keyframes titleFlow{to{background-position:220% 0}} | |
| .chat-body p{color:var(--text-2);margin-top:10px;font-size:16px} | |
| .suggest{display:flex;gap:10px;margin-top:30px;flex-wrap:wrap;justify-content:center} | |
| .suggest button{padding:10px 16px;border-radius:999px;font-size:13.5px;color:var(--text-2);transition:.25s} | |
| .suggest button{position:relative;overflow:hidden} | |
| .suggest button::after{content:"";position:absolute;inset:-2px;transform:translateX(-130%) skewX(-20deg);background:linear-gradient(90deg,transparent,rgba(var(--effort-rgb),.16),transparent);transition:transform .65s var(--ease)} | |
| .suggest button:hover{color:var(--text);border-color:rgba(var(--effort-rgb),.42);transform:translateY(-3px);box-shadow:0 10px 28px rgba(var(--effort-rgb),.10)} | |
| .suggest button:hover::after{transform:translateX(130%) skewX(-20deg)} | |
| /* composer */ | |
| .composer-wrap{padding:0 22px 22px;display:flex;justify-content:center} | |
| .composer{width:min(860px,100%);border-radius:24px;padding:10px 10px 10px 12px;display:flex;align-items:flex-end;gap:10px;position:relative;transition:border-color .4s,box-shadow .4s,transform .35s var(--spring),background .4s;overflow:visible} | |
| .composer::before{content:"";position:absolute;inset:-1px;border-radius:inherit;pointer-events:none;opacity:.22;background:linear-gradient(100deg,transparent 15%,rgba(var(--effort-rgb),.55),transparent 85%);mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);padding:1px;-webkit-mask-composite:xor;mask-composite:exclude;transition:opacity .35s} | |
| .composer:focus-within{border-color:rgba(var(--effort-rgb),.48);box-shadow:var(--shadow),0 0 0 4px rgba(var(--effort-rgb),.11),0 0 44px rgba(var(--effort-rgb),.12);transform:translateY(-2px)} | |
| .composer:focus-within::before{opacity:.8} | |
| .composer textarea{flex:1;background:none;border:0;outline:0;resize:none;color:var(--text);font:inherit;font-size:15.5px;line-height:1.5;padding:10px 6px;max-height:200px;min-height:44px} | |
| .composer textarea::placeholder{color:var(--text-3)} | |
| .plus-btn{width:42px;height:42px;border-radius:14px;display:grid;place-items:center;color:var(--text-2);transition:.25s;flex:none;position:relative} | |
| .plus-btn:hover{background:var(--glass-2);color:var(--text)} | |
| .plus-btn svg{width:20px;height:20px;transition:transform .3s var(--spring)} | |
| .plus-btn:hover svg{transform:rotate(90deg)} | |
| .plus-btn .tip{position:absolute;bottom:calc(100% + 8px);left:0;font-size:12px;padding:5px 9px;border-radius:8px;white-space:nowrap;opacity:0;transition:.2s;pointer-events:none} | |
| .plus-btn:hover .tip{opacity:1} | |
| .effort-chip{padding:10px 14px;border-radius:999px;font-size:13px;font-weight:600;display:flex;align-items:center;gap:8px;flex:none;transition:.25s;position:relative;height:42px} | |
| .effort-chip:hover{border-color:var(--glass-border-2)} | |
| .effort-chip .dot{width:8px;height:8px;border-radius:50%;background:var(--effort-color,var(--accent));box-shadow:0 0 10px var(--effort-color,var(--accent));animation:effortDot 1.9s ease-in-out infinite} | |
| @keyframes effortDot{50%{transform:scale(1.35);box-shadow:0 0 18px var(--effort-color,var(--accent))}} | |
| #chat .effort-chip{border-color:rgba(var(--effort-rgb),.20);box-shadow:0 5px 18px rgba(var(--effort-rgb),.06)} | |
| .send-btn{width:42px;height:42px;border-radius:14px;display:grid;place-items:center;flex:none;background:linear-gradient(135deg,var(--effort-color),var(--effort-color-2));color:#fff;box-shadow:0 8px 22px rgba(var(--effort-rgb),.34);transition:transform .25s var(--spring),box-shadow .35s,background .5s var(--ease);position:relative;overflow:hidden} | |
| .send-btn::after{content:"";position:absolute;inset:-40%;background:conic-gradient(from 0deg,transparent,rgba(255,255,255,.32),transparent 25%);animation:sendSpin 3s linear infinite;opacity:.45} | |
| .send-btn svg{position:relative;z-index:1} | |
| @keyframes sendSpin{to{transform:rotate(360deg)}} | |
| .send-btn:hover{transform:translateY(-3px) scale(1.07);box-shadow:0 14px 34px rgba(var(--effort-rgb),.48)} | |
| .send-btn:active{transform:scale(.95)} | |
| .send-btn svg{width:20px;height:20px} | |
| /* effort meter popover */ | |
| .effort-pop{ | |
| position:absolute;bottom:calc(100% + 14px);right:0;width:340px;border-radius:24px;padding:22px 22px 18px;z-index:20; | |
| opacity:0;transform:translateY(10px) scale(.97);pointer-events:none;transition:all .3s var(--spring);transform-origin:bottom right;text-align:center | |
| } | |
| .effort-pop.open{opacity:1;transform:none;pointer-events:auto} | |
| .effort-pop h4{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);font-weight:600;margin-bottom:4px} | |
| .gauge{width:100%;touch-action:none;cursor:grab;user-select:none} | |
| .gauge:active{cursor:grabbing} | |
| .gauge .arc-track{fill:none;stroke:var(--glass-2);stroke-width:14;stroke-linecap:round} | |
| .gauge .arc-fill{fill:none;stroke:var(--effort-color);stroke-width:14;stroke-linecap:round;transition:stroke-dashoffset .12s linear,stroke .45s var(--ease);filter:drop-shadow(0 0 6px rgba(var(--effort-rgb),.38))} | |
| .gauge .tick{stroke:var(--text-3);stroke-width:2;stroke-linecap:round} | |
| .gauge .tick.on{stroke:var(--text)} | |
| .gauge .lbl{font-size:10px;fill:var(--text-3);font-weight:600;letter-spacing:.04em;text-anchor:middle;transition:.2s} | |
| .gauge .lbl.on{fill:var(--text);font-size:11px} | |
| .gauge .needle{stroke:var(--text);stroke-width:3.5;stroke-linecap:round;transform-origin:150px 150px;transition:transform .35s var(--spring);filter:drop-shadow(0 2px 4px rgba(0,0,0,.4))} | |
| .gauge.dragging .needle{transition:none} | |
| .gauge .hub{fill:var(--text)} | |
| .gauge .hub2{fill:var(--bg)} | |
| .effort-val{font-size:22px;font-weight:800;letter-spacing:-.02em;margin-top:-6px} | |
| .effort-val small{display:block;font-size:12.5px;color:var(--text-2);font-weight:400;margin-top:4px;min-height:18px} | |
| /* effort-reactive chat chrome */ | |
| #chat .logo-gem{background:linear-gradient(135deg,var(--effort-color-2),var(--effort-color));box-shadow:0 0 18px rgba(var(--effort-rgb),.18);transition:background .55s var(--ease),box-shadow .55s var(--ease)} | |
| #chat .effort-pop{border-color:rgba(var(--effort-rgb),.25);box-shadow:var(--shadow),0 18px 70px rgba(var(--effort-rgb),.16)} | |
| #chat .theme-toggle .knob{transition:transform .45s var(--spring),background .5s var(--ease),box-shadow .5s} | |
| #chat[data-effort="max"] .hero-gem{animation-duration:3.2s;box-shadow:0 20px 70px rgba(var(--effort-rgb),.55),0 0 70px rgba(var(--effort-rgb),.20)} | |
| #chat[data-effort="x-low"] .hero-gem{animation-duration:6s} | |
| #chat[data-effort="max"] .chat-main::after{animation-duration:4s;opacity:.3} | |
| #chat[data-effort="x-high"] .chat-main::after,#chat[data-effort="max"] .chat-main::after{background-size:160% 100%} | |
| @media (max-width:700px){ | |
| .dropdown{width:min(380px,calc(100vw - 28px))} | |
| .effort-pop{width:min(340px,calc(100vw - 28px));right:-54px} | |
| .topbar{padding:12px 12px;gap:7px} | |
| .composer-wrap{padding:0 12px 12px} | |
| } | |
| @media (prefers-reduced-motion:reduce){ | |
| *,*::before,*::after{animation-duration:.001ms;animation-iteration-count:1;scroll-behavior:auto} | |
| .blob,.hero-gem,.effort-chip .dot{animation:none} | |
| } | |
| /* transitions helpers */ | |
| .fade-out{opacity:0;transition:opacity .5s var(--ease)} | |
| </style> | |
| </head> | |
| <body> | |
| <!-- ambient backdrop --> | |
| <div class="ambient" id="ambient"> | |
| <div class="blob a"></div><div class="blob b"></div><div class="blob c"></div> | |
| </div> | |
| <!-- SVG defs --> | |
| <svg width="0" height="0" style="position:absolute"> | |
| <defs> | |
| <linearGradient id="ringGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#8b7cff"/><stop offset="1" stop-color="#5ee7ff"/></linearGradient> | |
| <linearGradient id="gaugeGrad" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#5ee7ff"/><stop offset=".5" stop-color="#8b7cff"/><stop offset="1" stop-color="#ff6ad5"/></linearGradient> | |
| <linearGradient id="prismFill" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="rgba(255,255,255,.35)"/><stop offset=".5" stop-color="rgba(255,255,255,.08)"/><stop offset="1" stop-color="rgba(255,255,255,.25)"/></linearGradient> | |
| </defs> | |
| </svg> | |
| <!-- ============ SPLASH ============ --> | |
| <section class="screen active show" id="splash"> | |
| <h1 class="splash-title"><small>Welcome to Project</small><span class="prism">PRISM</span></h1> | |
| </section> | |
| <!-- ============ AUTH ============ --> | |
| <section class="screen" id="auth"> | |
| <div class="auth-card glass"> | |
| <h1>Sign in with Hugging Face</h1> | |
| <p>Make sure you are a member of the<br><code>Project-Prism</code> organisation before continuing.</p> | |
| <button class="btn-hf" id="btnSignIn"> | |
| <span style="font-size:20px">🤗</span> Sign in with Hugging Face | |
| </button> | |
| </div> | |
| </section> | |
| <!-- ============ DASHBOARD ============ --> | |
| <section class="screen" id="dash"> | |
| <div class="prism-stage"> | |
| <svg viewBox="0 0 520 300" fill="none"> | |
| <!-- incoming white beam --> | |
| <line class="beam-in" x1="0" y1="185" x2="215" y2="150"/> | |
| <!-- outgoing spectrum --> | |
| <g> | |
| <line class="beam-out" x1="300" y1="140" x2="520" y2="70" stroke="#ff4d6d"/> | |
| <line class="beam-out" x1="300" y1="143" x2="520" y2="100" stroke="#ff9f43"/> | |
| <line class="beam-out" x1="300" y1="146" x2="520" y2="130" stroke="#ffd21e"/> | |
| <line class="beam-out" x1="300" y1="149" x2="520" y2="160" stroke="#4ade80"/> | |
| <line class="beam-out" x1="300" y1="152" x2="520" y2="190" stroke="#5ee7ff"/> | |
| <line class="beam-out" x1="300" y1="155" x2="520" y2="220" stroke="#8b7cff"/> | |
| </g> | |
| <ellipse class="prism-glow" cx="260" cy="160" rx="70" ry="60" fill="#8b7cff" opacity=".25" style="filter:blur(30px)"/> | |
| <!-- prism --> | |
| <polygon class="prism-body" points="260,40 340,240 180,240"/> | |
| <polygon class="prism-body" points="260,40 300,25 380,225 340,240" style="opacity:.6"/> | |
| <polygon class="prism-body" points="180,240 340,240 380,225 220,225" style="opacity:.4"/> | |
| </svg> | |
| </div> | |
| <div class="dash-content"> | |
| <div class="dash-head"> | |
| <h1>Welcome, <span id="username">Astra</span>!</h1> | |
| <p>Everything's ready. Let's refract something.</p> | |
| </div> | |
| <div class="dash-grid"> | |
| <div class="card glass"> | |
| <h3>News</h3> | |
| <div class="news-item"><i class="news-dot"></i><div><b>Orion Flagship v2.3 shipped</b><span>Better long-context reasoning and a 20% latency drop on research tasks.</span></div><time>2h</time></div> | |
| <div class="news-item"><i class="news-dot"></i><div><b>Effort meter is live</b><span>Dial in how hard the model thinks — from X-Low to Max.</span></div><time>1d</time></div> | |
| <div class="news-item"><i class="news-dot"></i><div><b>Prism Ultra is coming</b><span>The power model for all tasks enters private preview next month.</span></div><time>3d</time></div> | |
| <div class="news-item"><i class="news-dot"></i><div><b>File uploads in chat</b><span>Drop PDFs, images and code straight into the composer.</span></div><time>5d</time></div> | |
| </div> | |
| <div class="card glass enter-card"> | |
| <div> | |
| <h2>Enter the chat</h2> | |
| <p>Start a conversation with the current flagship model.</p> | |
| </div> | |
| <button class="btn-enter" id="btnEnter"> | |
| <span class="logo-gem" style="width:18px;height:18px;border-radius:5px"></span> | |
| Orion Flagship | |
| <svg class="arrow" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg> | |
| </button> | |
| </div> | |
| <div class="card glass usage-card"> | |
| <h3 style="align-self:flex-start">Usage remaining today</h3> | |
| <div class="ring"> | |
| <svg viewBox="0 0 160 160"><circle class="track" cx="80" cy="80" r="70"/><circle class="fill" cx="80" cy="80" r="70"/></svg> | |
| <div class="num"><b>97%</b><span>of daily quota</span></div> | |
| </div> | |
| <small>Resets in 14h 22m</small> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- ============ CHAT ============ --> | |
| <section class="screen" id="chat"> | |
| <aside class="sidebar glass" id="sidebar"> | |
| <div class="logo"><span class="logo-gem"></span> Prism</div> | |
| <button class="btn-new"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>New chat</button> | |
| <div class="sb-label">Today</div> | |
| <button class="sb-item on">Refraction index of borosilicate</button> | |
| <button class="sb-item">Summarize the Orion paper</button> | |
| <div class="sb-label">Yesterday</div> | |
| <button class="sb-item">Design tokens for glassmorphism</button> | |
| <button class="sb-item">Why is the sky blue, really</button> | |
| <button class="sb-item">Spectral decomposition notes</button> | |
| <div class="sb-foot glass"><span class="avatar"></span><div><div style="font-weight:600">Astra</div><div style="font-size:12px;color:var(--text-3)">Project-Prism</div></div></div> | |
| </aside> | |
| <div class="chat-main"> | |
| <header class="topbar"> | |
| <button class="icon-btn" id="btnSidebar" title="Toggle sidebar"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg> | |
| </button> | |
| <!-- model dropdown --> | |
| <div style="position:relative"> | |
| <button class="pill glass" id="modelPill"> | |
| <span class="logo-gem" style="width:16px;height:16px;border-radius:5px"></span> | |
| <span id="modelName">Orion Flagship</span> | |
| <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M6 9l6 6 6-6"/></svg> | |
| </button> | |
| <div class="dropdown glass" id="modelDropdown"> | |
| <button class="dd-item selected" data-model="Orion Flagship"> | |
| <div class="dd-title">Orion Flagship <span class="dd-tag">Flagship</span></div> | |
| <div class="dd-row"> | |
| <div class="dd-icons"> | |
| <span title="Reasoning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M9 18h6M10 21h4M12 3a6 6 0 0 0-4 10.5c.7.6 1 1.4 1 2.5h6c0-1.1.3-1.9 1-2.5A6 6 0 0 0 12 3z"/></svg></span> | |
| <span title="Long context"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8 8h8M8 12h8M8 16h5"/></svg></span> | |
| </div> | |
| <div class="dd-desc">Orion Flagship is a proprietary research model at Smilyai. Best for deep reasoning and long documents.</div> | |
| </div> | |
| <svg class="dd-check" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 7"/></svg> | |
| </button> | |
| <button class="dd-item" data-model="Orion Flagship Mini"> | |
| <div class="dd-title">Orion Flagship Mini</div> | |
| <div class="dd-desc">Faster variant of Orion. Snappy answers for everyday tasks.</div> | |
| <svg class="dd-check" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5L20 7"/></svg> | |
| </button> | |
| <button class="dd-item disabled" data-model="Prism Ultra" disabled> | |
| <div class="dd-title">Prism Ultra <span class="dd-tag soon">Coming soon</span></div> | |
| <div class="dd-desc">Power model for all tasks. The full spectrum.</div> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="pill glass" style="cursor:default"> | |
| <span style="color:var(--text-2)">Usage</span><b>97%</b> | |
| <span class="mini-ring"><svg viewBox="0 0 22 22"><circle class="t" cx="11" cy="11" r="9"/><circle class="f" cx="11" cy="11" r="9"/></svg></span> | |
| </div> | |
| <div class="spacer"></div> | |
| <button class="theme-toggle glass" id="themeToggle" title="Toggle theme"> | |
| <span class="knob"> | |
| <svg class="moon" viewBox="0 0 24 24" fill="currentColor"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg> | |
| <svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg> | |
| </span> | |
| </button> | |
| </header> | |
| <main class="chat-body"> | |
| <div class="hero-gem"></div> | |
| <h1>Welcome to the <span>Prism</span>!</h1> | |
| <p>Let's refract something.</p> | |
| <div class="suggest"> | |
| <button class="glass">Explain dispersion like I'm five</button> | |
| <button class="glass">Draft a research abstract</button> | |
| <button class="glass">Refactor this function</button> | |
| </div> | |
| </main> | |
| <div class="composer-wrap"> | |
| <div class="composer glass"> | |
| <button class="plus-btn" title="Attach files"> | |
| <span class="tip glass">Files</span> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg> | |
| </button> | |
| <textarea id="input" rows="1" placeholder="Let your mind wander…"></textarea> | |
| <!-- effort meter --> | |
| <button class="effort-chip glass" id="effortChip"><span class="dot"></span><span id="effortLabel">High</span></button> | |
| <div class="effort-pop glass" id="effortPop"> | |
| <h4>Effort meter</h4> | |
| <svg class="gauge" id="gauge" viewBox="0 0 300 175"> | |
| <path class="arc-track" d="M30 150 A120 120 0 0 1 270 150"/> | |
| <path class="arc-fill" id="arcFill" d="M30 150 A120 120 0 0 1 270 150"/> | |
| <g id="ticks"></g> | |
| <g id="labels"></g> | |
| <line class="needle" id="needle" x1="150" y1="150" x2="150" y2="48"/> | |
| <circle class="hub" cx="150" cy="150" r="10"/> | |
| <circle class="hub2" cx="150" cy="150" r="4"/> | |
| </svg> | |
| <div class="effort-val"><span id="effortBig">High</span><small id="effortDesc">Drag the needle</small></div> | |
| </div> | |
| <button class="send-btn" title="Send"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19V5M5 12l7-7 7 7"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <script> | |
| /* ============ SCREEN FLOW ============ */ | |
| const $ = s => document.querySelector(s); | |
| const screens = { splash:$('#splash'), auth:$('#auth'), dash:$('#dash'), chat:$('#chat') }; | |
| function showScreen(name, cb){ | |
| const el = screens[name]; | |
| el.classList.add('active'); | |
| requestAnimationFrame(()=>requestAnimationFrame(()=>{ el.classList.add('show'); cb && cb(); })); | |
| } | |
| function hideScreen(name, done){ | |
| const el = screens[name]; | |
| el.classList.remove('show'); | |
| setTimeout(()=>{ el.classList.remove('active'); done && done(); }, 650); | |
| } | |
| // Splash: hold 2s -> slide up -> black -> fade in auth | |
| setTimeout(()=>{ | |
| screens.splash.classList.add('slide-up'); | |
| setTimeout(()=>{ | |
| screens.splash.classList.remove('active','show'); | |
| setTimeout(()=>{ $('#ambient').classList.add('on'); showScreen('auth'); }, 500); | |
| }, 900); | |
| }, 2000); | |
| // Auth -> dashboard (prism animation, then content reveals) | |
| $('#btnSignIn').addEventListener('click', ()=>{ | |
| hideScreen('auth', ()=>{ | |
| showScreen('dash', ()=>{ | |
| setTimeout(()=> screens.dash.classList.add('reveal'), 1700); | |
| }); | |
| }); | |
| }); | |
| // Dashboard -> chat | |
| $('#btnEnter').addEventListener('click', ()=>{ | |
| hideScreen('dash', ()=> showScreen('chat')); | |
| }); | |
| /* ============ THEME ============ */ | |
| $('#themeToggle').addEventListener('click', ()=>{ | |
| const h = document.documentElement; | |
| h.dataset.theme = h.dataset.theme === 'dark' ? 'light' : 'dark'; | |
| }); | |
| /* ============ SIDEBAR ============ */ | |
| $('#btnSidebar').addEventListener('click', ()=> $('#sidebar').classList.toggle('collapsed')); | |
| /* ============ MODEL DROPDOWN ============ */ | |
| const pill = $('#modelPill'), dd = $('#modelDropdown'); | |
| pill.addEventListener('click', e=>{ e.stopPropagation(); pill.classList.toggle('open'); dd.classList.toggle('open'); closeEffort(); }); | |
| dd.querySelectorAll('.dd-item:not(.disabled)').forEach(item=>{ | |
| item.addEventListener('click', ()=>{ | |
| dd.querySelectorAll('.dd-item').forEach(i=>i.classList.remove('selected')); | |
| item.classList.add('selected'); | |
| $('#modelName').textContent = item.dataset.model; | |
| pill.classList.remove('open'); dd.classList.remove('open'); | |
| }); | |
| }); | |
| document.addEventListener('click', e=>{ | |
| if(!dd.contains(e.target)){ pill.classList.remove('open'); dd.classList.remove('open'); } | |
| if(!$('#effortPop').contains(e.target) && e.target!==$('#effortChip') && !$('#effortChip').contains(e.target)) closeEffort(); | |
| }); | |
| /* ============ EFFORT METER ============ */ | |
| const LEVELS = [ | |
| {n:'X-Low', d:'Blink-fast replies, minimal reasoning', c:'#5ee7ff', c2:'#67f5d2', rgb:'94,231,255'}, | |
| {n:'Low', d:'Quick answers for simple asks', c:'#55b8ff', c2:'#5ee7ff', rgb:'85,184,255'}, | |
| {n:'Medium', d:'Balanced speed and depth', c:'#7f8cff', c2:'#5ee7ff', rgb:'127,140,255'}, | |
| {n:'Med-High', d:'Powerful enough for complex tasks, with latency in mind', c:'#8b7cff', c2:'#7b9cff', rgb:'139,124,255'}, | |
| {n:'High', d:'Careful, thorough reasoning', c:'#a97bff', c2:'#8b7cff', rgb:'169,123,255'}, | |
| {n:'X-High', d:'Deep multi-step thinking', c:'#d56fe8', c2:'#a97bff', rgb:'213,111,232'}, | |
| {n:'Max', d:'Everything it has. Slow but brilliant', c:'#ff5fcb', c2:'#ff9b66', rgb:'255,95,203'}, | |
| ]; | |
| const gauge=$('#gauge'), needle=$('#needle'), arcFill=$('#arcFill'); | |
| const CX=150, CY=150, R=120; | |
| const ARC_LEN = Math.PI*R; // semicircle length | |
| arcFill.style.strokeDasharray = ARC_LEN; | |
| let level = 4; // High | |
| const pop=$('#effortPop'), chip=$('#effortChip'); | |
| // build ticks + labels | |
| const ticks=$('#ticks'), labels=$('#labels'); | |
| LEVELS.forEach((L,i)=>{ | |
| const a = Math.PI - (i/(LEVELS.length-1))*Math.PI; // rad, left=PI to right=0 | |
| const x1=CX+Math.cos(a)*(R+14), y1=CY-Math.sin(a)*(R+14); | |
| const x2=CX+Math.cos(a)*(R+22), y2=CY-Math.sin(a)*(R+22); | |
| const t=document.createElementNS('http://www.w3.org/2000/svg','line'); | |
| t.setAttribute('x1',x1);t.setAttribute('y1',y1);t.setAttribute('x2',x2);t.setAttribute('y2',y2);t.classList.add('tick');ticks.appendChild(t); | |
| const lx=CX+Math.cos(a)*(R+36), ly=CY-Math.sin(a)*(R+36)+4; | |
| const l=document.createElementNS('http://www.w3.org/2000/svg','text'); | |
| l.setAttribute('x',lx);l.setAttribute('y',ly);l.classList.add('lbl');l.textContent=L.n.toUpperCase();labels.appendChild(l); | |
| }); | |
| function setLevel(i, fromDrag){ | |
| level = Math.max(0, Math.min(LEVELS.length-1, i)); | |
| const L = LEVELS[level]; | |
| const frac = level/(LEVELS.length-1); | |
| needle.style.transform = `rotate(${-90 + frac*180}deg)`; | |
| arcFill.style.strokeDashoffset = ARC_LEN*(1-frac); | |
| $('#effortLabel').textContent = L.n; | |
| $('#effortBig').textContent = L.n; | |
| $('#effortDesc').textContent = L.d; | |
| chip.style.setProperty('--effort-color', L.c); | |
| // Re-theme the whole chat around the selected reasoning effort. | |
| const chat = $('#chat'); | |
| chat.style.setProperty('--effort-color', L.c); | |
| chat.style.setProperty('--effort-color-2', L.c2); | |
| chat.style.setProperty('--effort-rgb', L.rgb); | |
| chat.dataset.effort = L.n.toLowerCase().replace(/[^a-z0-9]+/g,'-'); | |
| // Tiny visual "thump" whenever the effort changes. | |
| chat.classList.remove('effort-shift'); | |
| void chat.offsetWidth; | |
| chat.classList.add('effort-shift'); | |
| clearTimeout(setLevel._fxTimer); | |
| setLevel._fxTimer = setTimeout(()=>chat.classList.remove('effort-shift'), 600); | |
| ticks.querySelectorAll('.tick').forEach((t,k)=>t.classList.toggle('on',k<=level)); | |
| labels.querySelectorAll('.lbl').forEach((l,k)=>l.classList.toggle('on',k===level)); | |
| } | |
| setLevel(level); | |
| chip.addEventListener('click', e=>{ e.stopPropagation(); pop.classList.toggle('open'); pill.classList.remove('open'); dd.classList.remove('open'); }); | |
| function closeEffort(){ pop.classList.remove('open'); } | |
| // drag | |
| let dragging=false; | |
| function angleToLevel(clientX, clientY){ | |
| const pt = gauge.createSVGPoint(); pt.x=clientX; pt.y=clientY; | |
| const p = pt.matrixTransform(gauge.getScreenCTM().inverse()); | |
| let a = Math.atan2(CY-p.y, p.x-CX); // 0..PI across top | |
| if(a<0) a = p.x<CX ? Math.PI : 0; | |
| const frac = 1 - a/Math.PI; | |
| return Math.round(frac*(LEVELS.length-1)); | |
| } | |
| gauge.addEventListener('pointerdown', e=>{ dragging=true; gauge.classList.add('dragging'); gauge.setPointerCapture(e.pointerId); setLevel(angleToLevel(e.clientX,e.clientY)); }); | |
| gauge.addEventListener('pointermove', e=>{ if(dragging) setLevel(angleToLevel(e.clientX,e.clientY)); }); | |
| ['pointerup','pointercancel'].forEach(ev=>gauge.addEventListener(ev, ()=>{ dragging=false; gauge.classList.remove('dragging'); })); | |
| /* ============ CHAT MICRO-INTERACTIONS ============ */ | |
| $('.suggest').querySelectorAll('button').forEach(btn=>{ | |
| btn.addEventListener('click', ()=>{ | |
| $('#input').value = btn.textContent.trim(); | |
| $('#input').dispatchEvent(new Event('input')); | |
| $('#input').focus(); | |
| }); | |
| }); | |
| $('.send-btn').addEventListener('click', ()=>{ | |
| const composer = document.querySelector('.composer'); | |
| composer.animate([ | |
| {transform:'translateY(-2px) scale(1)'}, | |
| {transform:'translateY(-2px) scale(.985)'}, | |
| {transform:'translateY(-2px) scale(1)'} | |
| ],{duration:280,easing:'cubic-bezier(.34,1.56,.64,1)'}); | |
| }); | |
| /* ============ TEXTAREA AUTOSIZE ============ */ | |
| const ta=$('#input'); | |
| ta.addEventListener('input', ()=>{ ta.style.height='auto'; ta.style.height=Math.min(ta.scrollHeight,200)+'px'; }); | |
| </script> | |
| </body> | |
| </html> |