mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix: redesign landing page with Nous blue palette and cleaner layout
This commit is contained in:
parent
8fa96debc9
commit
c0f985d05a
3 changed files with 1207 additions and 1107 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -4,339 +4,486 @@
|
|||
|
||||
// --- Platform install commands ---
|
||||
const PLATFORMS = {
|
||||
linux: {
|
||||
command: 'curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash',
|
||||
prompt: '$',
|
||||
note: 'Works on Linux, macOS & WSL2 · No prerequisites · Installs everything automatically',
|
||||
stepNote: 'Installs uv, Python 3.11, clones the repo, sets up everything. No sudo needed.',
|
||||
},
|
||||
linux: {
|
||||
command:
|
||||
"curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash",
|
||||
prompt: "$",
|
||||
note: "Works on Linux, macOS & WSL2 · No prerequisites · Installs everything automatically",
|
||||
stepNote:
|
||||
"Installs uv, Python 3.11, clones the repo, sets up everything. No sudo needed.",
|
||||
},
|
||||
};
|
||||
|
||||
function detectPlatform() {
|
||||
return 'linux';
|
||||
return "linux";
|
||||
}
|
||||
|
||||
function switchPlatform(platform) {
|
||||
const cfg = PLATFORMS[platform];
|
||||
if (!cfg) return;
|
||||
const cfg = PLATFORMS[platform];
|
||||
if (!cfg) return;
|
||||
|
||||
// Update hero install widget
|
||||
const commandEl = document.getElementById('install-command');
|
||||
const promptEl = document.getElementById('install-prompt');
|
||||
const noteEl = document.getElementById('install-note');
|
||||
// Update hero install widget
|
||||
const commandEl = document.getElementById("install-command");
|
||||
const promptEl = document.getElementById("install-prompt");
|
||||
const noteEl = document.getElementById("install-note");
|
||||
|
||||
if (commandEl) commandEl.textContent = cfg.command;
|
||||
if (promptEl) promptEl.textContent = cfg.prompt;
|
||||
if (noteEl) noteEl.textContent = cfg.note;
|
||||
if (commandEl) commandEl.textContent = cfg.command;
|
||||
if (promptEl) promptEl.textContent = cfg.prompt;
|
||||
if (noteEl) noteEl.textContent = cfg.note;
|
||||
|
||||
// Update active tab in hero
|
||||
document.querySelectorAll('.install-tab').forEach(tab => {
|
||||
tab.classList.toggle('active', tab.dataset.platform === platform);
|
||||
});
|
||||
// Update active tab in hero
|
||||
document.querySelectorAll(".install-tab").forEach((tab) => {
|
||||
tab.classList.toggle("active", tab.dataset.platform === platform);
|
||||
});
|
||||
|
||||
// Sync the step section tabs too
|
||||
switchStepPlatform(platform);
|
||||
// Sync the step section tabs too
|
||||
switchStepPlatform(platform);
|
||||
}
|
||||
|
||||
function switchStepPlatform(platform) {
|
||||
const cfg = PLATFORMS[platform];
|
||||
if (!cfg) return;
|
||||
const cfg = PLATFORMS[platform];
|
||||
if (!cfg) return;
|
||||
|
||||
const commandEl = document.getElementById('step1-command');
|
||||
const copyBtn = document.getElementById('step1-copy');
|
||||
const noteEl = document.getElementById('step1-note');
|
||||
const commandEl = document.getElementById("step1-command");
|
||||
const copyBtn = document.getElementById("step1-copy");
|
||||
const noteEl = document.getElementById("step1-note");
|
||||
|
||||
if (commandEl) commandEl.textContent = cfg.command;
|
||||
if (copyBtn) copyBtn.setAttribute('data-text', cfg.command);
|
||||
if (noteEl) noteEl.textContent = cfg.stepNote;
|
||||
if (commandEl) commandEl.textContent = cfg.command;
|
||||
if (copyBtn) copyBtn.setAttribute("data-text", cfg.command);
|
||||
if (noteEl) noteEl.textContent = cfg.stepNote;
|
||||
|
||||
// Update active tab in step section
|
||||
document.querySelectorAll('.code-tab').forEach(tab => {
|
||||
tab.classList.toggle('active', tab.dataset.platform === platform);
|
||||
});
|
||||
// Update active tab in step section
|
||||
document.querySelectorAll(".code-tab").forEach((tab) => {
|
||||
tab.classList.toggle("active", tab.dataset.platform === platform);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleMobileNav() {
|
||||
document.getElementById("nav-mobile").classList.toggle("open");
|
||||
}
|
||||
|
||||
// --- Copy to clipboard ---
|
||||
function copyInstall() {
|
||||
const text = document.getElementById('install-command').textContent;
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
const btn = document.querySelector('.install-widget-body .copy-btn');
|
||||
const original = btn.querySelector('.copy-text').textContent;
|
||||
btn.querySelector('.copy-text').textContent = 'Copied!';
|
||||
btn.style.color = 'var(--gold)';
|
||||
setTimeout(() => {
|
||||
btn.querySelector('.copy-text').textContent = original;
|
||||
btn.style.color = '';
|
||||
}, 2000);
|
||||
});
|
||||
const text = document.getElementById("install-command").textContent;
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
const btn = document.querySelector(".install-widget-body .copy-btn");
|
||||
const original = btn.querySelector(".copy-text").textContent;
|
||||
btn.querySelector(".copy-text").textContent = "Copied!";
|
||||
btn.style.color = "var(--primary-light)";
|
||||
setTimeout(() => {
|
||||
btn.querySelector(".copy-text").textContent = original;
|
||||
btn.style.color = "";
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function copyText(btn) {
|
||||
const text = btn.getAttribute('data-text');
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
const original = btn.textContent;
|
||||
btn.textContent = 'Copied!';
|
||||
btn.style.color = 'var(--gold)';
|
||||
setTimeout(() => {
|
||||
btn.textContent = original;
|
||||
btn.style.color = '';
|
||||
}, 2000);
|
||||
});
|
||||
const text = btn.getAttribute("data-text");
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
const original = btn.textContent;
|
||||
btn.textContent = "Copied!";
|
||||
btn.style.color = "var(--primary-light)";
|
||||
setTimeout(() => {
|
||||
btn.textContent = original;
|
||||
btn.style.color = "";
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Scroll-triggered fade-in ---
|
||||
function initScrollAnimations() {
|
||||
const elements = document.querySelectorAll(
|
||||
'.feature-card, .tool-pill, .platform-group, .skill-category, ' +
|
||||
'.install-step, .research-card, .footer-card, .section-header, ' +
|
||||
'.lead-text, .section-desc, .terminal-window'
|
||||
);
|
||||
const elements = document.querySelectorAll(
|
||||
".feature-card, .spec-row, .install-step, " +
|
||||
".section-header, .terminal-window",
|
||||
);
|
||||
|
||||
elements.forEach(el => el.classList.add('fade-in'));
|
||||
elements.forEach((el) => el.classList.add("fade-in"));
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
// Stagger children within grids
|
||||
const parent = entry.target.parentElement;
|
||||
if (parent) {
|
||||
const siblings = parent.querySelectorAll('.fade-in');
|
||||
let idx = Array.from(siblings).indexOf(entry.target);
|
||||
if (idx < 0) idx = 0;
|
||||
setTimeout(() => {
|
||||
entry.target.classList.add('visible');
|
||||
}, idx * 60);
|
||||
} else {
|
||||
entry.target.classList.add('visible');
|
||||
}
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
// Stagger children within grids
|
||||
const parent = entry.target.parentElement;
|
||||
if (parent) {
|
||||
const siblings = parent.querySelectorAll(".fade-in");
|
||||
let idx = Array.from(siblings).indexOf(entry.target);
|
||||
if (idx < 0) idx = 0;
|
||||
setTimeout(() => {
|
||||
entry.target.classList.add("visible");
|
||||
}, idx * 60);
|
||||
} else {
|
||||
entry.target.classList.add("visible");
|
||||
}
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.1, rootMargin: "0px 0px -40px 0px" },
|
||||
);
|
||||
|
||||
elements.forEach(el => observer.observe(el));
|
||||
elements.forEach((el) => observer.observe(el));
|
||||
}
|
||||
|
||||
// --- Terminal Demo ---
|
||||
const CURSOR = '<span class="terminal-cursor">█</span>';
|
||||
|
||||
const demoSequence = [
|
||||
// Scene 1: Research task with delegation
|
||||
{ type: 'prompt', text: '❯ ' },
|
||||
{ type: 'type', text: 'Research the latest approaches to GRPO training and write a summary', delay: 30 },
|
||||
{ type: 'pause', ms: 600 },
|
||||
{ type: 'output', lines: [
|
||||
'',
|
||||
'<span class="t-dim">┊ 🔍 web_search "GRPO reinforcement learning 2026" 1.2s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ 📄 web_extract arxiv.org/abs/2402.03300 3.1s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ 🔍 web_search "GRPO vs PPO ablation results" 0.9s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ 📄 web_extract huggingface.co/blog/grpo 2.8s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ ✍️ write_file ~/research/grpo-summary.md 0.1s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 500 },
|
||||
{ type: 'output', lines: [
|
||||
'',
|
||||
'<span class="t-text">Done! I\'ve written a summary covering:</span>',
|
||||
'',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> GRPO\'s group-relative advantage (no critic model needed)</span>',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Comparison with PPO/DPO on reasoning benchmarks</span>',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Implementation notes for Axolotl and TRL</span>',
|
||||
'',
|
||||
'<span class="t-text">Saved to</span> <span class="t-amber">~/research/grpo-summary.md</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 2500 },
|
||||
{ type: "prompt", text: "❯ " },
|
||||
{
|
||||
type: "type",
|
||||
text: "Research the latest approaches to GRPO training and write a summary",
|
||||
delay: 30,
|
||||
},
|
||||
{ type: "pause", ms: 600 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
"",
|
||||
'<span class="t-dim"> web_search "GRPO reinforcement learning 2026" 1.2s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> web_extract arxiv.org/abs/2402.03300 3.1s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> web_search "GRPO vs PPO ablation results" 0.9s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> web_extract huggingface.co/blog/grpo 2.8s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> write_file ~/research/grpo-summary.md 0.1s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 500 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
"",
|
||||
'<span class="t-text">Done! I\'ve written a summary covering:</span>',
|
||||
"",
|
||||
'<span class="t-text"> <span class="t-green">✓</span> GRPO\'s group-relative advantage (no critic model needed)</span>',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Comparison with PPO/DPO on reasoning benchmarks</span>',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Implementation notes for Axolotl and TRL</span>',
|
||||
"",
|
||||
'<span class="t-text">Saved to</span> <span class="t-accent">~/research/grpo-summary.md</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 2500 },
|
||||
|
||||
// Scene 2: Quick delegation
|
||||
{ type: 'clear' },
|
||||
{ type: 'prompt', text: '❯ ' },
|
||||
{ type: 'type', text: 'Review the PR at NousResearch/hermes-agent#42 and fix any issues', delay: 30 },
|
||||
{ type: 'pause', ms: 600 },
|
||||
{ type: 'output', lines: [
|
||||
'',
|
||||
'<span class="t-dim">┊ 🔀 delegate_task "review PR #42 changes" 2.1s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 500 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ 💻 git diff main..pr-42 0.4s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ ✏️ patch tools/registry.py 0.1s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ 💻 python -m pytest tests/ -x 3.2s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 400 },
|
||||
{ type: 'output', lines: [
|
||||
'<span class="t-dim">┊ 💻 git commit -m "fix: handle empty tool schemas" 0.3s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 500 },
|
||||
{ type: 'output', lines: [
|
||||
'',
|
||||
'<span class="t-text">Found 2 issues in the PR and fixed both:</span>',
|
||||
'',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Empty tool schema crash in registry.py — added guard</span>',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Missing error handling in delegate_tool.py — added try/except</span>',
|
||||
'',
|
||||
'<span class="t-text">Tests pass. Committed the fix and pushed to the PR branch.</span>',
|
||||
'<span class="t-text">I also saved a</span> <span class="t-amber">skill</span> <span class="t-text">for this PR review pattern.</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 2500 },
|
||||
{ type: "clear" },
|
||||
{ type: "prompt", text: "❯ " },
|
||||
{
|
||||
type: "type",
|
||||
text: "Review the PR at NousResearch/hermes-agent#42 and fix any issues",
|
||||
delay: 30,
|
||||
},
|
||||
{ type: "pause", ms: 600 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
"",
|
||||
'<span class="t-dim"> delegate_task "review PR #42 changes" 2.1s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 500 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> git diff main..pr-42 0.4s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> patch tools/registry.py 0.1s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> python -m pytest tests/ -x 3.2s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 400 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
'<span class="t-dim"> git commit -m "fix: handle empty tool schemas" 0.3s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 500 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
"",
|
||||
'<span class="t-text">Found 2 issues in the PR and fixed both:</span>',
|
||||
"",
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Empty tool schema crash in registry.py — added guard</span>',
|
||||
'<span class="t-text"> <span class="t-green">✓</span> Missing error handling in delegate_tool.py — added try/except</span>',
|
||||
"",
|
||||
'<span class="t-text">Tests pass. Committed the fix and pushed to the PR branch.</span>',
|
||||
'<span class="t-text">I also saved a</span> <span class="t-accent">skill</span> <span class="t-text">for this PR review pattern.</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 2500 },
|
||||
|
||||
// Scene 3: Session search by keyword
|
||||
{ type: 'clear' },
|
||||
{ type: 'prompt', text: '❯ ' },
|
||||
{ type: 'type', text: 'How did we fix that Docker networking issue?', delay: 35 },
|
||||
{ type: 'pause', ms: 500 },
|
||||
{ type: 'output', lines: [
|
||||
'',
|
||||
'<span class="t-dim">┊ 🔎 session_search "Docker networking" 1.4s</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 500 },
|
||||
{ type: 'output', lines: [
|
||||
'',
|
||||
'<span class="t-text">Found it — from a session on February 12th:</span>',
|
||||
'',
|
||||
'<span class="t-text">The containers couldn\'t reach each other because the compose</span>',
|
||||
'<span class="t-text">file was using the default bridge network. We switched to a</span>',
|
||||
'<span class="t-text">custom network with</span> <span class="t-amber">driver: overlay</span><span class="t-text">, added explicit</span>',
|
||||
'<span class="t-text">aliases, and set</span> <span class="t-amber">dns: 8.8.8.8</span> <span class="t-text">as a fallback.</span>',
|
||||
'',
|
||||
'<span class="t-text">The fix was committed in</span> <span class="t-amber">docker-compose.prod.yml</span><span class="t-text">.</span>',
|
||||
]},
|
||||
{ type: 'pause', ms: 3000 },
|
||||
{ type: "clear" },
|
||||
{ type: "prompt", text: "❯ " },
|
||||
{
|
||||
type: "type",
|
||||
text: "How did we fix that Docker networking issue?",
|
||||
delay: 35,
|
||||
},
|
||||
{ type: "pause", ms: 500 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
"",
|
||||
'<span class="t-dim"> session_search "Docker networking" 1.4s</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 500 },
|
||||
{
|
||||
type: "output",
|
||||
lines: [
|
||||
"",
|
||||
'<span class="t-text">Found it — from a session on February 12th:</span>',
|
||||
"",
|
||||
'<span class="t-text">The containers couldn\'t reach each other because the compose</span>',
|
||||
'<span class="t-text">file was using the default bridge network. We switched to a</span>',
|
||||
'<span class="t-text">custom network with</span> <span class="t-accent">driver: overlay</span><span class="t-text">, added explicit</span>',
|
||||
'<span class="t-text">aliases, and set</span> <span class="t-accent">dns: 8.8.8.8</span> <span class="t-text">as a fallback.</span>',
|
||||
"",
|
||||
'<span class="t-text">The fix was committed in</span> <span class="t-accent">docker-compose.prod.yml</span><span class="t-text">.</span>',
|
||||
],
|
||||
},
|
||||
{ type: "pause", ms: 3000 },
|
||||
];
|
||||
|
||||
class TerminalDemo {
|
||||
constructor(element, cursorElement) {
|
||||
this.el = element;
|
||||
this.cursor = cursorElement;
|
||||
this.running = false;
|
||||
this.content = '';
|
||||
this.observer = null;
|
||||
}
|
||||
constructor(container) {
|
||||
this.container = container;
|
||||
this.running = false;
|
||||
this.content = "";
|
||||
}
|
||||
|
||||
async start() {
|
||||
if (this.running) return;
|
||||
this.running = true;
|
||||
|
||||
while (this.running) {
|
||||
for (const step of demoSequence) {
|
||||
if (!this.running) return;
|
||||
await this.execute(step);
|
||||
}
|
||||
// Loop
|
||||
this.clear();
|
||||
await this.sleep(1000);
|
||||
async start() {
|
||||
if (this.running) return;
|
||||
this.running = true;
|
||||
|
||||
while (this.running) {
|
||||
for (const step of demoSequence) {
|
||||
if (!this.running) return;
|
||||
await this.execute(step);
|
||||
}
|
||||
this.clear();
|
||||
await this.sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
async execute(step) {
|
||||
switch (step.type) {
|
||||
case "prompt":
|
||||
this.append(`<span class="t-prompt">${step.text}</span>`);
|
||||
break;
|
||||
case "type":
|
||||
for (const char of step.text) {
|
||||
if (!this.running) return;
|
||||
this.append(`<span class="t-cmd">${char}</span>`);
|
||||
await this.sleep(step.delay || 30);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
async execute(step) {
|
||||
switch (step.type) {
|
||||
case 'prompt':
|
||||
this.append(`<span class="t-prompt">${step.text}</span>`);
|
||||
break;
|
||||
|
||||
case 'type':
|
||||
for (const char of step.text) {
|
||||
if (!this.running) return;
|
||||
this.append(`<span class="t-cmd">${char}</span>`);
|
||||
await this.sleep(step.delay || 30);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'output':
|
||||
for (const line of step.lines) {
|
||||
if (!this.running) return;
|
||||
this.append('\n' + line);
|
||||
await this.sleep(50);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pause':
|
||||
await this.sleep(step.ms);
|
||||
break;
|
||||
|
||||
case 'clear':
|
||||
this.clear();
|
||||
break;
|
||||
break;
|
||||
case "output":
|
||||
for (const line of step.lines) {
|
||||
if (!this.running) return;
|
||||
this.append("\n" + line);
|
||||
await this.sleep(50);
|
||||
}
|
||||
break;
|
||||
case "pause":
|
||||
await this.sleep(step.ms);
|
||||
break;
|
||||
case "clear":
|
||||
this.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
append(html) {
|
||||
this.content += html;
|
||||
this.el.innerHTML = this.content;
|
||||
// Keep cursor at end
|
||||
this.el.parentElement.scrollTop = this.el.parentElement.scrollHeight;
|
||||
}
|
||||
append(html) {
|
||||
this.content += html;
|
||||
this.render();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.content = '';
|
||||
this.el.innerHTML = '';
|
||||
}
|
||||
render() {
|
||||
this.container.innerHTML = this.content + CURSOR;
|
||||
this.container.scrollTop = this.container.scrollHeight;
|
||||
}
|
||||
|
||||
sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
clear() {
|
||||
this.content = "";
|
||||
this.container.innerHTML = "";
|
||||
}
|
||||
|
||||
sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Noise Overlay (ported from hermes-chat NoiseOverlay) ---
|
||||
function initNoiseOverlay() {
|
||||
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
||||
if (typeof THREE === "undefined") return;
|
||||
|
||||
const canvas = document.getElementById("noise-overlay");
|
||||
if (!canvas) return;
|
||||
|
||||
const vertexShader = `
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const fragmentShader = `
|
||||
uniform vec2 uRes;
|
||||
uniform float uDpr, uSize, uDensity, uOpacity;
|
||||
uniform vec3 uColor;
|
||||
varying vec2 vUv;
|
||||
|
||||
float hash(vec2 p) {
|
||||
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
||||
p3 += dot(p3, p3.yzx + 33.33);
|
||||
return fract((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float n = hash(floor(vUv * uRes / (uSize * uDpr)));
|
||||
gl_FragColor = vec4(uColor, step(1.0 - uDensity, n)) * uOpacity;
|
||||
}
|
||||
`;
|
||||
|
||||
function hexToVec3(hex) {
|
||||
const c = hex.replace("#", "");
|
||||
return new THREE.Vector3(
|
||||
parseInt(c.substring(0, 2), 16) / 255,
|
||||
parseInt(c.substring(2, 4), 16) / 255,
|
||||
parseInt(c.substring(4, 6), 16) / 255,
|
||||
);
|
||||
}
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
alpha: true,
|
||||
canvas,
|
||||
premultipliedAlpha: false,
|
||||
});
|
||||
renderer.setClearColor(0x000000, 0);
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
||||
const geo = new THREE.PlaneGeometry(2, 2);
|
||||
|
||||
const mat = new THREE.ShaderMaterial({
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
transparent: true,
|
||||
uniforms: {
|
||||
uColor: { value: hexToVec3("#8090BB") },
|
||||
uDensity: { value: 0.1 },
|
||||
uDpr: { value: 1 },
|
||||
uOpacity: { value: 0.4 },
|
||||
uRes: { value: new THREE.Vector2() },
|
||||
uSize: { value: 1.0 },
|
||||
},
|
||||
});
|
||||
|
||||
scene.add(new THREE.Mesh(geo, mat));
|
||||
|
||||
function resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const w = window.innerWidth;
|
||||
const h = window.innerHeight;
|
||||
renderer.setSize(w, h);
|
||||
renderer.setPixelRatio(dpr);
|
||||
mat.uniforms.uRes.value.set(w * dpr, h * dpr);
|
||||
mat.uniforms.uDpr.value = dpr;
|
||||
}
|
||||
|
||||
resize();
|
||||
window.addEventListener("resize", resize);
|
||||
|
||||
function loop() {
|
||||
requestAnimationFrame(loop);
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
loop();
|
||||
}
|
||||
|
||||
// --- Initialize ---
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Auto-detect platform and set the right install command
|
||||
const detectedPlatform = detectPlatform();
|
||||
switchPlatform(detectedPlatform);
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const detectedPlatform = detectPlatform();
|
||||
switchPlatform(detectedPlatform);
|
||||
|
||||
initScrollAnimations();
|
||||
initScrollAnimations();
|
||||
initNoiseOverlay();
|
||||
|
||||
// Terminal demo - start when visible
|
||||
const terminalEl = document.getElementById('terminal-content');
|
||||
const cursorEl = document.getElementById('terminal-cursor');
|
||||
|
||||
if (terminalEl && cursorEl) {
|
||||
const demo = new TerminalDemo(terminalEl, cursorEl);
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
demo.start();
|
||||
} else {
|
||||
demo.stop();
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
const terminalEl = document.getElementById("terminal-demo");
|
||||
|
||||
observer.observe(document.querySelector('.terminal-window'));
|
||||
}
|
||||
if (terminalEl) {
|
||||
const demo = new TerminalDemo(terminalEl);
|
||||
|
||||
// Smooth nav background on scroll
|
||||
const nav = document.querySelector('.nav');
|
||||
let ticking = false;
|
||||
window.addEventListener('scroll', () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(() => {
|
||||
if (window.scrollY > 50) {
|
||||
nav.style.borderBottomColor = 'rgba(255, 215, 0, 0.1)';
|
||||
} else {
|
||||
nav.style.borderBottomColor = '';
|
||||
}
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
demo.start();
|
||||
} else {
|
||||
demo.stop();
|
||||
}
|
||||
});
|
||||
},
|
||||
{ threshold: 0.3 },
|
||||
);
|
||||
|
||||
observer.observe(document.querySelector(".terminal-window"));
|
||||
}
|
||||
|
||||
const nav = document.querySelector(".nav");
|
||||
let ticking = false;
|
||||
window.addEventListener("scroll", () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(() => {
|
||||
if (window.scrollY > 50) {
|
||||
nav.style.borderBottomColor = "rgba(48, 80, 255, 0.15)";
|
||||
} else {
|
||||
nav.style.borderBottomColor = "";
|
||||
}
|
||||
});
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* =========================================================================
|
||||
Hermes Agent Landing Page
|
||||
Colors: Gold (#FFD700) / Amber (#FFBF00) / Bronze (#CD7F32)
|
||||
Colors: Nous Blue (#3050FF) palette
|
||||
========================================================================= */
|
||||
|
||||
/* --- Reset & Base --- */
|
||||
|
|
@ -11,18 +11,18 @@
|
|||
}
|
||||
|
||||
:root {
|
||||
--gold: #FFD700;
|
||||
--amber: #FFBF00;
|
||||
--bronze: #CD7F32;
|
||||
--dark-gold: #B8860B;
|
||||
--bg: #07070d;
|
||||
--bg-card: #0f0f18;
|
||||
--bg-card-hover: #14142a;
|
||||
--border: rgba(255, 215, 0, 0.08);
|
||||
--border-hover: rgba(255, 215, 0, 0.18);
|
||||
--text: #e8e4dc;
|
||||
--text-dim: #9a968e;
|
||||
--text-muted: #6a665e;
|
||||
--primary: #3050FF;
|
||||
--primary-light: #5070FF;
|
||||
--primary-dim: #2040CC;
|
||||
--primary-dark: #1E30AA;
|
||||
--bg: #0A0E1A;
|
||||
--bg-card: #12182A;
|
||||
--bg-card-hover: #1A2240;
|
||||
--border: rgba(48, 80, 255, 0.1);
|
||||
--border-hover: rgba(48, 80, 255, 0.22);
|
||||
--text: #E8ECFF;
|
||||
--text-dim: #8090BB;
|
||||
--text-muted: #506090;
|
||||
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
|
||||
--container: 1080px;
|
||||
|
|
@ -45,17 +45,17 @@ body {
|
|||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
background-image: radial-gradient(rgba(255, 215, 0, 0.03) 1px, transparent 1px);
|
||||
background-image: radial-gradient(rgba(48, 80, 255, 0.04) 1px, transparent 1px);
|
||||
background-size: 32px 32px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--gold);
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--amber);
|
||||
color: var(--primary-light);
|
||||
}
|
||||
|
||||
strong {
|
||||
|
|
@ -63,6 +63,17 @@ strong {
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* --- Noise Overlay --- */
|
||||
#noise-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 50;
|
||||
pointer-events: none;
|
||||
mix-blend-mode: soft-light;
|
||||
}
|
||||
|
||||
/* --- Ambient Glow --- */
|
||||
.ambient-glow {
|
||||
position: fixed;
|
||||
|
|
@ -75,7 +86,7 @@ strong {
|
|||
.glow-1 {
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
background: var(--gold);
|
||||
background: var(--primary);
|
||||
top: -200px;
|
||||
left: -200px;
|
||||
opacity: 0.08;
|
||||
|
|
@ -83,7 +94,7 @@ strong {
|
|||
.glow-2 {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
background: var(--bronze);
|
||||
background: var(--primary-dim);
|
||||
bottom: 20%;
|
||||
right: -150px;
|
||||
opacity: 0.06;
|
||||
|
|
@ -127,11 +138,18 @@ strong {
|
|||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
.nav-logo:hover { color: var(--gold); }
|
||||
.nav-logo:hover { color: var(--primary-light); }
|
||||
|
||||
.nav-symbol {
|
||||
font-size: 22px;
|
||||
color: var(--gold);
|
||||
.nav-nous-logo {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.nav-by {
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
|
|
@ -153,6 +171,46 @@ strong {
|
|||
|
||||
.external-icon { opacity: 0.4; }
|
||||
|
||||
/* --- Hamburger & Mobile Nav --- */
|
||||
.nav-hamburger {
|
||||
display: none;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-dim);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.nav-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-mobile.open {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(7, 7, 13, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 16px 24px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.nav-mobile a {
|
||||
color: var(--text-dim);
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.nav-mobile a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* --- Hero --- */
|
||||
.hero {
|
||||
position: relative;
|
||||
|
|
@ -174,8 +232,8 @@ strong {
|
|||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 16px;
|
||||
background: rgba(255, 215, 0, 0.06);
|
||||
border: 1px solid rgba(255, 215, 0, 0.15);
|
||||
background: rgba(48, 80, 255, 0.08);
|
||||
border: 1px solid rgba(48, 80, 255, 0.18);
|
||||
border-radius: 100px;
|
||||
font-size: 13px;
|
||||
color: var(--text-dim);
|
||||
|
|
@ -187,7 +245,7 @@ strong {
|
|||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--gold);
|
||||
background: var(--primary);
|
||||
display: inline-block;
|
||||
animation: pulse-dot 2s ease-in-out infinite;
|
||||
}
|
||||
|
|
@ -199,21 +257,20 @@ strong {
|
|||
|
||||
.hero-ascii {
|
||||
margin-bottom: 28px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero-logo {
|
||||
max-width: 700px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
filter: drop-shadow(0 0 24px rgba(255, 215, 0, 0.15));
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-variant-ligatures: none;
|
||||
font-size: clamp(4px, 0.95vw, 11px);
|
||||
line-height: 1.15;
|
||||
color: var(--primary-light);
|
||||
text-align: center;
|
||||
text-shadow: 0 0 20px rgba(48, 80, 255, 0.3);
|
||||
opacity: 0.85;
|
||||
transition: opacity 0.3s;
|
||||
opacity: 0.9;
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.hero-ascii:hover .hero-logo {
|
||||
.hero-ascii:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
|
@ -227,7 +284,7 @@ strong {
|
|||
}
|
||||
|
||||
.hero-gradient {
|
||||
background: linear-gradient(135deg, var(--gold), var(--amber), var(--bronze));
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-light), #90B0FF);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
|
|
@ -309,8 +366,8 @@ strong {
|
|||
}
|
||||
|
||||
.install-tab.active {
|
||||
background: rgba(255, 215, 0, 0.12);
|
||||
color: var(--gold);
|
||||
background: rgba(48, 80, 255, 0.14);
|
||||
color: var(--primary-light);
|
||||
}
|
||||
|
||||
.install-tab svg {
|
||||
|
|
@ -329,7 +386,7 @@ strong {
|
|||
}
|
||||
|
||||
.install-prompt {
|
||||
color: var(--gold);
|
||||
color: var(--primary-light);
|
||||
font-weight: 600;
|
||||
flex-shrink: 0;
|
||||
opacity: 0.7;
|
||||
|
|
@ -369,8 +426,8 @@ strong {
|
|||
}
|
||||
|
||||
.code-tab.active {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
color: var(--gold);
|
||||
background: rgba(48, 80, 255, 0.12);
|
||||
color: var(--primary-light);
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
|
|
@ -389,8 +446,8 @@ strong {
|
|||
transition: all 0.2s;
|
||||
}
|
||||
.copy-btn:hover {
|
||||
color: var(--gold);
|
||||
background: rgba(255, 215, 0, 0.08);
|
||||
color: var(--primary-light);
|
||||
background: rgba(48, 80, 255, 0.1);
|
||||
}
|
||||
|
||||
.install-note {
|
||||
|
|
@ -419,26 +476,14 @@ strong {
|
|||
}
|
||||
|
||||
.btn-primary {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
color: var(--gold);
|
||||
border-color: rgba(255, 215, 0, 0.2);
|
||||
background: rgba(48, 80, 255, 0.12);
|
||||
color: var(--primary-light);
|
||||
border-color: rgba(48, 80, 255, 0.25);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: rgba(255, 215, 0, 0.18);
|
||||
border-color: rgba(255, 215, 0, 0.35);
|
||||
color: var(--gold);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: var(--text-dim);
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
color: var(--text);
|
||||
background: rgba(48, 80, 255, 0.22);
|
||||
border-color: rgba(48, 80, 255, 0.4);
|
||||
color: #fff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
|
@ -457,12 +502,6 @@ strong {
|
|||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.section-marker {
|
||||
font-size: 20px;
|
||||
color: var(--gold);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 28px;
|
||||
font-weight: 650;
|
||||
|
|
@ -479,21 +518,6 @@ strong {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
/* --- Section: What --- */
|
||||
.section-what {
|
||||
padding: 60px 0 20px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.lead-text {
|
||||
font-size: 20px;
|
||||
line-height: 1.75;
|
||||
color: var(--text-dim);
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* --- Features Grid --- */
|
||||
.features-grid {
|
||||
display: grid;
|
||||
|
|
@ -505,7 +529,7 @@ strong {
|
|||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 28px 24px;
|
||||
padding: 20px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
|
|
@ -516,8 +540,9 @@ strong {
|
|||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 28px;
|
||||
margin-bottom: 16px;
|
||||
color: var(--primary-light);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.feature-card h3 {
|
||||
|
|
@ -590,7 +615,7 @@ strong {
|
|||
|
||||
.terminal-cursor {
|
||||
animation: blink 1s step-end infinite;
|
||||
color: var(--gold);
|
||||
color: var(--primary-light);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
|
|
@ -600,141 +625,60 @@ strong {
|
|||
}
|
||||
|
||||
/* Terminal demo colors */
|
||||
.t-prompt { color: var(--gold); }
|
||||
.t-prompt { color: var(--primary-light); }
|
||||
.t-cmd { color: #fff; }
|
||||
.t-dim { color: var(--text-muted); }
|
||||
.t-text { color: var(--text-dim); }
|
||||
.t-green { color: #4ade80; }
|
||||
.t-blue { color: #60a5fa; }
|
||||
.t-amber { color: var(--amber); }
|
||||
.t-bronze { color: var(--bronze); }
|
||||
.t-accent { color: var(--primary-light); }
|
||||
.t-highlight { color: #90B0FF; }
|
||||
.t-tool { color: var(--text-muted); }
|
||||
|
||||
/* --- Tools Grid --- */
|
||||
.tools-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tool-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 18px;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 100px;
|
||||
font-size: 14px;
|
||||
color: var(--text-dim);
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.tool-pill:hover {
|
||||
border-color: var(--border-hover);
|
||||
color: var(--text);
|
||||
background: var(--bg-card-hover);
|
||||
}
|
||||
|
||||
.tool-emoji {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* --- Platforms --- */
|
||||
.platforms-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.platform-group {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.platform-label {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 16px;
|
||||
font-weight: 550;
|
||||
}
|
||||
|
||||
.platform-pills {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.platform-pill {
|
||||
padding: 8px 16px;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 100px;
|
||||
font-size: 13px;
|
||||
color: var(--text-dim);
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.platform-pill:hover {
|
||||
border-color: var(--border-hover);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* --- Skills --- */
|
||||
.section-skills {
|
||||
/* --- Specs --- */
|
||||
.section-specs {
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.skills-categories {
|
||||
.specs-list {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.spec-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: 120px 1fr;
|
||||
gap: 24px;
|
||||
padding: 24px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.skill-category {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 24px;
|
||||
.spec-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.skill-category h4 {
|
||||
.spec-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--gold);
|
||||
margin-bottom: 14px;
|
||||
color: var(--primary-light);
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.skill-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.skill-tags span {
|
||||
padding: 4px 10px;
|
||||
background: rgba(255, 215, 0, 0.04);
|
||||
border: 1px solid rgba(255, 215, 0, 0.08);
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
.spec-value {
|
||||
font-size: 15px;
|
||||
color: var(--text-dim);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.skill-tags span a {
|
||||
color: inherit;
|
||||
}
|
||||
.skill-tags span a:hover {
|
||||
color: var(--gold);
|
||||
.spec-value a {
|
||||
color: var(--text);
|
||||
border-bottom: 1px solid var(--border-hover);
|
||||
transition: border-color 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
.skill-hub-desc {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.6;
|
||||
margin-top: 12px;
|
||||
.spec-value a:hover {
|
||||
color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
/* --- Install Section --- */
|
||||
|
|
@ -761,12 +705,12 @@ strong {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 215, 0, 0.08);
|
||||
border: 1px solid rgba(255, 215, 0, 0.15);
|
||||
background: rgba(48, 80, 255, 0.1);
|
||||
border: 1px solid rgba(48, 80, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--gold);
|
||||
color: var(--primary-light);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
|
|
@ -847,112 +791,27 @@ strong {
|
|||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* --- Research --- */
|
||||
.research-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.research-card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 24px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.research-card:hover {
|
||||
border-color: var(--border-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.research-card h4 {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.research-card p {
|
||||
font-size: 14px;
|
||||
color: var(--text-dim);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* --- Footer --- */
|
||||
.footer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 80px 0 40px;
|
||||
padding: 40px 0 32px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 12px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.footer-card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.footer-card:hover {
|
||||
border-color: var(--border-hover);
|
||||
background: var(--bg-card-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.footer-card a {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 28px 20px;
|
||||
color: var(--text-dim);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.footer-card a:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.footer-card svg {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.footer-nous-logo {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.footer-skills-icon {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
.footer-copy {
|
||||
text-align: center;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.footer-bottom p {
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.footer-bottom a {
|
||||
.footer-copy a {
|
||||
color: var(--text-dim);
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.footer-bottom a:hover {
|
||||
color: var(--gold);
|
||||
|
||||
.footer-copy a:hover {
|
||||
color: var(--primary-light);
|
||||
}
|
||||
|
||||
/* --- Scroll Animations --- */
|
||||
|
|
@ -973,16 +832,10 @@ strong {
|
|||
@media (max-width: 900px) {
|
||||
.ambient-glow { display: none; }
|
||||
|
||||
.features-grid,
|
||||
.research-grid,
|
||||
.platforms-row,
|
||||
.skills-categories {
|
||||
.features-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.footer-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
|
|
@ -1012,10 +865,14 @@ strong {
|
|||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.nav-links a:not(:last-child):not(:nth-last-child(2)) {
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-hamburger {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* --- Hero --- */
|
||||
.hero {
|
||||
padding: 90px 16px 50px;
|
||||
|
|
@ -1032,8 +889,8 @@ strong {
|
|||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.hero-logo {
|
||||
max-width: 85%;
|
||||
.hero-ascii {
|
||||
font-size: 3.5px;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
|
|
@ -1096,14 +953,16 @@ strong {
|
|||
}
|
||||
|
||||
/* --- Grids → single column --- */
|
||||
.features-grid,
|
||||
.research-grid,
|
||||
.platforms-row,
|
||||
.skills-categories,
|
||||
.footer-grid {
|
||||
.features-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.spec-row {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 6px;
|
||||
padding: 18px 0;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
padding: 20px 18px;
|
||||
}
|
||||
|
|
@ -1121,16 +980,6 @@ strong {
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* --- Tools pills wrap tighter --- */
|
||||
.tools-grid {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tool-pill {
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* --- Terminal demo --- */
|
||||
.terminal-body {
|
||||
font-size: 11px;
|
||||
|
|
@ -1163,59 +1012,15 @@ strong {
|
|||
}
|
||||
|
||||
/* --- Footer --- */
|
||||
.footer-card a {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 50px 0 30px;
|
||||
padding: 32px 0 24px;
|
||||
}
|
||||
|
||||
.footer-bottom p {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* --- Platform pills --- */
|
||||
.platform-pills {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.platform-pill {
|
||||
font-size: 12px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
/* --- Skills --- */
|
||||
.skill-tags {
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.skill-tags span {
|
||||
font-size: 11px;
|
||||
padding: 3px 8px;
|
||||
}
|
||||
|
||||
.skill-hub-desc {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* --- Research cards --- */
|
||||
.research-card {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.research-card h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.research-card p {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Selection --- */
|
||||
::selection {
|
||||
background: rgba(255, 215, 0, 0.2);
|
||||
background: rgba(48, 80, 255, 0.25);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
|
@ -1232,5 +1037,5 @@ strong {
|
|||
border-radius: 3px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--dark-gold);
|
||||
background: var(--primary-dim);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue