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
\ No newline at end of file +
Bit width
Bits
Custom Number
Random runs briefly then stops automatically.
Tools
\ 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
\ No newline at end of file +
Digit width
Digits
Custom Number
Random runs briefly then stops automatically.
Tools
\ 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 +

Learn More Get Started
Computing Box Logo
\ 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; 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:

\ 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