diff --git a/public/css/tools/binary.css b/public/css/tools/binary.css
deleted file mode 100644
index f300e8f..0000000
--- a/public/css/tools/binary.css
+++ /dev/null
@@ -1,137 +0,0 @@
-/* ---------- DSEG7 font ---------- */
-/* Put your font file here:
- public/fonts/DSEG7Classic-Regular.woff2
-*/
-@font-face {
- font-family: "DSEG7ClassicRegular";
- src: url("/fonts/DSEG7Classic-Regular.woff2") format("woff2");
- font-display: swap;
-}
-
-/* ---------- Layout ---------- */
-.tool-shell {
- min-height: 100vh;
- display: grid;
- place-items: center;
- padding: 1rem;
- background: #0b0f14;
- color: #e7eaf0;
- font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
-}
-
-.tool-card {
- width: min(1100px, 100%);
- background: #111824;
- border: 1px solid rgba(255,255,255,0.08);
- border-radius: 18px;
- padding: 1rem;
-}
-
-.tool-header h1 { margin: 0 0 .25rem 0; font-size: 1.4rem; }
-.tool-header p { margin: 0 0 1rem 0; opacity: .85; }
-
-.display-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: .75rem;
- margin-bottom: .75rem;
-}
-
-.display-box {
- background: #0b0f14;
- border: 1px solid rgba(255,255,255,0.08);
- border-radius: 14px;
- padding: .75rem;
-}
-
-.display-label { font-size: .9rem; opacity: .8; margin-bottom: .25rem; }
-
-.sevenseg {
- font-family: "DSEG7ClassicRegular", monospace;
- font-size: clamp(2rem, 4vw, 3.2rem);
- letter-spacing: 0.08em;
- line-height: 1.1;
-}
-
-/* Buttons under denary/binary (your request) */
-.actions {
- display: flex;
- flex-wrap: wrap;
- gap: .5rem;
- margin-bottom: 1rem;
-}
-
-/* ---------- Simple MD3-ish buttons ---------- */
-.md3-btn {
- border: 1px solid rgba(255,255,255,0.16);
- background: rgba(255,255,255,0.06);
- color: #e7eaf0;
- padding: .6rem .9rem;
- border-radius: 999px;
- cursor: pointer;
- font-weight: 600;
-}
-.md3-btn:hover { background: rgba(255,255,255,0.10); }
-.md3-btn--tonal { background: rgba(255,255,255,0.10); }
-
-/* ---------- Switches row ---------- */
-.switch-row {
- display: grid;
- grid-template-columns: repeat(8, minmax(90px, 1fr));
- gap: .75rem;
-}
-
-.switch-col {
- display: grid;
- justify-items: center;
- gap: .35rem;
-}
-
-.bit-label { opacity: .85; font-weight: 600; }
-
-/* ---------- “Light switch” rocker ---------- */
-.rocker {
- position: relative;
- width: 70px;
- height: 46px;
- display: inline-block;
- user-select: none;
-}
-
-.rocker input {
- opacity: 0;
- width: 0;
- height: 0;
-}
-
-.rocker-body {
- position: absolute;
- inset: 0;
- border-radius: 12px;
- background: #1a2331;
- border: 1px solid rgba(255,255,255,0.14);
- box-shadow: inset 0 0 0 2px rgba(0,0,0,0.35);
-}
-
-/* the “toggle” */
-.rocker-body::after {
- content: "";
- position: absolute;
- left: 6px;
- top: 6px;
- width: 58px;
- height: 18px;
- border-radius: 10px;
- background: rgba(255,255,255,0.20);
- transition: transform 180ms ease, background 180ms ease;
-}
-
-/* ON position */
-.rocker input:checked + .rocker-body::after {
- transform: translateY(16px);
- background: rgba(255,255,255,0.55);
-}
-
-@media (max-width: 900px) {
- .switch-row { grid-template-columns: repeat(4, minmax(90px, 1fr)); }
-}
diff --git a/public/favicon.svg b/public/favicon.svg
deleted file mode 100644
index f157bd1..0000000
--- a/public/favicon.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/public/js/binary.js b/public/js/binary.js
deleted file mode 100644
index 0e65497..0000000
--- a/public/js/binary.js
+++ /dev/null
@@ -1,321 +0,0 @@
-// Binary simulator: unsigned + two's complement, 4–64 bits.
-// Key fixes:
-// - CSS moved to /public so dynamically-created switches & bulbs are styled.
-// - Bits grid wraps into rows of 8 (CSS).
-// - Binary readout wraps every 8 bits (JS -> adds \n).
-
-const bitsGrid = document.getElementById("bitsGrid");
-const denaryEl = document.getElementById("denaryNumber");
-const binaryEl = document.getElementById("binaryNumber");
-
-const modeToggle = document.getElementById("modeToggle");
-const modeHint = document.getElementById("modeHint");
-
-const bitsInput = document.getElementById("bitsInput");
-const btnUp = document.getElementById("btnBitsUp");
-const btnDown = document.getElementById("btnBitsDown");
-
-const btnShiftL = document.getElementById("btnShiftLeft");
-const btnShiftR = document.getElementById("btnShiftRight");
-const btnCustBin = document.getElementById("btnCustomBinary");
-const btnCustDen = document.getElementById("btnCustomDenary");
-
-let bitCount = clampInt(Number(bitsInput.value || 8), 4, 64);
-bitsInput.value = String(bitCount);
-
-let isTwos = false;
-
-// bits[0] = MSB, bits[bitCount-1] = LSB
-let bits = new Array(bitCount).fill(false);
-
-/* -----------------------------
- Helpers
------------------------------ */
-function clampInt(n, min, max){
- n = Number(n);
- if (!Number.isFinite(n)) return min;
- n = Math.floor(n);
- return Math.max(min, Math.min(max, n));
-}
-
-function maxUnsigned(nBits){
- // nBits up to 64 -> use BigInt for correctness
- return (1n << BigInt(nBits)) - 1n;
-}
-
-function rangeTwos(nBits){
- const min = -(1n << BigInt(nBits - 1));
- const max = (1n << BigInt(nBits - 1)) - 1n;
- return { min, max };
-}
-
-function bitsToBigIntUnsigned(){
- let v = 0n;
- for (let i = 0; i < bitCount; i++){
- v = (v << 1n) + (bits[i] ? 1n : 0n);
- }
- return v;
-}
-
-function bitsToBigIntTwos(){
- // Interpret current bit pattern as signed two's complement.
- const unsigned = bitsToBigIntUnsigned();
- const signBit = bits[0] ? 1n : 0n;
-
- if (signBit === 0n) return unsigned; // positive
-
- // negative: unsigned - 2^n
- const mod = 1n << BigInt(bitCount);
- return unsigned - mod;
-}
-
-function bigIntToBitsUnsigned(v){
- // v assumed 0..2^n-1
- const out = new Array(bitCount).fill(false);
- let x = BigInt(v);
- for (let i = bitCount - 1; i >= 0; i--){
- out[i] = (x & 1n) === 1n;
- x >>= 1n;
- }
- return out;
-}
-
-function bigIntToBitsTwos(v){
- // v assumed in signed range; convert to 0..2^n-1 representation
- const mod = 1n << BigInt(bitCount);
- let x = BigInt(v);
- if (x < 0n) x = mod + x;
- return bigIntToBitsUnsigned(x);
-}
-
-function formatBinaryForReadout(){
- // Wrap every 8 bits into a new line; keep spaces between groups.
- const raw = bits.map(b => (b ? "1" : "0")).join("");
- const groupsOf8 = raw.match(/.{1,8}/g) || [raw];
- return groupsOf8.join("\n");
-}
-
-/* -----------------------------
- UI build
------------------------------ */
-function buildBitsGrid(){
- bitsGrid.innerHTML = "";
-
- for (let i = 0; i < bitCount; i++){
- const weightUnsigned = 1n << BigInt(bitCount - 1 - i);
- const isMSB = i === 0;
-
- const bitEl = document.createElement("div");
- bitEl.className = "bit";
-
- const bulb = document.createElement("div");
- bulb.className = "bulb";
- bulb.id = `bulb-${i}`;
- bulb.setAttribute("aria-hidden", "true");
-
- const val = document.createElement("div");
- val.className = "bitVal";
- // if in two's complement, show MSB as negative label visually
- if (isTwos && isMSB) val.classList.add("msbNeg");
- val.textContent = weightUnsigned.toString(); // show magnitude only ( "-" is via CSS )
-
- const label = document.createElement("label");
- label.className = "switch";
- label.setAttribute("aria-label", `Toggle bit ${i + 1}`);
-
- const input = document.createElement("input");
- input.type = "checkbox";
- input.dataset.index = String(i);
-
- const slider = document.createElement("span");
- slider.className = "slider";
-
- label.appendChild(input);
- label.appendChild(slider);
-
- bitEl.appendChild(bulb);
- bitEl.appendChild(val);
- bitEl.appendChild(label);
-
- bitsGrid.appendChild(bitEl);
- }
-
- // Hook listeners after build
- bitsGrid.querySelectorAll('input[type="checkbox"][data-index]').forEach(input => {
- input.addEventListener("change", () => {
- const idx = Number(input.dataset.index);
- bits[idx] = input.checked;
- updateAll();
- });
- });
-
- syncInputsToBits();
- updateAll();
-}
-
-function syncInputsToBits(){
- bitsGrid.querySelectorAll('input[type="checkbox"][data-index]').forEach(input => {
- const idx = Number(input.dataset.index);
- input.checked = !!bits[idx];
- });
-}
-
-function syncBulbsToBits(){
- for (let i = 0; i < bitCount; i++){
- const bulb = document.getElementById(`bulb-${i}`);
- if (bulb) bulb.classList.toggle("on", !!bits[i]);
- }
-}
-
-function updateModeHint(){
- modeHint.textContent = isTwos
- ? "Tip: In two’s complement, the left-most bit (MSB) represents a negative value."
- : "Tip: In unsigned binary, all bits represent positive values.";
-}
-
-function updateAll(){
- const denary = isTwos ? bitsToBigIntTwos() : bitsToBigIntUnsigned();
- denaryEl.textContent = denary.toString();
- binaryEl.textContent = formatBinaryForReadout();
- syncBulbsToBits();
-}
-
-/* -----------------------------
- Bit-count changes (preserve LSBs)
------------------------------ */
-function setBitCount(newCount){
- newCount = clampInt(newCount, 4, 64);
- if (newCount === bitCount) return;
-
- // preserve LSB-aligned pattern:
- // take from the right end of old bits, pad on the left with zeros.
- const old = bits.slice();
- const newBits = new Array(newCount).fill(false);
-
- const take = Math.min(bitCount, newCount);
- for (let i = 0; i < take; i++){
- // copy from LSB side
- newBits[newCount - 1 - i] = old[bitCount - 1 - i];
- }
-
- bitCount = newCount;
- bits = newBits;
- bitsInput.value = String(bitCount);
-
- buildBitsGrid(); // rebuild with correct styling + rows
-}
-
-/* -----------------------------
- Custom input
------------------------------ */
-function requestBinary(){
- const v = prompt(`Enter a ${bitCount}-bit binary number (0/1):`);
- if (v === null) return;
-
- const clean = v.replace(/\s+/g, "");
- if (!/^[01]+$/.test(clean)){
- alert("Invalid input. Use only 0 and 1.");
- return;
- }
-
- const padded = clean.slice(-bitCount).padStart(bitCount, "0");
- bits = [...padded].map(ch => ch === "1");
- syncInputsToBits();
- updateAll();
-}
-
-function requestDenary(){
- const promptText = isTwos
- ? `Enter a denary number (${rangeTwos(bitCount).min} to ${rangeTwos(bitCount).max}):`
- : `Enter a denary number (0 to ${maxUnsigned(bitCount)}):`;
-
- const raw = prompt(promptText);
- if (raw === null) return;
-
- // allow leading +/- and digits
- if (!/^[+-]?\d+$/.test(raw.trim())){
- alert("Invalid input. Enter a whole number.");
- return;
- }
-
- const n = BigInt(raw.trim());
-
- if (isTwos){
- const { min, max } = rangeTwos(bitCount);
- if (n < min || n > max){
- alert(`Out of range. Enter between ${min} and ${max}.`);
- return;
- }
- bits = bigIntToBitsTwos(n);
- } else {
- const maxU = maxUnsigned(bitCount);
- if (n < 0n || n > maxU){
- alert(`Out of range. Enter between 0 and ${maxU}.`);
- return;
- }
- bits = bigIntToBitsUnsigned(n);
- }
-
- syncInputsToBits();
- updateAll();
-}
-
-/* -----------------------------
- Shifts
------------------------------ */
-function shiftLeft(){
- bits.shift();
- bits.push(false);
- syncInputsToBits();
- updateAll();
-}
-
-function shiftRight(){
- if (isTwos){
- // arithmetic shift right (preserve sign bit)
- const sign = bits[0];
- bits.pop();
- bits.unshift(sign);
- } else {
- // logical shift right
- bits.pop();
- bits.unshift(false);
- }
- syncInputsToBits();
- updateAll();
-}
-
-/* -----------------------------
- Mode toggle
------------------------------ */
-function setModeTwos(on){
- isTwos = !!on;
- updateModeHint();
-
- // rebuild so MSB label shows "-" via CSS class
- // (and keeps the same bit pattern)
- buildBitsGrid();
-}
-
-/* -----------------------------
- Wire up UI controls
------------------------------ */
-modeToggle.addEventListener("change", () => setModeTwos(modeToggle.checked));
-
-btnUp.addEventListener("click", () => setBitCount(bitCount + 1));
-btnDown.addEventListener("click", () => setBitCount(bitCount - 1));
-
-bitsInput.addEventListener("change", () => setBitCount(Number(bitsInput.value)));
-
-btnShiftL.addEventListener("click", shiftLeft);
-btnShiftR.addEventListener("click", shiftRight);
-
-btnCustBin.addEventListener("click", requestBinary);
-btnCustDen.addEventListener("click", requestDenary);
-
-/* -----------------------------
- Init
------------------------------ */
-updateModeHint();
-buildBitsGrid();
-updateAll();
diff --git a/public/scripts/binary.js b/public/scripts/binary.js
index 8effa3c..4733635 100644
--- a/public/scripts/binary.js
+++ b/public/scripts/binary.js
@@ -1,11 +1,4 @@
-/* Binary simulator for Computing:Box
- - Wrap bits every 8 (CSS handles layout)
- - Bit width 4..64
- - Unsigned + Two’s complement toggle (WORKING)
- - Bulbs + toggle switches for each bit
-*/
-
-const bitsGrid = document.getElementById("bitsGrid");
+const bitsRows = document.getElementById("bitsRows");
const denaryEl = document.getElementById("denaryNumber");
const binaryEl = document.getElementById("binaryNumber");
@@ -21,281 +14,250 @@ const btnShiftRight = document.getElementById("btnShiftRight");
const btnCustomBinary = document.getElementById("btnCustomBinary");
const btnCustomDenary = document.getElementById("btnCustomDenary");
-let bitCount = clampInt(Number(bitsInput?.value ?? 8), 4, 64);
-let isTwos = false;
+let bitCount = clampInt(Number(bitsInput.value || 8), 1, 64);
+let bits = new Array(bitCount).fill(false); // index 0 = MSB
-// bits[0] is MSB, bits[bitCount-1] is LSB
-let bits = new Array(bitCount).fill(false);
-
-function clampInt(n, min, max) {
+function clampInt(n, min, max){
n = Number(n);
- if (!Number.isInteger(n)) n = min;
+ if (!Number.isFinite(n)) n = min;
+ n = Math.floor(n);
return Math.max(min, Math.min(max, n));
}
-function pow2(exp) {
- // safe up to 2^63 in JS integer precision? (JS uses float) but our usage is display/control, ok.
- return 2 ** exp;
+function isTwos(){
+ return !!modeToggle.checked;
}
-/* -----------------------------
- Build UI (bulbs + switches)
------------------------------ */
-function buildBits(count) {
- bitCount = clampInt(count, 4, 64);
- bits = resizeBits(bits, bitCount);
+function msbValue(){
+ return 2 ** (bitCount - 1);
+}
- bitsGrid.innerHTML = "";
+function unsignedValueAt(i){
+ // i=0 is MSB
+ return 2 ** (bitCount - 1 - i);
+}
- for (let i = 0; i < bitCount; i++) {
- const exp = bitCount - 1 - i; // MSB has highest exponent
- const value = pow2(exp);
+function computeUnsigned(){
+ let sum = 0;
+ for (let i = 0; i < bitCount; i++){
+ if (bits[i]) sum += unsignedValueAt(i);
+ }
+ return sum;
+}
- const bit = document.createElement("div");
- bit.className = "bit";
- bit.innerHTML = `
-
- ${value}
-
- `;
+function computeDenary(){
+ const u = computeUnsigned();
+ if (!isTwos()) return u;
- bitsGrid.appendChild(bit);
+ // Two's complement:
+ // if MSB is 1, value = unsigned - 2^n
+ if (bits[0]) return u - (2 ** bitCount);
+ return u;
+}
+
+function bitsToString(){
+ return bits.map(b => (b ? "1" : "0")).join("");
+}
+
+function updateModeHint(){
+ if (isTwos()){
+ modeHint.textContent = "Tip: In two's complement, the left-most bit (MSB) represents a negative value.";
+ } else {
+ modeHint.textContent = "Tip: In unsigned binary, all bits represent positive values.";
+ }
+}
+
+function buildBitsUI(){
+ bitsRows.innerHTML = "";
+
+ // Build rows of 8 bits
+ const rowCount = Math.ceil(bitCount / 8);
+
+ for (let r = 0; r < rowCount; r++){
+ const row = document.createElement("div");
+ row.className = "byteRow";
+
+ const start = r * 8;
+ const end = Math.min(start + 8, bitCount);
+
+ for (let i = start; i < end; i++){
+ const bitEl = document.createElement("div");
+ bitEl.className = "bit";
+
+ // label: show -MSB in two's complement
+ const labelVal = (isTwos() && i === 0) ? -msbValue() : unsignedValueAt(i);
+
+ bitEl.innerHTML = `
+ 💡
+ ${labelVal}
+
+ `;
+
+ row.appendChild(bitEl);
+ }
+
+ bitsRows.appendChild(row);
}
- hookSwitches();
- syncUI();
-}
-
-function resizeBits(oldBits, newCount) {
- // keep LSB end stable when changing bit width:
- // align old bits to the right (LSB)
- const out = new Array(newCount).fill(false);
- const copy = Math.min(oldBits.length, newCount);
-
- for (let k = 0; k < copy; k++) {
- // copy from end (LSB)
- out[newCount - 1 - k] = oldBits[oldBits.length - 1 - k];
- }
- return out;
-}
-
-function hookSwitches() {
- bitsGrid.querySelectorAll('input[type="checkbox"][data-index]').forEach((input) => {
+ // Hook switches
+ bitsRows.querySelectorAll('input[type="checkbox"][data-index]').forEach(input => {
input.addEventListener("change", () => {
const i = Number(input.dataset.index);
bits[i] = input.checked;
updateReadout();
- updateBulb(i);
});
});
+
+ syncUI();
}
-/* -----------------------------
- Mode toggle (Unsigned <-> Two’s)
------------------------------ */
-function setModeTwos(on) {
- isTwos = !!on;
-
- modeHint.textContent = isTwos
- ? "Tip: In two’s complement, the left-most bit (MSB) represents a negative value."
- : "Tip: In unsigned binary, all bits represent positive values.";
-
- // Just re-calc denary using current bit pattern
- updateReadout();
-}
-
-modeToggle?.addEventListener("change", () => setModeTwos(modeToggle.checked));
-
-/* -----------------------------
- Calculations
------------------------------ */
-function getUnsignedValue() {
- let n = 0;
- for (let i = 0; i < bitCount; i++) {
- if (!bits[i]) continue;
- const exp = bitCount - 1 - i;
- n += pow2(exp);
- }
- return n;
-}
-
-function getTwosValue() {
- // MSB has negative weight
- let n = 0;
- for (let i = 0; i < bitCount; i++) {
- if (!bits[i]) continue;
- const exp = bitCount - 1 - i;
- if (i === 0) n -= pow2(exp); // MSB
- else n += pow2(exp);
- }
- return n;
-}
-
-function getDenary() {
- return isTwos ? getTwosValue() : getUnsignedValue();
-}
-
-function getBinaryString() {
- return bits.map(b => (b ? "1" : "0")).join("");
-}
-
-/* -----------------------------
- UI updates
------------------------------ */
-function updateBulb(i) {
- const bulb = document.getElementById(`bulb-${i}`);
- if (bulb) bulb.classList.toggle("on", bits[i]);
-}
-
-function updateReadout() {
- denaryEl.textContent = String(getDenary());
- binaryEl.textContent = getBinaryString();
-}
-
-function syncUI() {
- bitsGrid.querySelectorAll('input[type="checkbox"][data-index]').forEach((input) => {
+function syncUI(){
+ // sync inputs
+ bitsRows.querySelectorAll('input[type="checkbox"][data-index]').forEach(input => {
const i = Number(input.dataset.index);
input.checked = !!bits[i];
- updateBulb(i);
});
+
+ // sync bulbs
+ for (let i = 0; i < bitCount; i++){
+ const bulb = document.getElementById(`bulb-${i}`);
+ if (bulb) bulb.classList.toggle("on", !!bits[i]);
+ }
+
updateReadout();
}
-/* -----------------------------
- Set from Binary / Denary
------------------------------ */
-function setFromBinary(bin) {
+function updateReadout(){
+ denaryEl.textContent = String(computeDenary());
+ binaryEl.textContent = bitsToString();
+}
+
+function setFromBinary(bin){
const clean = String(bin).replace(/\s+/g, "");
if (!/^[01]+$/.test(clean)) return false;
const padded = clean.slice(-bitCount).padStart(bitCount, "0");
- bits = [...padded].map(ch => ch === "1");
+ for (let i = 0; i < bitCount; i++){
+ bits[i] = padded[i] === "1";
+ }
+
syncUI();
return true;
}
-function setFromDenary(n) {
+function setFromDenary(n){
+ n = Number(n);
if (!Number.isInteger(n)) return false;
- if (!isTwos) {
- const min = 0;
- const max = pow2(bitCount) - 1;
- if (n < min || n > max) return false;
+ if (!isTwos()){
+ // unsigned: 0 .. (2^n - 1)
+ const max = (2 ** bitCount) - 1;
+ if (n < 0 || n > max) return false;
- // unsigned fill from MSB->LSB
- let remaining = n;
- bits = bits.map((_, i) => {
- const exp = bitCount - 1 - i;
- const value = pow2(exp);
- if (remaining >= value) {
- remaining -= value;
- return true;
+ for (let i = 0; i < bitCount; i++){
+ const v = unsignedValueAt(i);
+ if (n >= v){
+ bits[i] = true;
+ n -= v;
+ } else {
+ bits[i] = false;
}
- return false;
- });
-
+ }
syncUI();
return true;
}
- // Two's complement bounds
- const min = -pow2(bitCount - 1);
- const max = pow2(bitCount - 1) - 1;
+ // two's complement: -(2^(n-1)) .. (2^(n-1)-1)
+ const min = -(2 ** (bitCount - 1));
+ const max = (2 ** (bitCount - 1)) - 1;
if (n < min || n > max) return false;
- // Convert to raw unsigned representation:
- // if negative, represent as 2^bitCount + n
- let raw = n;
- if (raw < 0) raw = pow2(bitCount) + raw;
+ // convert to unsigned representation
+ let u = n;
+ if (u < 0) u = (2 ** bitCount) + u; // wrap
- let remaining = raw;
- bits = bits.map((_, i) => {
- const exp = bitCount - 1 - i;
- const value = pow2(exp);
- if (remaining >= value) {
- remaining -= value;
- return true;
+ for (let i = 0; i < bitCount; i++){
+ const v = unsignedValueAt(i);
+ if (u >= v){
+ bits[i] = true;
+ u -= v;
+ } else {
+ bits[i] = false;
}
- return false;
- });
+ }
syncUI();
return true;
}
-/* -----------------------------
- Shifts
------------------------------ */
-function shiftLeft() {
- // drop MSB, append 0 at LSB
- bits.shift();
- bits.push(false);
+function shiftLeft(){
+ bits.shift(); // drop MSB
+ bits.push(false); // add LSB
syncUI();
}
-function shiftRight() {
- // unsigned: logical shift right (prepend 0)
- // twos: arithmetic shift right (prepend old MSB)
- const msb = bits[0];
- bits.pop();
- bits.unshift(isTwos ? msb : false);
+function shiftRight(){
+ bits.pop(); // drop LSB
+ bits.unshift(false); // add MSB
syncUI();
}
-/* -----------------------------
- Bit width controls
------------------------------ */
-function applyBitCount(next) {
- const v = clampInt(next, 4, 64);
- bitsInput.value = String(v);
- buildBits(v);
+function setBitCount(newCount){
+ newCount = clampInt(newCount, 4, 64);
+ if (newCount === bitCount) return;
+
+ // preserve right-most bits (LSB side) when resizing
+ const old = bits.slice();
+ const next = new Array(newCount).fill(false);
+
+ const copy = Math.min(old.length, next.length);
+ for (let k = 0; k < copy; k++){
+ // copy from end (LSB)
+ next[newCount - 1 - k] = old[old.length - 1 - k];
+ }
+
+ bitCount = newCount;
+ bits = next;
+
+ bitsInput.value = String(bitCount);
+ buildBitsUI();
}
-btnBitsUp?.addEventListener("click", () => applyBitCount(bitCount + 1));
-btnBitsDown?.addEventListener("click", () => applyBitCount(bitCount - 1));
+/* -------------------- events -------------------- */
-bitsInput?.addEventListener("change", () => {
- applyBitCount(Number(bitsInput.value));
+modeToggle.addEventListener("change", () => {
+ updateModeHint();
+ buildBitsUI(); // rebuild labels (MSB becomes negative/positive)
});
-/* -----------------------------
- Buttons
------------------------------ */
-btnShiftLeft?.addEventListener("click", shiftLeft);
-btnShiftRight?.addEventListener("click", shiftRight);
+btnBitsUp.addEventListener("click", () => setBitCount(bitCount + 1));
+btnBitsDown.addEventListener("click", () => setBitCount(bitCount - 1));
-btnCustomBinary?.addEventListener("click", () => {
- const v = prompt(`Enter a ${bitCount}-bit binary number:`);
+bitsInput.addEventListener("change", () => setBitCount(Number(bitsInput.value)));
+
+btnShiftLeft.addEventListener("click", shiftLeft);
+btnShiftRight.addEventListener("click", shiftRight);
+
+btnCustomBinary.addEventListener("click", () => {
+ const v = prompt(`Enter ${bitCount}-bit binary:`);
if (v === null) return;
- if (!setFromBinary(v)) alert("Invalid input. Use only 0 and 1.");
+ if (!setFromBinary(v)) alert("Invalid binary. Use only 0 and 1.");
});
-btnCustomDenary?.addEventListener("click", () => {
- const min = isTwos ? -pow2(bitCount - 1) : 0;
- const max = isTwos ? (pow2(bitCount - 1) - 1) : (pow2(bitCount) - 1);
+btnCustomDenary.addEventListener("click", () => {
+ const min = isTwos() ? -(2 ** (bitCount - 1)) : 0;
+ const max = isTwos() ? (2 ** (bitCount - 1)) - 1 : (2 ** bitCount) - 1;
const v = prompt(`Enter a denary number (${min} to ${max}):`);
if (v === null) return;
-
- const n = Number(v);
- if (!Number.isInteger(n) || !setFromDenary(n)) {
- alert(`Invalid input. Enter an integer from ${min} to ${max}.`);
- }
+ if (!setFromDenary(Number(v))) alert("Invalid denary for current mode/bit width.");
});
-/* -----------------------------
- INIT
------------------------------ */
-function init() {
- // default mode: unsigned
- setModeTwos(false);
- modeToggle.checked = false;
+/* -------------------- init -------------------- */
- // build initial bits
- applyBitCount(bitCount);
-}
-
-init();
+bitsInput.value = String(bitCount);
+updateModeHint();
+buildBitsUI();
diff --git a/public/styles.css b/public/styles.css
deleted file mode 100644
index 50ca124..0000000
--- a/public/styles.css
+++ /dev/null
@@ -1,96 +0,0 @@
-/* src/styles/md3-tokens.css */
-/* MD3-inspired tokens tuned for education: high readability, clear contrast, calm surfaces */
-:root{
- /* Typography */
- --font-sans: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
- /* Spacing + shape */
- --radius-1: 10px;
- --radius-2: 16px;
- --radius-3: 22px;
- --shadow-1: 0 1px 2px rgba(0,0,0,.08), 0 2px 8px rgba(0,0,0,.06);
- /* Color roles (keep simple) */
- --md-surface: #ffffff;
- --md-surface-2: #f6f7fb;
- --md-on-surface: #111318;
- --md-primary: #2f6fed; /* calm blue */
- --md-on-primary: #ffffff;
- --md-secondary: #5a5f72; /* muted */
- --md-on-secondary: #ffffff;
- --md-tertiary: #0f766e; /* teal for "practical" tools */
- --md-on-tertiary: #ffffff;
- --md-outline: #d7dbe7;
- --md-success: #1a7f37;
- --md-warning: #b54708;
- --md-danger: #b42318;
- /* Focus ring for accessibility */
- --md-focus: 0 0 0 3px rgba(47,111,237,.28);
-}
-@media (prefers-color-scheme: dark){
- :root{
- --md-surface: #0b0e14;
- --md-surface-2: #121725;
- --md-on-surface: #e8eaf2;
- --md-primary: #9bb6ff;
- --md-on-primary: #0b0e14;
- --md-secondary: #b8bccd;
- --md-on-secondary: #0b0e14;
- --md-tertiary: #4fd1c5;
- --md-on-tertiary: #0b0e14;
- --md-outline: #2b3244;
- --md-focus: 0 0 0 3px rgba(155,182,255,.25);
- }
-}
-
-/* src/styles/base.css */
-@import "./md3-tokens.css";
-html, body{ height:100%; }
-body{
- margin:0;
- font-family: var(--font-sans);
- background: var(--md-surface-2);
- color: var(--md-on-surface);
-}
-a{ color: var(--md-primary); text-decoration: none; }
-a:hover{ text-decoration: underline; }
-.container{
- max-width: 1100px;
- margin: 0 auto;
- padding: 16px;
-}
-.card{
- background: var(--md-surface);
- border: 1px solid var(--md-outline);
- border-radius: var(--radius-2);
- box-shadow: var(--shadow-1);
- padding: 16px;
-}
-.btn{
- display:inline-flex;
- gap:8px;
- align-items:center;
- justify-content:center;
- border-radius: 999px;
- border: 1px solid var(--md-outline);
- background: var(--md-surface);
- color: var(--md-on-surface);
- padding: 10px 14px;
- font-weight: 600;
- cursor: pointer;
-}
-.btn:hover{ filter: brightness(0.98); }
-.btn:focus{ outline:none; box-shadow: var(--md-focus); }
-.btn-primary{
- background: var(--md-primary);
- color: var(--md-on-primary);
- border-color: transparent;
-}
-.badge{
- display:inline-block;
- padding: 2px 10px;
- border-radius: 999px;
- font-size: 12px;
- border: 1px solid var(--md-outline);
- background: var(--md-surface-2);
-}
-code, pre{ font-family: var(--font-mono); }
diff --git a/public/css/binary.css b/public/styles/binary.css
similarity index 73%
rename from public/css/binary.css
rename to public/styles/binary.css
index 645c5b7..af70bde 100644
--- a/public/css/binary.css
+++ b/public/styles/binary.css
@@ -1,14 +1,4 @@
-:root{
- --bg: #1f2027;
- --panel2: rgba(255,255,255,.04);
- --text: #e8e8ee;
- --muted: #a9acb8;
- --accent: #33ff7a;
- --accent-dim: rgba(51,255,122,.15);
- --line: rgba(255,255,255,.12);
-}
-
-/* DSEG font (you already have these in public/fonts/) */
+/* Font */
@font-face{
font-family: "DSEG7ClassicRegular";
src:
@@ -19,10 +9,8 @@
font-display: swap;
}
-.wrap{
- max-width: 1200px;
- margin: 0 auto;
- padding: 32px 20px 60px;
+.binaryWrap{
+ padding-top: 8px;
}
.topGrid{
@@ -33,7 +21,6 @@
}
.readout{
- background: transparent;
text-align:center;
padding: 10px 10px 0;
}
@@ -43,7 +30,7 @@
font-weight: 800;
color: var(--muted);
text-transform: uppercase;
- font-size: 14px;
+ font-size: 13px;
margin-top: 10px;
}
@@ -55,16 +42,16 @@
}
.denary{
- font-size: 84px;
- line-height: 1.0;
- margin: 6px 0 16px;
+ font-size: 70px; /* smaller than before */
+ line-height: 1;
+ margin: 6px 0 10px;
}
.binary{
- font-size: 62px;
+ font-size: 54px; /* smaller than before */
letter-spacing: .12em;
- line-height: 1.0;
- margin: 6px 0 18px;
+ line-height: 1;
+ margin: 6px 0 16px;
}
.controls{
@@ -81,7 +68,7 @@
color: #fff;
padding: 12px 14px;
border-radius: 12px;
- font-weight: 800;
+ font-weight: 700;
cursor: pointer;
min-width: 160px;
}
@@ -92,7 +79,7 @@
border-top: 1px solid var(--line);
}
-/* Right panels */
+/* Right-side cards */
.panelCol{
display:flex;
flex-direction:column;
@@ -135,7 +122,7 @@
font-size: 14px;
}
-/* Switch (re-used for mode + bits) */
+/* Switch (reused for mode + bits) */
.switch{
position: relative;
width: 56px;
@@ -144,6 +131,7 @@
flex: 0 0 auto;
}
.switch input{
+ position:absolute;
opacity:0;
width:0;
height:0;
@@ -176,7 +164,7 @@
background: var(--accent);
}
-/* Bit width controls */
+/* Bit-width control */
.bitWidthRow{
display:grid;
grid-template-columns: 44px 1fr 44px;
@@ -191,7 +179,7 @@
background: rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.14);
color: #fff;
- cursor:pointer;
+ cursor: pointer;
font-weight: 900;
font-size: 18px;
}
@@ -219,8 +207,8 @@
width: 86px;
text-align:right;
background: transparent;
- border: none;
- outline: none;
+ border:none;
+ outline:none;
color: var(--accent);
font-family: "DSEG7ClassicRegular", ui-monospace, monospace;
font-size: 28px;
@@ -231,63 +219,66 @@
margin:0;
}
-/* ✅ Bits grid: wraps every 8 bits, NO horizontal scroll bar */
-.bits{
- margin-top: 26px;
- padding-top: 22px;
- display:grid;
- grid-template-columns: repeat(8, minmax(90px, 1fr));
+/* Bits: wrap every 8 (rows built in JS) */
+.bitsRows{
+ margin-top: 22px;
+ display:flex;
+ flex-direction:column;
gap: 18px;
- align-items:end;
- text-align:center;
-
- /* make absolutely sure we don't create a horizontal scrollbar */
- overflow-x: hidden;
}
-/* Bit tile */
+/* A row of up to 8 bits */
+.byteRow{
+ display:flex;
+ justify-content:center;
+ gap: 18px;
+ flex-wrap:nowrap;
+}
+
+/* A single bit */
.bit{
+ width: 110px;
display:flex;
flex-direction:column;
align-items:center;
gap: 10px;
- padding: 8px 4px;
+ padding: 6px 4px;
}
+/* Bulb emoji: bigger */
.bulb{
- width: 22px;
- height: 22px;
- border-radius: 50%;
- background: rgba(255,255,255,.08);
- border: 1px solid rgba(255,255,255,.12);
- box-shadow: none;
- margin-bottom: 4px;
+ font-size: 30px;
+ line-height: 1;
+ opacity: .20;
+ filter: grayscale(1);
+ transform: translateY(2px);
}
.bulb.on{
- background: #ffd86b;
- border-color: rgba(255,216,107,.7);
- box-shadow: 0 0 18px rgba(255,216,107,.6);
+ opacity: 1;
+ filter: grayscale(0);
+ text-shadow: 0 0 16px rgba(255,216,107,.65);
}
.bitVal{
font-family: "DSEG7ClassicRegular", ui-monospace, monospace;
font-size: 30px;
color: var(--text);
- opacity: .95;
- line-height: 1;
+ opacity: .92;
min-height: 34px;
}
-/* Responsive */
+/* Responsiveness */
@media (max-width: 980px){
.topGrid{ grid-template-columns: 1fr; }
- .denary{ font-size: 72px; }
- .binary{ font-size: 52px; }
- .bits{ grid-template-columns: repeat(4, minmax(90px, 1fr)); }
+ .denary{ font-size: 62px; }
+ .binary{ font-size: 48px; }
+ .bit{ width: 96px; }
}
@media (max-width: 520px){
- .denary{ font-size: 62px; }
- .binary{ font-size: 44px; }
+ .denary{ font-size: 56px; }
+ .binary{ font-size: 42px; }
.btn{ min-width: 140px; }
+ .byteRow{ gap: 12px; }
+ .bit{ width: 86px; }
}
diff --git a/public/styles/global.css b/public/styles/site.css
similarity index 53%
rename from public/styles/global.css
rename to public/styles/site.css
index 79b8405..5fdd4a9 100644
--- a/public/styles/global.css
+++ b/public/styles/site.css
@@ -4,9 +4,11 @@
--text: #e8e8ee;
--muted: #a9acb8;
--line: rgba(255,255,255,.12);
+ --accent: #33ff7a;
+ --accent-dim: rgba(51,255,122,.15);
}
-*{ box-sizing:border-box; }
+*{ box-sizing: border-box; }
body{
margin:0;
@@ -15,61 +17,62 @@ body{
color: var(--text);
}
-.site-header{
- border-bottom: 1px solid var(--line);
- background: rgba(0,0,0,.12);
- backdrop-filter: blur(6px);
+.page{
+ min-height: calc(100vh - 120px);
}
-.site-header__inner{
+.siteHeader{
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ background: rgba(0,0,0,.15);
+ border-bottom: 1px solid var(--line);
+ backdrop-filter: blur(10px);
+}
+
+.siteHeader__inner{
max-width: 1200px;
margin: 0 auto;
padding: 14px 20px;
- display:flex;
- align-items:center;
- justify-content:space-between;
- gap:16px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 18px;
}
.brand{
- text-decoration:none;
color: var(--text);
- font-weight: 900;
+ text-decoration: none;
+ font-weight: 800;
letter-spacing: .02em;
}
.nav{
- display:flex;
+ display: flex;
gap: 14px;
- flex-wrap:wrap;
+ flex-wrap: wrap;
+ justify-content: flex-end;
}
-.nav a{
+.nav__link{
color: var(--muted);
- text-decoration:none;
+ text-decoration: none;
font-weight: 700;
font-size: 14px;
}
-.nav a:hover{ color: var(--text); }
+.nav__link:hover{ color: var(--text); }
-.site-main{
- min-height: calc(100vh - 120px);
-}
-
-.site-footer{
+.siteFooter{
border-top: 1px solid var(--line);
- margin-top: 28px;
background: rgba(0,0,0,.10);
}
-.site-footer__inner{
+.siteFooter__inner{
max-width: 1200px;
margin: 0 auto;
padding: 18px 20px;
- display:flex;
- justify-content:space-between;
- gap:12px;
- flex-wrap:wrap;
+ color: var(--muted);
+ font-size: 12px;
+ display: grid;
+ gap: 6px;
}
-
-.muted{ color: var(--muted); font-size: 13px; }
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
new file mode 100644
index 0000000..443552a
--- /dev/null
+++ b/src/components/Footer.astro
@@ -0,0 +1,7 @@
+
diff --git a/src/components/Header.astro b/src/components/Header.astro
new file mode 100644
index 0000000..7746fba
--- /dev/null
+++ b/src/components/Header.astro
@@ -0,0 +1,13 @@
+
diff --git a/src/components/SiteFooter.astro b/src/components/SiteFooter.astro
deleted file mode 100644
index 0948906..0000000
--- a/src/components/SiteFooter.astro
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/src/components/SiteHeader.astro b/src/components/SiteHeader.astro
deleted file mode 100644
index eecd89e..0000000
--- a/src/components/SiteHeader.astro
+++ /dev/null
@@ -1,15 +0,0 @@
-
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index 7a7a8de..dfca60b 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -1,9 +1,10 @@
---
-import SiteHeader from "../components/SiteHeader.astro";
-import SiteFooter from "../components/SiteFooter.astro";
+import Header from "../components/Header.astro";
+import Footer from "../components/Footer.astro";
const { title = "Computing:Box" } = Astro.props;
---
+
@@ -11,16 +12,18 @@ const { title = "Computing:Box" } = Astro.props;
{title}
-
-
-
-
-
+
+
-
+
+
+
+
+
+
+
-
-
+
diff --git a/src/pages/binary.astro b/src/pages/binary.astro
index a1a0949..5f05b69 100644
--- a/src/pages/binary.astro
+++ b/src/pages/binary.astro
@@ -3,12 +3,11 @@ import BaseLayout from "../layouts/BaseLayout.astro";
---
-
-
-
-
+
+
+
Denary
@@ -27,11 +26,11 @@ import BaseLayout from "../layouts/BaseLayout.astro";
-
-
+
+
-
+
-
-
+
+
-
diff --git a/src/scripts/unsignedBinary.js b/src/scripts/unsignedBinary.js
deleted file mode 100644
index 58abb25..0000000
--- a/src/scripts/unsignedBinary.js
+++ /dev/null
@@ -1,54 +0,0 @@
-let bits = [128,64,32,16,8,4,2,1];
-let state = Array(8).fill(0);
-
-const denaryEl = document.getElementById("denaryNumber");
-const binaryEl = document.getElementById("binaryNumber");
-const bitEls = document.querySelectorAll(".bit");
-
-bitEls.forEach((el, i) => {
- el.addEventListener("click", () => {
- state[i] = state[i] ? 0 : 1;
- el.classList.toggle("on");
- update();
- });
-});
-
-function update() {
- const denary = state.reduce((sum, bit, i) => sum + bit * bits[i], 0);
- denaryEl.textContent = denary;
- binaryEl.textContent = state.join("");
-}
-
-function requestBinary() {
- const input = prompt("Enter 8-bit binary:");
- if (!/^[01]{8}$/.test(input)) return;
- state = input.split("").map(Number);
- bitEls.forEach((el,i)=>el.classList.toggle("on",state[i]));
- update();
-}
-
-function requestDenary() {
- const input = parseInt(prompt("Enter denary (0–255)"),10);
- if (isNaN(input) || input < 0 || input > 255) return;
-
- let value = input;
- state = bits.map(b => {
- if (value >= b) {
- value -= b;
- return 1;
- }
- return 0;
- });
-
- bitEls.forEach((el,i)=>el.classList.toggle("on",state[i]));
- update();
-}
-
-function shiftBinary(dir) {
- if (dir === "left") state.shift(), state.push(0);
- if (dir === "right") state.pop(), state.unshift(0);
- bitEls.forEach((el,i)=>el.classList.toggle("on",state[i]));
- update();
-}
-
-update();
diff --git a/src/styles/base.css b/src/styles/base.css
deleted file mode 100644
index f667474..0000000
--- a/src/styles/base.css
+++ /dev/null
@@ -1,52 +0,0 @@
-src/styles/base.css
-@import "./md3-tokens.css";
-html, body{ height:100%; }
-body{
- margin:0;
- font-family: var(--font-sans);
- background: var(--md-surface-2);
- color: var(--md-on-surface);
-}
-a{ color: var(--md-primary); text-decoration: none; }
-a:hover{ text-decoration: underline; }
-.container{
- max-width: 1100px;
- margin: 0 auto;
- padding: 16px;
-}
-.card{
- background: var(--md-surface);
- border: 1px solid var(--md-outline);
- border-radius: var(--radius-2);
- box-shadow: var(--shadow-1);
- padding: 16px;
-}
-.btn{
- display:inline-flex;
- gap:8px;
- align-items:center;
- justify-content:center;
- border-radius: 999px;
- border: 1px solid var(--md-outline);
- background: var(--md-surface);
- color: var(--md-on-surface);
- padding: 10px 14px;
- font-weight: 600;
- cursor: pointer;
-}
-.btn:hover{ filter: brightness(0.98); }
-.btn:focus{ outline:none; box-shadow: var(--md-focus); }
-.btn-primary{
- background: var(--md-primary);
- color: var(--md-on-primary);
- border-color: transparent;
-}
-.badge{
- display:inline-block;
- padding: 2px 10px;
- border-radius: 999px;
- font-size: 12px;
- border: 1px solid var(--md-outline);
- background: var(--md-surface-2);
-}
-code, pre{ font-family: var(--font-mono); }
diff --git a/src/styles/binary.css b/src/styles/binary.css
deleted file mode 100644
index 6a03738..0000000
--- a/src/styles/binary.css
+++ /dev/null
@@ -1,68 +0,0 @@
-.binary-container {
- max-width: 1100px;
- margin: auto;
- padding: 2rem;
- color: #e0e0e0;
-}
-
-.display {
- text-align: center;
-}
-
-.label {
- font-size: 1.2rem;
- opacity: 0.7;
-}
-
-.number {
- font-size: 3rem;
- margin-bottom: 1rem;
- color: #00ff66;
-}
-
-.controls {
- margin-top: 1rem;
-}
-
-.controls button {
- margin: 0.25rem;
- padding: 0.6rem 1rem;
- font-size: 1rem;
-}
-
-.bits {
- display: grid;
- grid-template-columns: repeat(8, 1fr);
- gap: 1rem;
- margin-top: 3rem;
-}
-
-.bit {
- width: 40px;
- height: 80px;
- background: #333;
- border-radius: 20px;
- position: relative;
- cursor: pointer;
-}
-
-.bit::after {
- content: "";
- width: 32px;
- height: 32px;
- background: #555;
- border-radius: 50%;
- position: absolute;
- bottom: 6px;
- left: 4px;
- transition: all 0.2s ease;
-}
-
-.bit.on {
- background: #00c853;
-}
-
-.bit.on::after {
- bottom: 42px;
- background: #eaffea;
-}
diff --git a/src/styles/fonts.css b/src/styles/fonts.css
deleted file mode 100644
index 768cb39..0000000
--- a/src/styles/fonts.css
+++ /dev/null
@@ -1,11 +0,0 @@
-@font-face {
- font-family: "DSEG7";
- src: url("/fonts/DSEG7Classic-Regular.ttf") format("truetype");
- font-weight: normal;
- font-style: normal;
-}
-
-.dseg {
- font-family: "DSEG7", monospace;
- letter-spacing: 0.15em;
-}
diff --git a/src/styles/md3-tokens.css b/src/styles/md3-tokens.css
deleted file mode 100644
index dff543c..0000000
--- a/src/styles/md3-tokens.css
+++ /dev/null
@@ -1,43 +0,0 @@
-src/styles/md3-tokens.css
-/* MD3-inspired tokens tuned for education: high readability, clear contrast, calm surfaces */
-:root{
- /* Typography */
- --font-sans: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
- /* Spacing + shape */
- --radius-1: 10px;
- --radius-2: 16px;
- --radius-3: 22px;
- --shadow-1: 0 1px 2px rgba(0,0,0,.08), 0 2px 8px rgba(0,0,0,.06);
- /* Color roles (keep simple) */
- --md-surface: #ffffff;
- --md-surface-2: #f6f7fb;
- --md-on-surface: #111318;
- --md-primary: #2f6fed; /* calm blue */
- --md-on-primary: #ffffff;
- --md-secondary: #5a5f72; /* muted */
- --md-on-secondary: #ffffff;
- --md-tertiary: #0f766e; /* teal for "practical" tools */
- --md-on-tertiary: #ffffff;
- --md-outline: #d7dbe7;
- --md-success: #1a7f37;
- --md-warning: #b54708;
- --md-danger: #b42318;
- /* Focus ring for accessibility */
- --md-focus: 0 0 0 3px rgba(47,111,237,.28);
-}
-@media (prefers-color-scheme: dark){
- :root{
- --md-surface: #0b0e14;
- --md-surface-2: #121725;
- --md-on-surface: #e8eaf2;
- --md-primary: #9bb6ff;
- --md-on-primary: #0b0e14;
- --md-secondary: #b8bccd;
- --md-on-secondary: #0b0e14;
- --md-tertiary: #4fd1c5;
- --md-on-tertiary: #0b0e14;
- --md-outline: #2b3244;
- --md-focus: 0 0 0 3px rgba(155,182,255,.25);
- }
-}