diff --git a/frontend/css/layout/responsive.css b/frontend/css/layout/responsive.css
index bcfb39b..e58f688 100644
--- a/frontend/css/layout/responsive.css
+++ b/frontend/css/layout/responsive.css
@@ -66,6 +66,23 @@
}
}
+/* Cramped / Mobile viewport: Hide sector pill numbers so only icons are displayed */
+@media (max-width: 640px) {
+ .sector-pill .sector-pill-rate {
+ display: none !important;
+ }
+
+ .sector-pill {
+ padding: 8px 4px;
+ gap: 0;
+ }
+
+ .sector-pill iconify-icon {
+ font-size: 1.25rem;
+ }
+}
+
+
/* ==========================================================================
TOASTS & MODALS
========================================================================== */
@@ -232,3 +249,20 @@
.btn-text-close:hover {
color: var(--text-primary);
}
+
+.modal-error-box {
+ background: #fef2f2;
+ border: 1px solid #fecaca;
+ color: #b91c1c;
+ padding: 8px 12px;
+ border-radius: var(--radius-sm);
+ font-size: 0.78rem;
+ font-weight: 600;
+}
+
+.modal-body-text {
+ font-size: 0.88rem;
+ color: var(--text-secondary);
+ line-height: 1.5;
+}
+
diff --git a/frontend/css/layout/workspace.css b/frontend/css/layout/workspace.css
index bad2788..9659e86 100644
--- a/frontend/css/layout/workspace.css
+++ b/frontend/css/layout/workspace.css
@@ -216,13 +216,33 @@
color: var(--emerald-dark);
}
-/* All Sectors Overview Grid */
+/* All Sectors Overview Grid (Strict 6, 3, or 2 grid for 6 sectors) */
.all-sectors-summary-grid {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
+@media (min-width: 1400px) {
+ .all-sectors-summary-grid {
+ grid-template-columns: repeat(6, 1fr);
+ }
+}
+
+@media (max-width: 768px) {
+ .all-sectors-summary-grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+@media (max-width: 480px) {
+ .all-sectors-summary-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 8px;
+ }
+}
+
+
.sector-mini-card {
background: var(--bg-surface);
border: 1px solid var(--border-color);
diff --git a/frontend/index.html b/frontend/index.html
index 393af59..7eb1d10 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -213,6 +213,9 @@
+
+
+
@@ -227,6 +230,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/js/app.js b/frontend/js/app.js
index 9126b8c..d91f100 100644
--- a/frontend/js/app.js
+++ b/frontend/js/app.js
@@ -275,15 +275,23 @@ class ProductionApp {
}
case 'TRIGGER_IPO': {
- const confirmed = confirm('Confirm Corporate Initial Public Offering (IPO)?\n\nYour factories and cash will reset in exchange for permanent Venture Shares ($V-Shares) and corporate equity!');
- if (confirmed) {
- const success = this.sm.performIPO();
- if (success) {
- this.showToast(`IPO Successful! Welcome to Wall Street, CEO!`, 'success');
- this.mountActiveView();
- this.mountInspectorPane();
+ this.showConfirmModal({
+ title: 'Authorize Initial Public Offering (IPO)',
+ subtitle: 'Corporate Equity Transition',
+ icon: 'lucide:trending-up',
+ text: 'Confirm Corporate Initial Public Offering (IPO)?
All factory floors and cash will be liquidated in exchange for permanent Venture Shares ($V-Shares) and corporate prestige bonuses!',
+ okText: 'Execute IPO',
+ cancelText: 'Abort'
+ }).then(confirmed => {
+ if (confirmed) {
+ const success = this.sm.performIPO();
+ if (success) {
+ this.showToast(`IPO Successful! Welcome to Wall Street, CEO!`, 'success');
+ this.mountActiveView();
+ this.mountInspectorPane();
+ }
}
- }
+ });
break;
}
@@ -468,8 +476,52 @@ class ProductionApp {
}, 3200);
}
+ showConfirmModal({ title = 'Executive Authorization', subtitle = 'Board Confirmation', icon = 'lucide:alert-triangle', text = '', okText = 'Confirm', cancelText = 'Cancel' } = {}) {
+ return new Promise((resolve) => {
+ const modal = document.getElementById('confirm-modal');
+ const elTitle = document.getElementById('confirm-modal-title');
+ const elSub = document.getElementById('confirm-modal-subtitle');
+ const elIcon = document.getElementById('confirm-modal-icon');
+ const elText = document.getElementById('confirm-modal-text');
+ const btnOk = document.getElementById('btn-confirm-ok');
+ const btnCancel = document.getElementById('btn-confirm-cancel');
+
+ if (!modal) return resolve(false);
+
+ if (elTitle) elTitle.textContent = title;
+ if (elSub) elSub.textContent = subtitle;
+ if (elIcon) elIcon.setAttribute('icon', icon);
+ if (elText) elText.innerHTML = text;
+ if (btnOk) btnOk.textContent = okText;
+ if (btnCancel) btnCancel.textContent = cancelText;
+
+ const cleanup = () => {
+ modal.classList.remove('open');
+ btnOk.onclick = null;
+ btnCancel.onclick = null;
+ };
+
+ btnOk.onclick = () => {
+ cleanup();
+ resolve(true);
+ };
+
+ btnCancel.onclick = () => {
+ cleanup();
+ resolve(false);
+ };
+
+ modal.classList.add('open');
+ });
+ }
+
openAuthModal() {
const modal = document.getElementById('auth-modal');
+ const errBox = document.getElementById('auth-error-msg');
+ if (errBox) {
+ errBox.style.display = 'none';
+ errBox.textContent = '';
+ }
if (modal) modal.classList.add('open');
}
@@ -478,10 +530,20 @@ class ProductionApp {
if (modal) modal.classList.remove('open');
}
+ showAuthError(msg) {
+ const errBox = document.getElementById('auth-error-msg');
+ if (errBox) {
+ errBox.textContent = msg;
+ errBox.style.display = 'block';
+ } else {
+ this.showToast(msg, 'warning');
+ }
+ }
+
async handleLogin() {
const u = document.getElementById('auth-username')?.value.trim();
const p = document.getElementById('auth-password')?.value;
- if (!u || !p) return alert('Please enter username and password');
+ if (!u || !p) return this.showAuthError('Please enter username and password');
try {
await this.sync.login(u, p);
@@ -489,7 +551,7 @@ class ProductionApp {
this.closeAuthModal();
this.updateHud();
} catch (err) {
- alert(err.message || 'Login failed');
+ this.showAuthError(err.message || 'Login failed');
}
}
@@ -497,7 +559,7 @@ class ProductionApp {
const u = document.getElementById('auth-username')?.value.trim();
const p = document.getElementById('auth-password')?.value;
const hp = document.getElementById('auth-website-hp')?.value;
- if (!u || !p) return alert('Please enter username and password');
+ if (!u || !p) return this.showAuthError('Please enter username and password');
try {
await this.sync.register(u, p, hp);
@@ -505,7 +567,7 @@ class ProductionApp {
this.closeAuthModal();
this.updateHud();
} catch (err) {
- alert(err.message || 'Registration failed');
+ this.showAuthError(err.message || 'Registration failed');
}
}