You've already forked computing-box
Compare commits
1 Commits
v26.03.01-
...
v26.03.01-
| Author | SHA1 | Date | |
|---|---|---|---|
|
bb8e0c1969
|
BIN
public/images/BitBoxLogo.png
Normal file
BIN
public/images/BitBoxLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
BIN
public/images/Educational_Impact.webp
Normal file
BIN
public/images/Educational_Impact.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 425 KiB |
BIN
public/images/computingbox-concept-illustration.webp
Normal file
BIN
public/images/computingbox-concept-illustration.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
@@ -2,36 +2,54 @@
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
---
|
||||
|
||||
<BaseLayout title="About | Computing:Box">
|
||||
<article style="max-width: 900px; margin: 0 auto;">
|
||||
<div class="card" style="margin-bottom: 40px;">
|
||||
<h1 class="brandName" style="font-size: 32px; color: var(--text); margin-bottom: 16px;">The New Computing:Box Experience</h1>
|
||||
<p style="color: var(--muted); font-size: 18px; line-height: 1.6;">
|
||||
The platform has been rebuilt from the ground up to provide a deeper, more professional simulation environment.
|
||||
We've introduced several key simulators and interface upgrades to support the modern Computing classroom:
|
||||
</p>
|
||||
|
||||
<div class="divider"></div>
|
||||
<BaseLayout title="About - Computing:Box">
|
||||
<article style="max-width: 1100px; margin: 0 auto; width: 100%;">
|
||||
|
||||
<div style="text-align: center; margin-bottom: 60px;">
|
||||
<img src="/images/computing-box-logo.svg" alt="Computing:Box Logo" style="width: 250px; border-radius: 20px; box-shadow: 0 12px 40px rgba(0,0,0,0.5);" />
|
||||
<h1 class="brandName" style="font-size: 42px; margin-top: 20px; color: var(--text);">The New Computing:Box Experience</h1>
|
||||
</div>
|
||||
|
||||
<ul style="list-style: none; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<div class="card" style="margin-bottom: 40px;">
|
||||
<p style="color: var(--muted); font-size: 18px; line-height: 1.6; text-align: center;">
|
||||
Rebuilt from the ground up to provide a deeper, more professional simulation environment for the UK Computing Curriculum.
|
||||
</p>
|
||||
<div class="divider"></div>
|
||||
<ul style="list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px;">
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> New User Interface (Responsive)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Two's Complement Simulator</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Extended Binary Simulator (Custom bit sizes)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Unified Binary Simulator (Unsigned & Two's Complement)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Extended Binary Simulator (Custom sizes)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Unified Binary Simulator</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Extended Hexadecimal Simulator</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Unified Hexadecimal Simulator (GCSE & A Level)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Enhanced Gate Simulator (Truth Table Creator)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Unified Hexadecimal Simulator</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Enhanced Gate Simulator (Truth Tables)</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Compound Gate Simulator</li>
|
||||
<li style="color: var(--text);"><span style="color: var(--accent);">✔</span> Computer Components Simulator</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2 class="brandName" style="font-size: 24px; margin-bottom: 12px;">Educational Impact</h2>
|
||||
<p style="color: var(--muted);">
|
||||
Computing:Box is designed to help students learn computing concepts step by step, using clear visuals and simple interactions.
|
||||
By changing values and seeing results straight away, students can build understanding at their own pace.
|
||||
</p>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-bottom: 40px; align-items: center;">
|
||||
<div class="card">
|
||||
<h2 class="brandName" style="font-size: 24px; color: var(--accent);">From Bit:Box to Computing:Box</h2>
|
||||
<p style="color: var(--muted); line-height: 1.6;">Computing:Box began as Bit:Box, a digital version of a physical Binary Light Box created by Mr Davis. The original device used lightbulbs to show how binary numbers are built.</p>
|
||||
</div>
|
||||
<img src="/images/BitBoxLogo.png" alt="Bit:Box Logo" style="width: 100%; border-radius: 16px; border: 1px solid var(--line);" />
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-bottom: 40px; align-items: center;">
|
||||
<img src="/images/computingbox-concept-illustration.webp" alt="Simulator Illustration" style="width: 100%; border-radius: 16px; border: 1px solid var(--line);" />
|
||||
<div class="card">
|
||||
<h2 class="brandName" style="font-size: 24px; color: var(--accent);">Learning by Doing</h2>
|
||||
<p style="color: var(--muted); line-height: 1.6;">Students can interact with simulations, change values, and see results instantly. This helps them understand how concepts work rather than memorising rules.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center;">
|
||||
<div class="card">
|
||||
<h2 class="brandName" style="font-size: 24px; color: var(--accent);">Educational Impact</h2>
|
||||
<p style="color: var(--muted); line-height: 1.6;">Designed for use in lessons, independent study, and revision, helping students build confidence as they explore how computers work.</p>
|
||||
</div>
|
||||
<img src="/images/Educational_Impact.webp" alt="Classroom Impact" style="width: 100%; border-radius: 16px; border: 1px solid var(--line);" />
|
||||
</div>
|
||||
</article>
|
||||
</BaseLayout>
|
||||
@@ -4,13 +4,17 @@
|
||||
(() => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
const viewport = document.getElementById("viewport");
|
||||
const wireLayer = document.getElementById("wireLayer");
|
||||
const internalLayer = document.getElementById("wireLayerInternal");
|
||||
const externalLayer = document.getElementById("wireLayerExternal");
|
||||
const specsContainer = document.getElementById("buildSpecsContainer");
|
||||
const toolboxGrid = document.getElementById("toolboxGrid");
|
||||
const btnClearBoard = document.getElementById("btnClearBoard");
|
||||
const toolboxToggle = document.getElementById("toolboxToggle");
|
||||
const pcPage = document.getElementById("pcPage");
|
||||
|
||||
// Parts defined as "Outside the Chassis"
|
||||
const EXTERNAL_TYPES = ['MONITOR', 'KEYBOARD', 'MOUSE', 'WEBCAM', 'SPEAKER', 'MIC', 'PRINTER'];
|
||||
|
||||
/* --- Extensive PC Component Library --- */
|
||||
const PC_PARTS = {
|
||||
'CASE': {
|
||||
@@ -98,17 +102,11 @@
|
||||
panY = mouseY - (mouseY - panY) * (newZoom / zoom);
|
||||
zoom = newZoom; updateViewport();
|
||||
}
|
||||
function getPortCoords(nodeId, portDataAttr) {
|
||||
const node = nodes[nodeId];
|
||||
if (!node || !node.el) return {x:0, y:0};
|
||||
const portEl = node.el.querySelector(`[data-port="${portDataAttr}"]`);
|
||||
if (!portEl) return {x:0, y:0};
|
||||
const wsRect = workspace.getBoundingClientRect();
|
||||
const portRect = portEl.getBoundingClientRect();
|
||||
return {
|
||||
x: (portRect.left - wsRect.left - panX + portRect.width / 2) / zoom,
|
||||
y: (portRect.top - wsRect.top - panY + portRect.height / 2) / zoom
|
||||
};
|
||||
function getPortCoords(nodeId, portId) {
|
||||
const n = nodes[nodeId];
|
||||
const pEl = n.el.querySelector(`[data-port="${portId}"]`);
|
||||
const r = pEl.getBoundingClientRect(), w = workspace.getBoundingClientRect();
|
||||
return { x: (r.left - w.left - panX) / zoom, y: (r.top - w.top - panY) / zoom };
|
||||
}
|
||||
function drawBezier(x1, y1, x2, y2) {
|
||||
const cpDist = Math.abs(x2 - x1) * 0.6 + 20;
|
||||
@@ -117,17 +115,22 @@
|
||||
|
||||
/* --- Rendering --- */
|
||||
function renderWires() {
|
||||
let svgHTML = '';
|
||||
connections.forEach(conn => {
|
||||
const from = getPortCoords(conn.fromNode, conn.fromPort);
|
||||
const to = getPortCoords(conn.toNode, conn.toPort);
|
||||
const isSelected = conn.id === selectedWireId;
|
||||
svgHTML += `<path class="pb-wire active ${isSelected ? 'selected' : ''}" d="${drawBezier(from.x, from.y, to.x, to.y)}" data-conn-id="${conn.id}" />`;
|
||||
let intHtml = '', extHtml = '';
|
||||
connections.forEach(c => {
|
||||
const fromNode = nodes[c.fN];
|
||||
const toNode = nodes[c.tN];
|
||||
if (!fromNode || !toNode) return;
|
||||
|
||||
const p1 = getPortCoords(c.fN, c.fP);
|
||||
const p2 = getPortCoords(c.tN, c.tP);
|
||||
const path = `<path class="pb-wire active" d="M ${p1.x} ${p1.y} C ${p1.x+60} ${p1.y}, ${p2.x-60} ${p2.y}, ${p2.x} ${p2.y}" />`;
|
||||
|
||||
// Determine if cable is Internal (under panel) or External (on top)
|
||||
(EXTERNAL_TYPES.includes(fromNode.type) || EXTERNAL_TYPES.includes(toNode.type)) ? extHtml += path : intHtml += path;
|
||||
});
|
||||
if (wiringStart && tempWirePath) {
|
||||
svgHTML += `<path class="pb-wire pb-wire-temp" d="${drawBezier(wiringStart.x, wiringStart.y, tempWirePath.x, tempWirePath.y)}" />`;
|
||||
}
|
||||
wireLayer.innerHTML = svgHTML;
|
||||
internalLayer.innerHTML = intHtml;
|
||||
externalLayer.innerHTML = extHtml;
|
||||
evaluateBuild();
|
||||
}
|
||||
|
||||
function updateNodePositions() {
|
||||
@@ -145,67 +148,10 @@
|
||||
|
||||
/* --- Seven-Segment Diagnostics Engine --- */
|
||||
function evaluateBuild() {
|
||||
if(!specsContainer) return;
|
||||
|
||||
let hasCase = false, hasMB = false, hasCPU = false, hasCooler = false, hasRAM = false, hasPSU = false;
|
||||
let hasStorage = false, hasGPU = false;
|
||||
let mbPwr = false, gpuPwr = false;
|
||||
let usbCount = 0, dispConn = false, audConn = false;
|
||||
|
||||
let caseNode = Object.values(nodes).find(n => n.type === 'CASE');
|
||||
let mbNode = Object.values(nodes).find(n => n.type === 'MB');
|
||||
|
||||
if (caseNode) {
|
||||
hasCase = true;
|
||||
if (caseNode.slots['MB1']) hasMB = true;
|
||||
if (caseNode.slots['PSU1']) hasPSU = true;
|
||||
if (caseNode.slots['HDD1'] || caseNode.slots['HDD2'] || caseNode.slots['SATA_SSD1'] || caseNode.slots['SATA_SSD2']) hasStorage = true;
|
||||
} else if (mbNode) {
|
||||
hasMB = true; // Motherboard exists outside case
|
||||
}
|
||||
|
||||
if (mbNode) {
|
||||
if (mbNode.slots['CPU1']) hasCPU = true;
|
||||
if (mbNode.slots['COOLER1']) hasCooler = true;
|
||||
if (mbNode.slots['RAM1'] || mbNode.slots['RAM2'] || mbNode.slots['RAM3'] || mbNode.slots['RAM4']) hasRAM = true;
|
||||
if (mbNode.slots['PCIE1'] || mbNode.slots['PCIE2']) hasGPU = true;
|
||||
if (mbNode.slots['M2_1'] || mbNode.slots['M2_2']) hasStorage = true;
|
||||
}
|
||||
|
||||
// Check Cables
|
||||
connections.forEach(c => {
|
||||
let n1 = nodes[c.fromNode], n2 = nodes[c.toNode];
|
||||
if(!n1 || !n2) return;
|
||||
let types = [n1.type, n2.type];
|
||||
|
||||
if(types.includes('MB') && types.includes('PSU')) mbPwr = true;
|
||||
if(types.includes('GPU') && types.includes('PSU')) gpuPwr = true;
|
||||
if(types.includes('MB') && ['KEYBOARD','MOUSE','WEBCAM','MIC','PRINTER'].some(t => types.includes(t))) usbCount++;
|
||||
if(types.includes('MB') && types.includes('SPEAKER')) audConn = true;
|
||||
if((types.includes('MB') || types.includes('GPU')) && types.includes('MONITOR')) dispConn = true;
|
||||
});
|
||||
|
||||
const isBootable = (hasMB && hasCPU && hasCooler && hasRAM && hasPSU && hasStorage && mbPwr && (hasGPU ? gpuPwr : true) && dispConn);
|
||||
|
||||
specsContainer.innerHTML = `
|
||||
<div class="diag-cat">Core System</div>
|
||||
<div class="diag-row"><span>CHASSIS</span><span style="color: ${hasCase ? '#28f07a' : '#ff5555'}">${hasCase ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>MOTHERBOARD</span><span style="color: ${hasMB ? '#28f07a' : '#ff5555'}">${hasMB ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>CPU</span><span style="color: ${hasCPU ? '#28f07a' : '#ff5555'}">${hasCPU ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>COOLING</span><span style="color: ${hasCooler ? '#28f07a' : '#ff5555'}">${hasCooler ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>MEMORY</span><span style="color: ${hasRAM ? '#28f07a' : '#ff5555'}">${hasRAM ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>POWER SPLY</span><span style="color: ${hasPSU ? '#28f07a' : '#ff5555'}">${hasPSU ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-cat">Connections</div>
|
||||
<div class="diag-row"><span>MB POWER</span><span style="color: ${mbPwr ? '#28f07a' : '#ff5555'}">${mbPwr ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>STORAGE</span><span style="color: ${hasStorage ? '#28f07a' : '#ff5555'}">${hasStorage ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>GPU POWER</span><span style="color: ${!hasGPU ? '#888' : (gpuPwr ? '#28f07a' : '#ff5555')}">${!hasGPU ? 'N/A' : (gpuPwr ? 'OK' : 'ERR')}</span></div>
|
||||
<div class="diag-row"><span>DISPLAY</span><span style="color: ${dispConn ? '#28f07a' : '#ff5555'}">${dispConn ? 'OK' : 'ERR'}</span></div>
|
||||
<div class="diag-row"><span>USB DEVS</span><span style="color: #55aaff">${usbCount}</span></div>
|
||||
<hr style="border-color: rgba(255,255,255,0.1); margin: 12px 0 8px 0;">
|
||||
<div style="text-align:center; font-size: 28px; color: ${isBootable ? '#28f07a' : '#ff5555'}; font-family: var(--bit-font); letter-spacing: 2px;">
|
||||
${isBootable ? 'BOOTING...' : 'HALTED'}
|
||||
</div>
|
||||
`;
|
||||
const hasMB = Object.values(nodes).some(n => n.type === 'MB' && n.snappedTo);
|
||||
const hasCPU = Object.values(nodes).some(n => n.type === 'CPU' && n.snappedTo);
|
||||
const boot = hasMB && hasCPU && connections.some(c => nodes[c.fN].type === 'MONITOR' || nodes[c.tN].type === 'MONITOR');
|
||||
workspace.classList.toggle('system-running', boot);
|
||||
}
|
||||
|
||||
/* --- Node Creation & Snapping --- */
|
||||
@@ -250,16 +196,12 @@
|
||||
evaluateBuild();
|
||||
}
|
||||
|
||||
// Recursive movement to handle nested snaps (MB inside CASE inside ...)
|
||||
/* --- Movement & Snap Logic (Restored from your Verified Working Script) --- */
|
||||
function moveNodeRecursive(nodeId, dx, dy) {
|
||||
const n = nodes[nodeId];
|
||||
if(!n) return;
|
||||
const n = nodes[nodeId]; if(!n) return;
|
||||
n.x += dx; n.y += dy;
|
||||
if(n.slots) {
|
||||
Object.keys(n.slots).forEach(k => {
|
||||
if(typeof n.slots[k] === 'string') moveNodeRecursive(n.slots[k], dx, dy);
|
||||
});
|
||||
}
|
||||
if(n.slots) { Object.keys(n.slots).forEach(k => { if(typeof n.slots[k] === 'string') moveNodeRecursive(n.slots[k], dx, dy); }); }
|
||||
if(n.el) { n.el.style.left = n.x + 'px'; n.el.style.top = n.y + 'px'; }
|
||||
}
|
||||
|
||||
/* --- Inspect Mode --- */
|
||||
|
||||
@@ -23,58 +23,75 @@
|
||||
--text: #e8e8ee;
|
||||
--muted: #a9acb8;
|
||||
--line: rgba(255,255,255,.10);
|
||||
|
||||
--ui-font: "Inter", system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
|
||||
--num-font: "DSEG7Classic", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
||||
--accent: #28f07a;
|
||||
--ui-font: "Inter", system-ui, -apple-system, sans-serif;
|
||||
--bit-font: "SevenSegment", monospace;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html, body { height: 100%; }
|
||||
body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--ui-font); display: flex; flex-direction: column; }
|
||||
html, body { height: 100%; margin: 0; }
|
||||
body { background: var(--bg); color: var(--text); font-family: var(--ui-font); display: flex; flex-direction: column; }
|
||||
|
||||
/* --- BASE LAYOUT --- */
|
||||
.siteNav { position: sticky; top: 0; z-index: 50; height: var(--nav-h); background: rgba(0,0,0,.10); border-bottom: 1px solid var(--line); backdrop-filter: blur(8px); }
|
||||
.navInner { height: 100%; max-width: 1400px; margin: 0 auto; padding: 0 20px; display: flex; align-items: center; justify-content: space-between; gap: 24px; }
|
||||
/* --- SITE NAVIGATION (Fixed Height) --- */
|
||||
.siteNav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 500;
|
||||
height: var(--nav-h);
|
||||
background: rgba(45, 44, 56, 0.95);
|
||||
border-bottom: 1px solid var(--line);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.navInner {
|
||||
height: 100%;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--text); }
|
||||
.brandLogo { width: 2.5em; height: 2.5em; image-rendering: pixelated; }
|
||||
.brandLogo { width: 32px; height: 32px; }
|
||||
.brandName { letter-spacing: .12em; font-weight: 900; font-size: 18px; }
|
||||
.navLinks { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
|
||||
.navLinks a { color: var(--muted); text-decoration: none; font-weight: 800; letter-spacing: .12em; font-size: 16px; }
|
||||
.navLinks a:hover, .navLinks a.active { color: #e8e8ee; }
|
||||
|
||||
.pageWrap { flex: 1; max-width: 1400px; margin: 0 auto; padding: 0 20px 40px; width: 100%; display: flex; flex-direction: column; }
|
||||
.siteFooter { border-top: 1px solid var(--line); background: rgba(0,0,0,.08); }
|
||||
.footerInner { max-width: 1400px; margin: 0 auto; padding: 18px 20px; color: var(--muted); font-size: 12px; letter-spacing: .08em; display: flex; flex-direction: column; gap: 6px; }
|
||||
.navLinks { display: flex; gap: 24px; }
|
||||
.navLinks a {
|
||||
color: var(--muted);
|
||||
text-decoration: none;
|
||||
font-weight: 800;
|
||||
font-size: 14px;
|
||||
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
/* --- SHARED UI COMPONENTS (Used by ALL Simulators) --- */
|
||||
.divider { height: 1px; background: rgba(255,255,255,.08); margin: 16px 0 16px; }
|
||||
/* Active Link Fix */
|
||||
.navLinks a.active,
|
||||
.navLinks a:hover {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.bulb { width: 44px; height: 44px; color: rgba(255,255,255,.15); margin-bottom: 8px; flex-shrink: 0; transition: 0.2s ease; background: transparent; display: flex; align-items: center; justify-content: center; }
|
||||
.bulb svg { width: 100%; height: 100%; display: block; }
|
||||
.bulb.on { color: #ffd86b !important; filter: drop-shadow(0 0 14px rgba(255, 216, 107, 1)) !important; }
|
||||
.bulb.on svg { fill: #ffd86b !important; }
|
||||
/* --- LAYOUT --- */
|
||||
.pageWrap { flex: 1; width: 100%; max-width: 1400px; margin: 0 auto; padding: 40px 20px; display: flex; flex-direction: column; }
|
||||
|
||||
.switch { position: relative; width: 56px; height: 28px; display: inline-block; }
|
||||
.switch input { display: none; }
|
||||
.slider { position: absolute; inset: 0; background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.14); border-radius: 999px; transition: .2s ease; }
|
||||
.slider::before { content: ""; position: absolute; width: 22px; height: 22px; left: 3px; top: 2px; background: rgba(255,255,255,.92); border-radius: 999px; transition: .2s ease; pointer-events: none; }
|
||||
.switch input:checked + .slider { background: rgba(40,240,122,.25); border-color: rgba(40,240,122,.30); }
|
||||
.switch input:checked + .slider::before { transform: translateX(28px); }
|
||||
/* --- FOOTER (Centered Links at Top) --- */
|
||||
.siteFooter { background: rgba(0,0,0,.08); border-top: 1px solid var(--line); padding: 40px 0; }
|
||||
.footerInner {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.footerLegal { margin-bottom: 8px; }
|
||||
.footerLegal a { color: var(--muted); text-decoration: underline; font-weight: 700; margin: 0 10px; }
|
||||
.footerLegal a:hover { color: #fff; }
|
||||
|
||||
.card { background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.10); border-radius: 16px; padding: 16px; backdrop-filter: blur(10px); }
|
||||
.cardTitle { font-family: var(--bit-font); font-weight: 900; letter-spacing: .14em; text-transform: uppercase; font-size: 18px; color: rgba(232,232,238,.9); margin-bottom: 12px; }
|
||||
.hint { font-family: var(--bit-font); font-size: 13px; letter-spacing: .08em; text-transform: uppercase; color: rgba(232,232,238,.55); margin-top: 10px; line-height: 1.35; }
|
||||
|
||||
.btn { border: 1px solid rgba(255,255,255,.12); background: rgba(255,255,255,.06); color: rgba(232,232,238,.92); border-radius: 12px; padding: 10px 12px; font-family: var(--bit-font); font-size: 14px; letter-spacing: .12em; text-transform: uppercase; font-weight: 900; cursor: pointer; }
|
||||
.btn:hover { border-color: rgba(255,255,255,.22); }
|
||||
.btnAccent { background: rgba(40,240,122,.12); border-color: rgba(40,240,122,.22); }
|
||||
.btnAccent:hover { border-color: rgba(40,240,122,.35); }
|
||||
.btnHalf { width: calc(50% - 6px); }
|
||||
.btnWide { width: 100%; }
|
||||
.btnReset { color: rgba(232,232,238,.95); }
|
||||
.btnReset:hover { background: rgba(255,80,80,.18); border-color: rgba(255,80,80,.35); }
|
||||
|
||||
.toolboxToggle { position: fixed; top: var(--toolbox-toggle-top, calc(var(--nav-h) + 16px)); right: 22px; z-index: 90; display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: 12px; border: 1px solid rgba(255,255,255,.12); background: rgba(0,0,0,.15); backdrop-filter: blur(8px); color: rgba(232,232,238,.95); font-family: var(--bit-font); font-weight: 800; font-size: 16px; letter-spacing: .12em; text-transform: uppercase; cursor: pointer; }
|
||||
.toolboxIcon { font-size: 20px; filter: drop-shadow(0 0 8px rgba(255,105,180,.35)); }
|
||||
.toolboxToggle:hover { border-color: rgba(255,255,255,.22); }
|
||||
/* Shared UI Components */
|
||||
.card { background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.10); border-radius: 16px; padding: 24px; backdrop-filter: blur(10px); }
|
||||
.divider { height: 1px; background: rgba(255,255,255,.08); margin: 16px 0 16px; }
|
||||
Reference in New Issue
Block a user