From 1ec16aecb37e9b1c7f4aca103b1b4c7025c92008 Mon Sep 17 00:00:00 2001 From: Alexander Lyall Date: Sun, 1 Mar 2026 18:16:42 +0000 Subject: [PATCH] Final Version 2.0 Beta release Signed-off-by: Alexander Lyall --- README.md | 15 ++- dist/binary/index.html | 5 +- dist/hexadecimal/index.html | 5 +- dist/index.html | 5 +- src/layouts/BaseLayout.astro | 12 +- src/pages/copyright.astro | 14 +- src/pages/pc-builder.astro | 4 +- src/scripts/pcBuilder.js | 124 ++++++++++++----- src/styles/global.css | 249 ++++++++++++++++++++++++++--------- 9 files changed, 308 insertions(+), 125 deletions(-) diff --git a/README.md b/README.md index fbc07a0..b8242a9 100644 --- a/README.md +++ b/README.md @@ -28,18 +28,19 @@ An evolution of Bit:Box & CS:Box to incorporate different elements of the UK Com - [X] XNOR Gate Simulator ### Wave 3 CS:Box Features (Spring 2026) -- [ ] New User Interface (Responsive) +- [X] New User Interface (Responsive) - [X] Two's Compliment Simulator - [X] Extended Binary Simulator (Custom bit sizes) - [X] Unified Binary Simulator (Unsigned & Two's Completment combined) -- [ ] Extended Hexadecimal Simulator -- [ ] Unified Hexadecimal Simulator (For GCSE & A Level Specification) -- [ ] Enhanced Gate Simulator (Truth Table Creator) -- [ ] Compound Gate Simulator -- [ ] Computer Components Simulator +- [X] Extended Hexadecimal Simulator +- [X] Unified Hexadecimal Simulator (For GCSE & A Level Specification) +- [X] Enhanced Gate Simulator (Truth Table Creator) +- [X] Compound Gate Simulator +- [X] Computer Components Simulator - Beta Available ## Version 1.0 Release Date: 1st September 2025 -## Version 2.0 Release Date (Goal): 1st May 2026 +## Version 2.0 Release Date (Beta): 1st March 2026 +## Version 2.0 Release Date (Full Release): 1st May 2026 Shield: [![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] diff --git a/dist/binary/index.html b/dist/binary/index.html index e72913a..8b1520c 100644 --- a/dist/binary/index.html +++ b/dist/binary/index.html @@ -13,8 +13,7 @@ var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); - +
Denary
0
Binary
00000000
Computer Science Concept Simulators
© 2026 Computing:Box • Created with ♥ by Alexander Lyall
Copyright Notice • -Legal Code
\ No newline at end of file +
Bit width
Bits
Custom Number
Random runs briefly then stops automatically.
Tools
Copyright Notice Legal Code
Computer Science Concept Simulators
© 2026 Computing:Box • Created with ♥ by Mr A Lyall
\ No newline at end of file diff --git a/dist/hexadecimal/index.html b/dist/hexadecimal/index.html index 71344d9..dfb3c34 100644 --- a/dist/hexadecimal/index.html +++ b/dist/hexadecimal/index.html @@ -13,8 +13,7 @@ var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); - +
Denary
0
Hexadecimal
00
Binary
00000000
Computer Science Concept Simulators
© 2026 Computing:Box • Created with ♥ by Alexander Lyall
Copyright Notice • -Legal Code
\ No newline at end of file +
Digit width
Digits
Custom Number
Random runs briefly then stops automatically.
Tools
Copyright Notice Legal Code
Computer Science Concept Simulators
© 2026 Computing:Box • Created with ♥ by Mr A Lyall
\ No newline at end of file diff --git a/dist/index.html b/dist/index.html index 2065b3f..9674850 100644 --- a/dist/index.html +++ b/dist/index.html @@ -13,7 +13,6 @@ var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); -

Version 2.0 Now Live

Understand Computing concepts better.

+

Version 2.0 Now Live

Understand Computing concepts better.

Interactive simulators for Binary, Hexadecimal, Logic Gates, and Computer Components designed for the UK curriculum. -

Computing Box Logo
Computer Science Concept Simulators
© 2026 Computing:Box • Created with ♥ by Alexander Lyall
\ No newline at end of file +

Computing Box Logo
Copyright Notice Legal Code
Computer Science Concept Simulators
© 2026 Computing:Box • Created with ♥ by Mr A Lyall
\ No newline at end of file diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index cf04c9d..d0e14ec 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -54,13 +54,13 @@ const { title = "Computing:Box" } = Astro.props;
-
+
+
Computer Science Concept Simulators
-
© {new Date().getFullYear()} Computing:Box • Created with ♥ by Alexander Lyall
- +
© {new Date().getFullYear()} Computing:Box • Created with ♥ by Mr A Lyall
diff --git a/src/pages/copyright.astro b/src/pages/copyright.astro index 2b6f65f..636e6d1 100644 --- a/src/pages/copyright.astro +++ b/src/pages/copyright.astro @@ -5,11 +5,7 @@ import BaseLayout from "../layouts/BaseLayout.astro";

Copyright Notice

-

- Computing:Box - © 2024 by Alexander Lyall is licensed under - Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International. -

+ Computing:Box © 2024 by Mr A Lyall is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
@@ -22,9 +18,11 @@ import BaseLayout from "../layouts/BaseLayout.astro";

Under the following terms:

    -
  • Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
  • -
  • NonCommercial — You may not use the material for commercial purposes.
  • -
  • ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
  • +
  • Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
  • +
  • NonCommercial — You may not use the material for commercial purposes.
  • +
  • ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
  • + +
  • No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
\ No newline at end of file diff --git a/src/pages/pc-builder.astro b/src/pages/pc-builder.astro index 5f68a10..6f3499f 100644 --- a/src/pages/pc-builder.astro +++ b/src/pages/pc-builder.astro @@ -26,9 +26,7 @@ import "../styles/pc-builder.css";
- - - +
diff --git a/src/scripts/pcBuilder.js b/src/scripts/pcBuilder.js index 087058a..b23e2b2 100644 --- a/src/scripts/pcBuilder.js +++ b/src/scripts/pcBuilder.js @@ -4,17 +4,13 @@ (() => { const workspace = document.getElementById("workspace"); const viewport = document.getElementById("viewport"); - const internalLayer = document.getElementById("wireLayerInternal"); - const externalLayer = document.getElementById("wireLayerExternal"); + const wireLayer = document.getElementById("wireLayer"); 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': { @@ -102,11 +98,17 @@ panY = mouseY - (mouseY - panY) * (newZoom / zoom); zoom = newZoom; updateViewport(); } - 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 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 drawBezier(x1, y1, x2, y2) { const cpDist = Math.abs(x2 - x1) * 0.6 + 20; @@ -115,22 +117,17 @@ /* --- Rendering --- */ function renderWires() { - 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 = ``; - - // 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; + 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 += ``; }); - internalLayer.innerHTML = intHtml; - externalLayer.innerHTML = extHtml; - evaluateBuild(); + if (wiringStart && tempWirePath) { + svgHTML += ``; + } + wireLayer.innerHTML = svgHTML; } function updateNodePositions() { @@ -148,10 +145,67 @@ /* --- Seven-Segment Diagnostics Engine --- */ function evaluateBuild() { - 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); + 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 = ` +
Core System
+
CHASSIS${hasCase ? 'OK' : 'ERR'}
+
MOTHERBOARD${hasMB ? 'OK' : 'ERR'}
+
CPU${hasCPU ? 'OK' : 'ERR'}
+
COOLING${hasCooler ? 'OK' : 'ERR'}
+
MEMORY${hasRAM ? 'OK' : 'ERR'}
+
POWER SPLY${hasPSU ? 'OK' : 'ERR'}
+
Connections
+
MB POWER${mbPwr ? 'OK' : 'ERR'}
+
STORAGE${hasStorage ? 'OK' : 'ERR'}
+
GPU POWER${!hasGPU ? 'N/A' : (gpuPwr ? 'OK' : 'ERR')}
+
DISPLAY${dispConn ? 'OK' : 'ERR'}
+
USB DEVS${usbCount}
+
+
+ ${isBootable ? 'BOOTING...' : 'HALTED'} +
+ `; } /* --- Node Creation & Snapping --- */ @@ -196,12 +250,16 @@ evaluateBuild(); } -/* --- Movement & Snap Logic (Restored from your Verified Working Script) --- */ + // Recursive movement to handle nested snaps (MB inside CASE inside ...) 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.el) { n.el.style.left = n.x + 'px'; n.el.style.top = n.y + 'px'; } + if(n.slots) { + Object.keys(n.slots).forEach(k => { + if(typeof n.slots[k] === 'string') moveNodeRecursive(n.slots[k], dx, dy); + }); + } } /* --- Inspect Mode --- */ diff --git a/src/styles/global.css b/src/styles/global.css index c02a5bb..10a39a9 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -25,73 +25,204 @@ --line: rgba(255,255,255,.10); --accent: #28f07a; --ui-font: "Inter", system-ui, -apple-system, sans-serif; - --bit-font: "SevenSegment", monospace; + --bit-font: "SevenSegment", monospace; + --num-font: "DSEG7Classic" } * { box-sizing: border-box; } -html, body { height: 100%; margin: 0; } -body { background: var(--bg); color: var(--text); font-family: var(--ui-font); display: flex; flex-direction: column; } +html, body { height: 100%; } +body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--ui-font); display: flex; flex-direction: column; } -/* --- 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; -} +/* --- 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); margin-bottom: 25px; } +.navInner { height: 90px; max-width: 1400px; margin: 0 auto; padding: 0 20px; display: flex; align-items: center; justify-content: space-between; gap: 24px; } .brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--text); } -.brandLogo { width: 32px; height: 32px; } +.brandLogo { width: 2.5em; height: 2.5em; image-rendering: pixelated; } .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; } -.navLinks { display: flex; gap: 24px; } -.navLinks a { - color: var(--muted); - text-decoration: none; - font-weight: 800; - font-size: 14px; - - transition: color 0.2s; +.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; } + +/* --- APP LAYOUT --- */ +.binaryPage { + --toolbox-w: 360px; + --toolbox-gap: 22px; + --toolbox-toggle-top: calc(var(--nav-h) + 16px); + --toolbox-top: calc(var(--toolbox-toggle-top) + 60px); + position: relative; padding-top: 16px; flex: 1; display: flex; flex-direction: column; +} +.binaryPage:not(.toolboxCollapsed) { padding-right: calc(var(--toolbox-w) + var(--toolbox-gap)); } +.binaryPage.toolboxCollapsed { padding-right: 0; } +.topGrid { display: flex; align-items: stretch; gap: 28px; flex: 1; } +.leftCol { flex: 1 1 auto; min-width: 0; container-type: inline-size; display: flex; flex-direction: column; } + +/* --- READOUT FORMATTING --- */ +.readoutContainer { display: flex; align-items: center; justify-content: center; gap: 64px; width: 100%; } +.readout { display: flex; flex-direction: column; align-items: center; gap: 16px; padding-top: 4px; } +.readoutBlock { display: flex; flex-direction: column; align-items: center; gap: 8px; } +.label { font-family: var(--bit-font); letter-spacing: .14em; text-transform: uppercase; font-size: 18px; opacity: .75; margin: 0; } +.num { font-family: var(--num-font); color: #28f07a; text-shadow: 0 0 18px rgba(40,240,122,.35); letter-spacing: 2px; } + +.denaryValue, .hexValue, .binaryValue { display: flex; gap: 16px; justify-content: center; white-space: pre-wrap; text-align: center; margin: 0; line-height: 1; } +.denaryValue { font-size: 56px; } +.hexValue { font-size: 48px; } +.binaryValue { font-size: 40px; } +.divider { height: 1px; background: rgba(255,255,255,.08); margin: 16px 0 16px; } + +/* --- GRIDS & BITS --- */ +.bitsWrap { width: 100%; } +.bitsGrid { --cols: 8; display: grid; grid-template-columns: repeat(var(--cols), minmax(92px, 1fr)); gap: 26px 22px; align-items: start; justify-items: center; } +.bitsGrid.bitsFew { justify-content: center; } +.bit { width: 100%; max-width: 140px; display: flex; flex-direction: column; align-items: center; gap: 8px; container-type: inline-size; } +.bitVal { font-family: var(--bit-font); font-size: min(32px, calc(140cqw / var(--len, 1))); letter-spacing: 2px; color: rgba(232,232,238,.85); white-space: nowrap; line-height: 1; } + +.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; } + +.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); } + +/* --- HEXADECIMAL --- */ +.hexGrid { --cols: 4; display: grid; grid-template-columns: repeat(var(--cols), minmax(160px, 1fr)); gap: 32px 20px; align-items: start; justify-items: center; width: 100%; } +.hexGrid.bitsFew { justify-content: center; } +.hexCol { display: flex; flex-direction: column; align-items: center; width: 100%; } + +/* --- HEX COLOURS SPECIFIC --- */ +.colorGroupWrap { display: flex; flex-wrap: nowrap; gap: 16px; justify-content: center; width: 100%; } +.colorGroup { display: flex; gap: 12px; padding: 12px; background: rgba(255,255,255,.02); border-radius: 20px; border: 1px solid rgba(255,255,255,.05); flex: 0 1 auto; min-width: 0; } +.colorPreviewSide { display: flex; gap: 24px; align-items: center; justify-content: center; } +.colorBoxWrap { display: flex; flex-direction: column; align-items: center; gap: 8px; } +.colorBox { width: 60px; height: 60px; border-radius: 12px; border: 2px solid rgba(255,255,255,.15); box-shadow: 0 4px 16px rgba(0,0,0,.4); background-color: #000000; transition: background-color 0.2s ease; } +.colorBoxLabel { font-family: var(--ui-font); font-size: 11px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); } + +.text-red { color: #ff5555 !important; text-shadow: 0 0 18px rgba(255,85,85,.35) !important; } +.text-green { color: #28f07a !important; text-shadow: 0 0 18px rgba(40,240,122,.35) !important; } +.text-blue { color: #55aaff !important; text-shadow: 0 0 18px rgba(85,170,255,.35) !important; } + +/* HEX CARD */ +.hexCard { background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08); border-radius: 16px; padding: 16px 14px; display: flex; flex-direction: column; align-items: center; gap: 16px; width: 100%; max-width: 190px; flex: 0 1 auto; min-width: 0; box-shadow: 0 4px 24px rgba(0,0,0,.2); backdrop-filter: blur(10px); } +.hexCardButtons { display: flex; gap: 10px; } +.hexCardBtn { width: 38px; height: 38px; border-radius: 10px; border: 1px solid rgba(255,255,255,.12); font-family: var(--bit-font); font-size: 16px; font-weight: 900; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; color: rgba(232,232,238,.92); transition: all 0.2s ease; } +.hexCardBtn.inc { background: rgba(40,240,122,.15); border-color: rgba(40,240,122,.25); } +.hexCardBtn.inc:hover { background: rgba(40,240,122,.25); border-color: rgba(40,240,122,.4); } +.hexCardBtn.dec { background: rgba(255,80,80,.18); border-color: rgba(255,80,80,.25); } +.hexCardBtn.dec:hover { background: rgba(255,80,80,.28); border-color: rgba(255,80,80,.4); } +.hexDigitDisplay { font-family: var(--num-font); font-size: 48px; color: #28f07a; text-shadow: 0 0 18px rgba(40,240,122,.35); line-height: 1; } +.hexNibbleRow { display: flex; gap: 10px; justify-content: center; width: 100%; } +.hexNibbleBit { display: flex; flex-direction: column; align-items: center; gap: 6px; } +.hexNibbleBulb { width: 32px !important; height: 32px !important; margin-bottom: 2px !important; } +.hexNibbleLabel { font-family: var(--bit-font); font-size: 24px; color: rgba(232,232,238,.6); } +.hexColWeight { font-family: var(--bit-font); font-size: 40px; color: rgba(232,232,238,.6); margin-top: 14px; } + + +/* --- TOOLBOX --- */ +.toolboxToggle { position: fixed; top: var(--toolbox-toggle-top); 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); } +.panelCol { position: fixed; top: var(--toolbox-top); right: 22px; width: var(--toolbox-w); z-index: 80; display: flex; flex-direction: column; gap: 16px; transform: translateX(0); opacity: 1; transition: transform 420ms cubic-bezier(.2,.9,.2,1), opacity 220ms ease; } +.binaryPage.toolboxCollapsed .panelCol { transform: translateX(calc(var(--toolbox-w) + 32px)); opacity: 0; pointer-events: none; } +.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; } +.toggleRow { display: flex; align-items: center; justify-content: space-between; gap: 12px; } +.toggleLabel { font-family: var(--bit-font); font-size: 16px; letter-spacing: .12em; text-transform: uppercase; white-space: nowrap; color: var(--muted); transition: color 0.2s, text-shadow 0.2s; } +.toggleLabel.activeMode { color: #28f07a; text-shadow: 0 0 12px rgba(40,240,122,.45); } +.subCard { margin-top: 12px; padding: 12px; border-radius: 14px; border: 1px solid rgba(255,255,255,.10); background: rgba(0,0,0,.12); } +.subTitle { font-family: var(--bit-font); font-weight: 900; letter-spacing: .14em; text-transform: uppercase; font-size: 16px; margin-bottom: 10px; opacity: .85; } +.bitWidthRow { display: flex; align-items: center; gap: 10px; } +.miniBtn { width: 44px; height: 44px; border-radius: 12px; border: 1px solid rgba(255,255,255,.12); background: rgba(255,255,255,.06); color: rgba(232,232,238,.9); font-family: var(--bit-font); font-weight: 900; font-size: 22px; cursor: pointer; } +.miniBtn:hover { border-color: rgba(255,255,255,.22); } +.bitInputWrap { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 10px; border-radius: 12px; border: 1px solid rgba(255,255,255,.10); background: rgba(255,255,255,.04); padding: 10px 12px; } +.bitInputLabel { font-family: var(--bit-font); font-size: 16px; letter-spacing: .12em; text-transform: uppercase; opacity: .7; } +.bitInput { width: 70px; text-align: right; font-family: var(--num-font); font-size: 28px; letter-spacing: 2px; color: #28f07a; background: transparent; border: none; outline: none; } +.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%; } +.controlsRow { display: flex; gap: 12px; margin-bottom: 12px; } +.toolRowCentered { display: flex; justify-content: center; gap: 10px; margin-bottom: 10px; } +.toolBtn { width: 46px; height: 46px; border-radius: 12px; border: 1px solid rgba(255,255,255,.12); background: rgba(255,255,255,.06); color: rgba(232,232,238,.92); font-family: var(--bit-font); font-size: 16px; font-weight: 900; cursor: pointer; } +.toolDec { background: rgba(255,80,80,.20); border-color: rgba(255,80,80,.25); } +.toolInc { background: rgba(40,240,122,.18); border-color: rgba(40,240,122,.25); } +.btnReset { color: rgba(232,232,238,.95); } +.btnReset:hover { background: rgba(255,80,80,.18); border-color: rgba(255,80,80,.35); } + +/* === CONTAINER QUERIES === */ +@container (max-width: 1050px) { + .readoutContainer { gap: 40px; } + .colorGroupWrap { gap: 10px; } + .colorGroup { padding: 10px; gap: 8px; border-radius: 16px; } + .hexCard { padding: 12px 8px; width: 140px; gap: 12px; } + .hexDigitDisplay { font-size: 40px; } + .hexNibbleBulb { width: 24px !important; height: 24px !important; } + .hexNibbleLabel { font-size: 20px; } + .hexColWeight { font-size: 26px; margin-top: 10px; } + .hexCardBtn { width: 34px; height: 34px; font-size: 14px; } } -/* Active Link Fix */ -.navLinks a.active, -.navLinks a:hover { - color: #ffffff !important; -} - -/* --- LAYOUT --- */ -.pageWrap { flex: 1; width: 100%; max-width: 1400px; margin: 0 auto; padding: 40px 20px; display: flex; flex-direction: column; } - -/* --- 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; +@container (max-width: 800px) { + .readoutContainer { flex-direction: column; gap: 24px; } + .colorPreviewSide { padding-top: 0; } + .colorGroupWrap { gap: 6px; } + .colorGroup { padding: 6px; gap: 6px; border-radius: 12px; } + .hexCard { padding: 8px 4px; width: 90px; gap: 8px; border-radius: 10px; } + .hexDigitDisplay { font-size: 32px; } + .hexNibbleBulb { width: 16px !important; height: 16px !important; } + .hexNibbleLabel { font-size: 16px; } + .hexColWeight { font-size: 20px; margin-top: 6px; } + .hexCardBtn { width: 28px; height: 28px; font-size: 12px; } + .denaryValue, .hexValue, .binaryValue { font-size: 32px; gap: 10px; } } -.footerLegal { margin-bottom: 8px; } -.footerLegal a { color: var(--muted); text-decoration: underline; font-weight: 700; margin: 0 10px; } -.footerLegal a:hover { color: #fff; } -/* 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; } \ No newline at end of file +@media (max-width: 1100px) { .binaryPage { --toolbox-w: 330px; } .denaryValue { font-size: 48px; } .hexValue { font-size: 40px; } .binaryValue { font-size: 32px; } } +@media (max-width: 900px) { .binaryPage { --toolbox-w: 320px; } .bitsGrid { grid-template-columns: repeat(var(--cols), minmax(84px, 1fr)); } .hexGrid { grid-template-columns: repeat(var(--cols), minmax(130px, 1fr)); } } + +.cc-sa:before { + background-image: url(https://creativecommons.org/wp-content/themes/vocabulary-theme/vocabulary/svg/cc/icons/cc-icons.svg#cc-sa); + float: left; + margin-left: -2.5em; + filter: invert(100%); +} + +.cc-nc:before { + background-image: url(https://creativecommons.org/wp-content/themes/vocabulary-theme/vocabulary/svg/cc/icons/cc-icons.svg#cc-nc); + float: left; + margin-left: -2.5em; + filter: invert(100%); +} + +.cc-by:before { + background-image: url(https://creativecommons.org/wp-content/themes/vocabulary-theme/vocabulary/svg/cc/icons/cc-icons.svg#cc-by); + float: left; + margin-left: -2.5em; + filter: invert(100%); +} + +.cc-terms ul > li { + padding-left: 2.5em; + clear: both; + list-style: none; + margin-bottom: 2em; + min-height: 2em; +} + +.cc-terms ul { + padding: 0; + font-size: 1.5rem; + font-style: normal; + font-weight: 400; + line-height: 150%; + margin: 0 0 2em 2em; +} \ No newline at end of file