InfinityGRM / static /index.html
afaceuser09's picture
Update static/index.html
4af7e95 verified
Raw
History Blame Contribute Delete
29.8 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Infinity GRM</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
html {
scroll-behavior: smooth;
}
body {
overflow-x: hidden;
background: #fff;
}
/* =========================
HEADER
========================= */
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 80px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 40px;
background: #fff;
z-index: 1000;
transition: background-color 0.3s ease;
}
header.dark {
background: #000;
}
.logo img {
height: 50px;
width: auto;
display: block;
}
.nav {
position: absolute;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 40px;
}
.nav a {
color: #000;
text-decoration: none;
font-weight: 600;
font-size: 15px;
transition: color 0.3s ease;
}
header.dark .nav a {
color: #fff;
}
/* =========================
ACCOUNT
========================= */
.account {
width: 48px;
height: 48px;
border-radius: 50%;
background: #000;
display: grid;
place-items: center;
text-decoration: none;
}
.account svg {
width: 23px;
height: 23px;
display: block;
fill: #fff;
}
header.dark .account {
background: #fff;
}
header.dark .account svg {
fill: #000;
}
/* =========================
MAIN
========================= */
main {
min-height: 100vh;
padding-top: 80px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
/* =========================
HOME
========================= */
.home {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
h1 {
font-size: 4rem;
margin-bottom: 30px;
}
/* =========================
INPUT BAR
========================= */
.input {
width: min(680px, 90%);
min-height: 68px;
position: relative;
display: flex;
align-items: center;
background: #fff;
border: 1px solid #d1d5db;
border-radius: 18px;
box-shadow:
0 5px 25px rgba(0, 0, 0, 0.05);
transition:
border-color 0.2s ease,
box-shadow 0.2s ease;
}
.input:focus-within {
border-color: #aaa;
box-shadow:
0 5px 25px rgba(0, 0, 0, 0.08);
}
/* =========================
TEXT INPUT
========================= */
.edit {
width: 100%;
min-height: 66px;
max-height: 180px;
padding:
18px
105px
18px
18px;
outline: none;
border: none;
overflow-y: auto;
overflow-x: hidden;
font-size: 16px;
line-height: 1.4;
color: #111;
cursor: text;
white-space: pre-wrap;
word-break: break-word;
/*
Makes the contenteditable behave
consistently after being cleared.
*/
caret-color: #000;
}
.edit:focus {
outline: none;
}
/* =========================
ASK ME ANYTHING PLACEHOLDER
========================= */
/*
Because this is contenteditable rather
than a normal input, we use ::before.
When the element is completely empty,
"Ask me anything..." appears.
Your JavaScript must clear the element
with innerHTML = "" after sending.
*/
.edit:empty::before {
content: attr(data-placeholder);
color: #aaa;
pointer-events: none;
user-select: none;
}
/*
Keep the placeholder visible when the
contenteditable receives focus.
*/
.edit:focus:empty::before {
color: #aaa;
}
/* =========================
BUTTON RESET
========================= */
button {
border: 0;
outline: 0;
background: transparent;
cursor: pointer;
padding: 0;
-webkit-appearance: none;
appearance: none;
}
/* =========================
MICROPHONE
========================= */
.voice {
position: absolute;
right: 52px;
bottom: 14px;
width: 38px;
height: 38px;
min-width: 38px;
min-height: 38px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #777;
background: transparent;
transition:
background-color 0.2s ease,
color 0.2s ease,
transform 0.15s ease;
}
.voice:hover {
background: #eee;
color: #333;
}
.voice:active {
transform: scale(0.94);
}
.voice.active {
background: #eee;
color: #000;
}
/* =========================
SEND / UP ARROW
========================= */
/*
INACTIVE STATE
This matches the gray circle from
your reference image.
It appears even when the input is empty.
*/
.send {
position: absolute;
right: 10px;
bottom: 14px;
width: 38px;
height: 38px;
min-width: 38px;
min-height: 38px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: #b3b3b3;
color: #fff;
transition:
background-color 0.2s ease,
color 0.2s ease,
transform 0.15s ease;
}
/*
INACTIVE HOVER
*/
.send:hover {
background: #a5a5a5;
color: #fff;
}
/*
CLICK
*/
.send:active {
transform: scale(0.94);
}
/*
ACTIVE STATE
JavaScript adds .active when the
user enters text.
*/
.send.active {
background: #000;
color: #fff;
}
/*
ACTIVE HOVER
*/
.send.active:hover {
background: #222;
color: #fff;
}
/* =========================
SVG ICONS
========================= */
.voice svg,
.send svg {
display: block;
width: 20px;
height: 20px;
min-width: 20px;
min-height: 20px;
max-width: 20px;
max-height: 20px;
flex-shrink: 0;
overflow: visible;
}
.voice svg {
width: 21px;
height: 21px;
min-width: 21px;
min-height: 21px;
max-width: 21px;
max-height: 21px;
}
.voice svg path,
.send svg path {
fill: none;
stroke: currentColor;
vector-effect: non-scaling-stroke;
}
/* =========================
MISSION BUTTON
========================= */
.mission-btn {
margin-top: 20px;
padding:
15px
35px;
border-radius: 50px;
background: #000;
color: #fff;
text-decoration: none;
font-weight: bold;
transition:
background-color 0.2s ease,
transform 0.2s ease;
}
.mission-btn:hover {
background: #222;
transform: translateY(-1px);
}
/* =========================
CHAT
========================= */
.chat {
display: none;
position: fixed;
top: 80px;
right: 0;
bottom: 0;
left: 0;
flex-direction: column;
background: #fff;
z-index: 500;
/*
Prevent the page itself from scrolling.
*/
overflow: hidden;
}
/* =========================
CHAT MESSAGES
========================= */
.messages {
flex: 1;
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
padding:
35px
20px
150px;
/*
Keep scrolling inside the messages
area instead of moving the webpage.
*/
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
.messages-inner {
max-width: 850px;
margin: 0 auto;
}
/* =========================
MESSAGE
========================= */
.message {
display: flex;
margin-bottom: 25px;
}
/* =========================
USER MESSAGE
========================= */
.user {
justify-content: flex-end;
}
.user div {
max-width: 70%;
background: #f1f1f1;
padding:
12px
17px;
border-radius:
20px
20px
6px
20px;
color: #111;
line-height: 1.5;
white-space: pre-wrap;
word-break: break-word;
}
/* =========================
AI MESSAGE
========================= */
.ai div {
max-width: 85%;
color: #111;
line-height: 1.7;
white-space: pre-wrap;
word-break: break-word;
}
/* =========================
CHAT BOTTOM INPUT
========================= */
.bottom {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
padding:
15px
20px
22px;
background:
linear-gradient(
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 0.95) 40%,
#fff 70%
);
z-index: 10;
}
/*
Keep the chat input white.
*/
.bottom .input {
width: min(680px, 100%);
background: #fff;
}
/*
The same gray inactive send button
applies to the chat input.
*/
.bottom .send {
background: #b3b3b3;
color: #fff;
}
.bottom .send:hover {
background: #a5a5a5;
color: #fff;
}
.bottom .send.active {
background: #000;
color: #fff;
}
.bottom .send.active:hover {
background: #222;
color: #fff;
}
/* =========================
MISSION
========================= */
#mission {
min-height: 100vh;
background: #000;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding:
100px
10%;
}
#mission h2 {
font-size: 4rem;
margin-bottom: 30px;
}
#mission p {
max-width: 900px;
font-size: 1.2rem;
line-height: 1.9;
}
/* =========================
MOBILE
========================= */
@media (max-width: 700px) {
header {
height: 70px;
padding:
0
15px;
}
.logo img {
height: 42px;
}
.nav {
gap: 15px;
}
.nav a {
font-size: 12px;
}
.account {
width: 42px;
height: 42px;
}
main {
padding-top: 70px;
}
h1 {
font-size: 2.5rem;
}
.input {
width: 92%;
min-height: 64px;
}
.edit {
min-height: 62px;
padding:
17px
105px
17px
16px;
}
.chat {
top: 70px;
}
.messages {
padding:
30px
15px
150px;
}
.user div {
max-width: 85%;
}
.ai div {
max-width: 92%;
}
#mission {
padding:
80px
8%;
}
#mission h2 {
font-size: 2.5rem;
}
#mission p {
font-size: 1rem;
line-height: 1.7;
}
}
</style>
</head>
<body>
<!-- =========================
HEADER
========================= -->
<header id="header">
<a
class="logo"
href="index.html"
>
<img
src="https://copilot.microsoft.com/th/id/BCO.cc808577-1db9-4523-90a6-be7b2abee261.png"
alt="InfinityGRM"
>
</a>
<nav class="nav">
<a href="index.html">
Home
</a>
<a href="labs.html">
Labs
</a>
</nav>
<a
href="signup.html"
class="account"
aria-label="Account"
>
<svg
viewBox="0 0 24 24"
aria-hidden="true"
>
<path d="M12 12c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm0 2c-3.34 0-10 1.68-10 5v3h20v-3c0-3.32-6.66-5-10-5z"/>
</svg>
</a>
</header>
<!-- =========================
MAIN
========================= -->
<main>
<!-- =========================
HOME
========================= -->
<section
class="home"
id="home"
>
<h1>
InfinityGRM
</h1>
<div class="input">
<!-- HOME INPUT -->
<div
id="input"
class="edit"
contenteditable="true"
role="textbox"
aria-label="Ask me anything"
data-placeholder="Ask me anything..."
></div>
<!-- HOME DICTATION -->
<button
id="voice"
class="voice"
type="button"
aria-label="Dictate"
title="Dictate"
>
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M12 1.5a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0v-7a3 3 0 0 0-3-3z"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M19.5 10.5v1.5a7.5 7.5 0 0 1-15 0v-1.5"
stroke-width="1.5"
stroke-linecap="round"
/>
<path
d="M12 19.5v3"
stroke-width="1.5"
stroke-linecap="round"
/>
</svg>
</button>
<!-- HOME SEND -->
<button
id="send"
class="send"
type="button"
aria-label="Send"
title="Send"
>
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M12 19V5m0 0-6 6m6-6 6 6"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
<!-- MISSION BUTTON -->
<a
href="#mission"
class="mission-btn"
>
Our Mission
</a>
</section>
<!-- =========================
CHAT
========================= -->
<section
class="chat"
id="chat"
>
<!-- MESSAGE AREA -->
<div
class="messages"
id="messagesContainer"
>
<div
class="messages-inner"
id="messages"
></div>
</div>
<!-- =========================
CHAT INPUT
========================= -->
<div class="bottom">
<div class="input">
<!-- CHAT INPUT -->
<div
id="chatInput"
class="edit"
contenteditable="true"
role="textbox"
aria-label="Ask me anything"
data-placeholder="Ask me anything..."
></div>
<!-- CHAT DICTATION -->
<button
id="chatVoice"
class="voice"
type="button"
aria-label="Dictate"
title="Dictate"
>
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M12 1.5a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0v-7a3 3 0 0 0-3-3z"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M19.5 10.5v1.5a7.5 7.5 0 0 1-15 0v-1.5"
stroke-width="1.5"
stroke-linecap="round"
/>
<path
d="M12 19.5v3"
stroke-width="1.5"
stroke-linecap="round"
/>
</svg>
</button>
<!-- CHAT SEND -->
<button
id="chatSend"
class="send"
type="button"
aria-label="Send"
title="Send"
>
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M12 19V5m0 0-6 6m6-6 6 6"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</div>
</section>
</main>
<!-- =========================
MISSION
========================= -->
<section id="mission">
<h2>
Our Mission
</h2>
<p>
Our mission is to develop safe superintelligence that elevates and
benefits all of humanity. We believe in building advanced AI systems,
infrastructure, and breakthroughs that empower individuals and help
shape a flourishing future. Every contribution allows us to continue
pioneering new frontiers, supporting ambitious research, and ensuring
that the rewards of technological progress make a lasting difference
for communities around the world.
</p>
</section>
<script>
/* =========================
ELEMENTS
========================= */
const header =
document.getElementById("header");
const mission =
document.getElementById("mission");
const home =
document.getElementById("home");
const chat =
document.getElementById("chat");
const input =
document.getElementById("input");
const send =
document.getElementById("send");
const chatInput =
document.getElementById("chatInput");
const chatSend =
document.getElementById("chatSend");
const messages =
document.getElementById("messages");
const messagesContainer =
document.getElementById("messagesContainer");
const voice =
document.getElementById("voice");
const chatVoice =
document.getElementById("chatVoice");
/* =========================
CHAT STATE
========================= */
/*
This tells the header whether the user
is currently inside the chat.
When true, the header will ALWAYS remain white.
*/
let chatActive = false;
/* =========================
SESSION ID
========================= */
/*
One session ID is created for the entire
browser session.
This allows multiple questions to belong
to the same conversation.
*/
const sessionId =
"session_" +
Math.random()
.toString(36)
.slice(2) +
"_" +
Date.now();
/* =========================
HEADER
========================= */
function updateHeader() {
/*
CRITICAL FIX:
If chat is open, never turn the header black.
The user can scroll through 50+ messages and
the header will stay white.
*/
if (chatActive) {
header.classList.remove("dark");
return;
}
/*
Normal homepage behavior.
The header becomes black when the Mission
section reaches the top of the viewport.
*/
const missionTop =
mission.getBoundingClientRect().top;
header.classList.toggle(
"dark",
missionTop <= 100
);
}
/*
Listen for normal page scrolling.
This does NOT affect the header while chatActive
is true.
*/
window.addEventListener(
"scroll",
updateHeader
);
/*
Initial header state.
*/
window.addEventListener(
"load",
updateHeader
);
/* =========================
GET CLEAN TEXT
========================= */
function getInputText(element) {
return element.innerText
.replace(/\u200B/g, "")
.replace(/\u00A0/g, " ")
.trim();
}
/* =========================
CLEAR CONTENTEDITABLE
========================= */
function clearInput(element) {
/*
innerHTML = "" is important.
contenteditable browsers can insert <br>
elements that would otherwise prevent
:empty from working correctly.
*/
element.innerHTML = "";
element.textContent = "";
}
/* =========================
BUTTON STATE
========================= */
function updateButton(
inputElement,
buttonElement
) {
const text =
getInputText(inputElement);
buttonElement.classList.toggle(
"active",
text.length > 0
);
}
/* =========================
ADD MESSAGE
========================= */
function addMessage(
text,
type
) {
const message =
document.createElement("div");
message.className =
"message " + type;
const content =
document.createElement("div");
content.textContent =
text;
message.appendChild(
content
);
messages.appendChild(
message
);
/*
Scroll ONLY the chat message area.
This is important because the page itself
should not move when new messages arrive.
*/
requestAnimationFrame(() => {
messagesContainer.scrollTop =
messagesContainer.scrollHeight;
});
}
/* =========================
SHOW CHAT
========================= */
function showChat() {
/*
Mark chat as active FIRST.
This prevents the header scroll handler
from turning it black.
*/
chatActive = true;
/*
Immediately force the header white.
*/
header.classList.remove(
"dark"
);
/*
Hide homepage.
*/
home.style.display =
"none";
/*
Show chat.
*/
chat.style.display =
"flex";
/*
Prevent the main document from scrolling
while the chat is active.
*/
document.body.style.overflow =
"hidden";
/*
Focus the chat input.
*/
requestAnimationFrame(() => {
chatInput.focus();
});
}
/* =========================
SEND MESSAGE
========================= */
async function sendMessage(
inputElement,
buttonElement
) {
const text =
getInputText(inputElement);
/*
Do nothing if empty.
*/
if (!text) {
return;
}
/*
Open chat.
*/
showChat();
/*
Add user's message immediately.
*/
addMessage(
text,
"user"
);
/*
Clear the input.
This makes the placeholder
"Ask me anything..."
appear again.
*/
clearInput(
inputElement
);
/*
Reset send button.
*/
updateButton(
inputElement,
buttonElement
);
try {
const response = await fetch(
"ai-bridge.php",
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
message: text,
session_id: sessionId
})
}
);
/*
Check HTTP status.
*/
if (!response.ok) {
throw new Error(
"Server returned " +
response.status
);
}
/*
Convert response to JSON.
*/
const data =
await response.json();
/*
Add AI response.
*/
addMessage(
data.response ||
(
"Error: " +
(
data.error ||
"No response"
)
),
"ai"
);
} catch (error) {
console.error(
"Chat error:",
error
);
addMessage(
"Failed to connect to the server.",
"ai"
);
}
/*
ALWAYS reset the chat input.
This guarantees the placeholder is
visible after the AI responds.
*/
clearInput(
chatInput
);
updateButton(
chatInput,
chatSend
);
/*
Keep the chat input ready for
another question.
*/
requestAnimationFrame(() => {
chatInput.focus();
});
}
/* =========================
HOME INPUT
========================= */
input.addEventListener(
"input",
() => {
updateButton(
input,
send
);
}
);
/* =========================
CHAT INPUT
========================= */
chatInput.addEventListener(
"input",
() => {
updateButton(
chatInput,
chatSend
);
}
);
/* =========================
SEND BUTTON
========================= */
send.addEventListener(
"click",
() => {
sendMessage(
input,
send
);
}
);
chatSend.addEventListener(
"click",
() => {
sendMessage(
chatInput,
chatSend
);
}
);
/* =========================
ENTER TO SEND
========================= */
input.addEventListener(
"keydown",
event => {
/*
Enter = send
Shift + Enter = new line
*/
if (
event.key === "Enter" &&
!event.shiftKey
) {
event.preventDefault();
sendMessage(
input,
send
);
}
}
);
chatInput.addEventListener(
"keydown",
event => {
/*
Enter = send
Shift + Enter = new line
*/
if (
event.key === "Enter" &&
!event.shiftKey
) {
event.preventDefault();
sendMessage(
chatInput,
chatSend
);
}
}
);
/* =========================
DICTATION
========================= */
function setupDictation(
button,
targetInput,
targetSendButton
) {
const SpeechRecognition =
window.SpeechRecognition ||
window.webkitSpeechRecognition;
/*
Browser doesn't support speech recognition.
*/
if (!SpeechRecognition) {
button.addEventListener(
"click",
() => {
alert(
"Voice dictation is not supported in this browser."
);
}
);
return;
}
const recognition =
new SpeechRecognition();
recognition.continuous =
false;
recognition.interimResults =
false;
recognition.lang =
"en-US";
/* =========================
START
========================= */
button.addEventListener(
"click",
() => {
try {
recognition.start();
button.classList.add(
"active"
);
} catch (error) {
console.log(
"Speech recognition:",
error
);
}
}
);
/* =========================
RESULT
========================= */
recognition.addEventListener(
"result",
event => {
const transcript =
event
.results[0][0]
.transcript;
/*
Add dictated text.
*/
const existing =
getInputText(
targetInput
);
if (existing) {
targetInput.innerText =
existing +
" " +
transcript;
} else {
targetInput.innerText =
transcript;
}
/*
Update send button.
*/
updateButton(
targetInput,
targetSendButton
);
/*
Focus input.
*/
targetInput.focus();
}
);
/* =========================
END
========================= */
recognition.addEventListener(
"end",
() => {
button.classList.remove(
"active"
);
}
);
/* =========================
ERROR
========================= */
recognition.addEventListener(
"error",
error => {
console.log(
"Dictation error:",
error
);
button.classList.remove(
"active"
);
}
);
}
/* =========================
ENABLE HOME DICTATION
========================= */
setupDictation(
voice,
input,
send
);
/* =========================
ENABLE CHAT DICTATION
========================= */
setupDictation(
chatVoice,
chatInput,
chatSend
);
/* =========================
INITIAL STATE
========================= */
clearInput(
input
);
clearInput(
chatInput
);
updateButton(
input,
send
);
updateButton(
chatInput,
chatSend
);
/*
Make sure the header starts white.
*/
header.classList.remove(
"dark"
);
</script>
</body>
</html>