diff --git a/arma/ui/app.js b/arma/ui/app.js
new file mode 100644
index 0000000..02a2219
--- /dev/null
+++ b/arma/ui/app.js
@@ -0,0 +1,235 @@
+/**
+ * Simple React-like Vanilla JS Implementation
+ */
+
+// --- 1. The "Library" Logic ---
+
+// Helper to create DOM elements (like React.createElement)
+function h(tag, props = {}, ...children) {
+ const el = document.createElement(tag);
+
+ // Handle props
+ if (props) {
+ Object.entries(props).forEach(([key, value]) => {
+ if (key.startsWith('on') && typeof value === 'function') {
+ el.addEventListener(key.substring(2).toLowerCase(), value);
+ } else if (key === 'className') {
+ el.className = value;
+ } else if (key === 'style' && typeof value === 'object') {
+ Object.assign(el.style, value);
+ } else {
+ el.setAttribute(key, value);
+ }
+ });
+ }
+
+ // Handle children
+ children.forEach(child => {
+ if (typeof child === 'string' || typeof child === 'number') {
+ el.appendChild(document.createTextNode(child));
+ } else if (child instanceof Node) {
+ el.appendChild(child);
+ } else if (Array.isArray(child)) {
+ child.forEach(c => el.appendChild(c));
+ }
+ });
+
+ return el;
+}
+
+// Simple Rendering Logic
+let _rootContainer = null;
+let _rootComponent = null;
+
+function render(component, container) {
+ _rootContainer = container;
+ _rootComponent = component;
+ _render();
+}
+
+function _render() {
+ _rootContainer.innerHTML = ''; // Clear previous tree (simple re-render)
+ _rootContainer.appendChild(_rootComponent());
+}
+
+// Simple State Hook (Global for simplicity, or localized using closures)
+// Note: In a real app this would be more complex to handle multiple components.
+// For this demo, we'll re-render the whole app on state change.
+const createSignal = (initialValue) => {
+ let _val = initialValue;
+ const getValue = () => _val;
+ const setValue = (newValue) => {
+ _val = typeof newValue === 'function' ? newValue(_val) : newValue;
+ _render(); // Trigger re-render
+ };
+ return [getValue, setValue];
+};
+
+// --- 2. The Application Components ---
+
+// Global View State: 'home', 'login', 'create'
+const [getView, setView] = createSignal('home');
+
+// Header Component
+function Header({ title }) {
+ return h('div', { className: 'header' },
+ h('h1', {
+ style: { cursor: 'pointer' },
+ onClick: () => setView('home')
+ }, title),
+ h('p', null, 'Organization Registration & Management Portal')
+ );
+}
+
+// Login Form Component
+function LoginForm() {
+ const handleSubmit = (e) => {
+ e.preventDefault(); // Critical for strict sandbox
+ const formData = new FormData(e.target);
+ const data = Object.fromEntries(formData.entries());
+ console.log('Login Attempt:', data);
+ // TODO: Handle authentication logic here
+ };
+
+ return h('div', { className: 'card', style: { maxWidth: '400px', margin: '0 auto' } },
+ h('h2', null, 'Organization Login'),
+ h('form', { onSubmit: handleSubmit },
+ h('div', null,
+ h('label', null, 'Email'),
+ h('input', { name: 'email', type: 'text', placeholder: 'admin@spearnet.mil' })
+ ),
+ h('div', null,
+ h('label', null, 'Password'),
+ h('input', { name: 'password', type: 'password', placeholder: '••••••••' })
+ ),
+ h('div', { className: 'form-actions' },
+ h('button', { type: 'submit', style: { width: '100%' } }, 'Access Authenticator'),
+ h('span', {
+ className: 'cancel-link',
+ onClick: () => setView('home')
+ }, 'Cancel / Return to Main')
+ )
+ )
+ );
+}
+
+// Create Org Form Component
+function CreateOrgForm() {
+ const handleSubmit = (e) => {
+ e.preventDefault(); // Critical for strict sandbox
+ const formData = new FormData(e.target);
+ const data = Object.fromEntries(formData.entries());
+ console.log('Org Registration:', data);
+ // TODO: Handle registration logic here
+ };
+
+ return h('div', { className: 'split-container' },
+ h('div', { className: 'info-panel' },
+ h('h2', null, 'Registration Details'),
+ h('p', null, 'Complete the form to add your organization to the Global Organization Registry.'),
+ h('ul', { style: { textAlign: 'left', marginTop: '1.5rem', listStyleType: 'none', padding: 0 } },
+ h('li', { style: { marginBottom: '0.5rem' } }, '✅ Official Organization Designator'),
+ h('li', { style: { marginBottom: '0.5rem' } }, '✅ Secure Comms Channel'),
+ h('li', { style: { marginBottom: '0.5rem' } }, '✅ Deployment Roster Access'),
+ h('li', { style: { marginBottom: '0.5rem' } }, '✅ After-Action Report Tools')
+ ),
+ h('div', { className: 'price-tag', style: { marginTop: '2rem', padding: '1rem', background: 'var(--bg-app)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
+ h('span', { style: { display: 'block', fontSize: '0.9rem', color: 'var(--text-muted)' } }, 'Registration Fee'),
+ h('span', { style: { display: 'block', fontSize: '2rem', fontWeight: '700', color: 'var(--primary)' } }, '$50,000')
+ )
+ ),
+ h('div', { className: 'form-panel card', style: { margin: 0 } },
+ h('h2', null, 'Organization Registration'),
+ h('form', { onSubmit: handleSubmit },
+ h('div', null,
+ h('label', null, 'Organization Name'),
+ h('input', { name: 'orgName', type: 'text', placeholder: 'e.g. Task Force 141' })
+ ),
+ h('div', null,
+ h('label', null, 'Organization Type'),
+ h('select', { name: 'type' },
+ h('option', { value: 'infantry' }, 'Infantry / Milsim'),
+ h('option', { value: 'aviation' }, 'Aviation Wing'),
+ h('option', { value: 'pmc' }, 'Private Military Company'),
+ h('option', { value: 'support' }, 'Logistics & Support')
+ )
+ ),
+ h('div', { className: 'form-actions' },
+ h('button', { type: 'submit', style: { width: '100%' } }, 'Submit Registration'),
+ h('span', {
+ className: 'cancel-link',
+ onClick: () => setView('home')
+ }, 'Cancel / Return to Main')
+ )
+ )
+ )
+ );
+}
+
+// Home View Component
+function HomeView() {
+ return h('div', { className: 'content' },
+ h('div', { className: 'card' },
+ h('h2', null, 'Create Organization'),
+ h('p', null, 'Establish your Task Force, PMC, or Milsim unit with the Global Organization Network. Receive your official unit designator and TO&E authorization instantly.'),
+ h('button', { onClick: () => setView('create') }, 'Register')
+ ),
+ h('div', { className: 'card' },
+ h('h2', null, 'Organization Dashboard'),
+ h('p', null, 'Access your unit dashboard to modify rosters, adjust active deployments, and submit after-action reports through the secure field uplink.'),
+ h('button', { onClick: () => setView('login') }, 'Login')
+ )
+ );
+}
+
+// Footer Component (unchanged)
+function Footer() {
+ return h('div', { className: 'footer' },
+ h('div', { className: 'wrapper' },
+ h('div', null,
+ h('h3', null, 'Registry Resources'),
+ h('ul', { style: { listStyleType: 'none', padding: 0 } },
+ h('li', null, 'Registration Guidelines'),
+ h('li', null, 'Tax & Fee Schedule'),
+ h('li', null, 'Legal Compliance'),
+ h('li', null, 'Trademark Database')
+ )
+ ),
+ h('div', null,
+ h('h3', null, 'Bureau Support'),
+ h('ul', { style: { listStyleType: 'none', padding: 0 } },
+ h('li', null, 'Office: Sector 7 Admin Block'),
+ h('li', null, 'Hours: 0800 - 1600 (GST)'),
+ h('li', null, 'Helpdesk: 555-01-REGISTRY'),
+ h('li', null, 'support@org-bureau.gov')
+ )
+ )
+ )
+ );
+}
+
+// Main App Component
+function App() {
+ const view = getView();
+
+ let mainContent;
+ if (view === 'home') {
+ mainContent = HomeView();
+ } else if (view === 'login') {
+ mainContent = LoginForm();
+ } else if (view === 'create') {
+ mainContent = CreateOrgForm();
+ }
+
+ return h('main', null,
+ h('div', { className: 'container' },
+ Header({ title: 'Global Organization Network' }),
+ mainContent
+ ),
+ Footer()
+ );
+}
+
+// --- 3. Mount Application ---
+const root = document.getElementById('app');
+render(App, root);
diff --git a/arma/ui/atm.html b/arma/ui/atm.html
new file mode 100644
index 0000000..62a23d6
--- /dev/null
+++ b/arma/ui/atm.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ ATM - Global Financial Network
+
+
+
+
+
+
+
+
+
+
diff --git a/arma/ui/atm.js b/arma/ui/atm.js
new file mode 100644
index 0000000..a054ad4
--- /dev/null
+++ b/arma/ui/atm.js
@@ -0,0 +1,272 @@
+/**
+ * ATM App - Vanilla JS Kiosk Implementation
+ */
+
+// --- 1. The "Library" Logic (Reused) ---
+
+function h(tag, props = {}, ...children) {
+ const el = document.createElement(tag);
+ if (props) {
+ Object.entries(props).forEach(([key, value]) => {
+ if (key.startsWith('on') && typeof value === 'function') {
+ el.addEventListener(key.substring(2).toLowerCase(), value);
+ } else if (key === 'className') {
+ el.className = value;
+ } else if (key === 'style' && typeof value === 'object') {
+ Object.assign(el.style, value);
+ } else {
+ el.setAttribute(key, value);
+ }
+ });
+ }
+ children.forEach(child => {
+ if (typeof child === 'string' || typeof child === 'number') {
+ el.appendChild(document.createTextNode(child));
+ } else if (child instanceof Node) {
+ el.appendChild(child);
+ } else if (Array.isArray(child)) {
+ child.forEach(c => el.appendChild(c));
+ }
+ });
+ return el;
+}
+
+let _rootContainer = null;
+let _rootComponent = null;
+
+function render(component, container) {
+ _rootContainer = container;
+ _rootComponent = component;
+ _render();
+}
+
+function _render() {
+ _rootContainer.innerHTML = '';
+ _rootContainer.appendChild(_rootComponent());
+}
+
+const createSignal = (initialValue) => {
+ let _val = initialValue;
+ const getValue = () => _val;
+ const setValue = (newValue) => {
+ _val = typeof newValue === 'function' ? newValue(_val) : newValue;
+ _render();
+ };
+ return [getValue, setValue];
+};
+
+// --- 2. ATM Application Components ---
+
+// Global State
+const [getView, setView] = createSignal('pin'); // 'pin', 'menu', 'withdraw', 'custom_withdraw', 'balance'
+const [getPin, setPin] = createSignal('');
+const [getCustomAmount, setCustomAmount] = createSignal(''); // For custom withdrawal
+const [getBalance, setBalance] = createSignal(1250000); // Shared mockup balance
+const [getMessage, setMessage] = createSignal(''); // For feedback
+
+// Header
+function Header() {
+ return h('div', { className: 'header', style: { marginBottom: '2rem' } },
+ h('h1', null, 'ATM TERMINAL'),
+ h('p', null, 'Global Financial Network')
+ );
+}
+
+// PIN Entry View
+function PinView() {
+ const currentPin = getPin();
+
+ const handleNumClick = (num) => {
+ if (currentPin.length < 4) {
+ setPin(prev => prev + num);
+ }
+ };
+
+ const handleClear = () => setPin('');
+ const handleEnter = () => {
+ if (currentPin.length === 4) {
+ // Mock auth success
+ setView('menu');
+ } else {
+ setMessage('Invalid PIN Length');
+ setTimeout(() => setMessage(''), 2000);
+ }
+ };
+
+ return h('div', { className: 'card', style: { padding: '3rem 2rem' } },
+ h('h2', null, 'Enter Security PIN'),
+ h('div', { className: 'pin-display' },
+ currentPin.replace(/./g, '•') || '----'
+ ),
+ h('p', { style: { color: 'red', height: '1.5rem' } }, getMessage()),
+ h('div', { className: 'numpad' },
+ ['1', '2', '3', '4', '5', '6', '7', '8', '9'].map(num =>
+ h('button', { onClick: () => handleNumClick(num) }, num)
+ ),
+ h('button', { style: { background: '#ef4444', color: 'white' }, onClick: handleClear }, 'C'),
+ h('button', { onClick: () => handleNumClick('0') }, '0'),
+ h('button', { style: { background: '#10b981', color: 'white' }, onClick: handleEnter }, '↵')
+ )
+ );
+}
+
+// Main Menu View
+function MenuView() {
+ return h('div', { className: 'kiosk-content' },
+ h('h2', { style: { textAlign: 'center', marginBottom: '1rem' } }, 'Select Transaction'),
+ h('div', { className: 'kiosk-menu-stack' },
+ h('button', { className: 'kiosk-btn', onClick: () => setView('withdraw') },
+ 'Withdraw Cash'
+ ),
+ h('button', { className: 'kiosk-btn', onClick: () => setView('balance') },
+ 'Check Balance'
+ ),
+ h('button', {
+ className: 'kiosk-btn',
+ style: { background: 'var(--bg-surface)', color: 'var(--text-main)', border: '1px solid var(--border)' },
+ onClick: () => {
+ setPin('');
+ setView('pin');
+ }
+ }, 'Cancel Transaction')
+ )
+ );
+}
+
+// Withdraw View
+function WithdrawView() {
+ const handleWithdraw = (amount) => {
+ if (getBalance() >= amount) {
+ setBalance(prev => prev - amount);
+ setMessage(`Please take your cash: $${amount}`);
+ setTimeout(() => {
+ setMessage('');
+ setView('menu');
+ }, 3000);
+ } else {
+ setMessage('Insufficient Funds');
+ setTimeout(() => setMessage(''), 2000);
+ }
+ };
+
+ if (getMessage()) {
+ return h('div', { className: 'card', style: { padding: '4rem', textAlign: 'center' } },
+ h('h2', { style: { color: 'var(--primary)' } }, getMessage())
+ );
+ }
+
+ return h('div', { className: 'kiosk-content' },
+ h('h2', { style: { textAlign: 'center', marginBottom: '1rem' } }, 'Select Amount'),
+ h('div', { className: 'kiosk-grid' },
+ h('button', { className: 'kiosk-btn', onClick: () => handleWithdraw(20) }, '$20'),
+ h('button', { className: 'kiosk-btn', onClick: () => handleWithdraw(50) }, '$50'),
+ h('button', { className: 'kiosk-btn', onClick: () => handleWithdraw(100) }, '$100'),
+ h('button', {
+ className: 'kiosk-btn',
+ onClick: () => {
+ setCustomAmount('');
+ setView('custom_withdraw');
+ }
+ }, 'Other Amount'),
+ h('button', { className: 'kiosk-btn', style: { gridColumn: 'span 2', background: 'var(--text-muted)' }, onClick: () => setView('menu') }, 'Cancel')
+ )
+ );
+}
+
+// Custom Withdraw View
+function CustomWithdrawView() {
+ const currentAmount = getCustomAmount();
+
+ const handleNumClick = (num) => {
+ if (currentAmount.length < 5) { // Limit to 5 digits for safety
+ setCustomAmount(prev => prev + num);
+ }
+ };
+
+ const handleClear = () => setCustomAmount('');
+
+ const handleEnter = () => {
+ const amount = parseInt(currentAmount, 10);
+ if (amount > 0) {
+ if (getBalance() >= amount) {
+ setBalance(prev => prev - amount);
+ setMessage(`Please take your cash: $${amount}`);
+ setTimeout(() => {
+ setMessage('');
+ setView('menu');
+ }, 3000);
+ } else {
+ setMessage('Insufficient Funds');
+ setTimeout(() => setMessage(''), 2000);
+ }
+ } else {
+ setMessage('Invalid Amount');
+ setTimeout(() => setMessage(''), 2000);
+ }
+ };
+
+ if (getMessage()) {
+ return h('div', { className: 'card', style: { padding: '4rem', textAlign: 'center' } },
+ h('h2', { style: { color: 'var(--primary)' } }, getMessage())
+ );
+ }
+
+ return h('div', { className: 'card', style: { padding: '3rem 2rem' } },
+ h('h2', null, 'Enter Amount'),
+ h('div', { className: 'pin-display' },
+ currentAmount ? `$${currentAmount}` : '$0'
+ ),
+ h('div', { className: 'numpad' },
+ ['1', '2', '3', '4', '5', '6', '7', '8', '9'].map(num =>
+ h('button', { onClick: () => handleNumClick(num) }, num)
+ ),
+ h('button', { style: { background: '#ef4444', color: 'white' }, onClick: handleClear }, 'C'),
+ h('button', { onClick: () => handleNumClick('0') }, '0'),
+ h('button', { style: { background: '#10b981', color: 'white' }, onClick: handleEnter }, '↵')
+ ),
+ h('button', {
+ style: { width: '100%', marginTop: '2rem', padding: '1rem', background: 'var(--text-muted)' },
+ onClick: () => setView('withdraw')
+ }, 'Cancel')
+ );
+}
+
+// Balance View
+function BalanceView() {
+ return h('div', { className: 'card', style: { textAlign: 'center', padding: '3rem' } },
+ h('h2', { style: { color: 'var(--text-muted)' } }, 'Available Balance'),
+ h('div', { style: { fontSize: '4rem', fontWeight: '800', margin: '2rem 0', color: 'var(--primary-hover)' } },
+ '$' + getBalance().toLocaleString()
+ ),
+ h('button', { className: 'kiosk-btn', style: { width: '100%', maxWidth: '300px', margin: '0 auto' }, onClick: () => setView('menu') }, 'Return to Menu')
+ );
+}
+
+// Main App
+function App() {
+ const view = getView();
+
+ let mainContent;
+ if (view === 'pin') {
+ mainContent = PinView();
+ } else if (view === 'menu') {
+ mainContent = MenuView();
+ } else if (view === 'withdraw') {
+ mainContent = WithdrawView();
+ } else if (view === 'custom_withdraw') {
+ mainContent = CustomWithdrawView();
+ } else if (view === 'balance') {
+ mainContent = BalanceView();
+ }
+
+ return h('main', null,
+ h('div', { className: 'container' },
+ Header(),
+ mainContent
+ )
+ );
+}
+
+// Mount
+const root = document.getElementById('app');
+render(App, root);
diff --git a/arma/ui/bank.html b/arma/ui/bank.html
new file mode 100644
index 0000000..fe92a70
--- /dev/null
+++ b/arma/ui/bank.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ FDIC - Global Financial Network
+
+
+
+
+
+
+
+
+
diff --git a/arma/ui/bank.js b/arma/ui/bank.js
new file mode 100644
index 0000000..8fe0486
--- /dev/null
+++ b/arma/ui/bank.js
@@ -0,0 +1,265 @@
+/**
+ * Player Bank App - Vanilla JS "React-like" Implementation
+ */
+
+// --- 1. The "Library" Logic (Reused) ---
+
+function h(tag, props = {}, ...children) {
+ const el = document.createElement(tag);
+ if (props) {
+ Object.entries(props).forEach(([key, value]) => {
+ if (key.startsWith('on') && typeof value === 'function') {
+ el.addEventListener(key.substring(2).toLowerCase(), value);
+ } else if (key === 'className') {
+ el.className = value;
+ } else if (key === 'style' && typeof value === 'object') {
+ Object.assign(el.style, value);
+ } else {
+ el.setAttribute(key, value);
+ }
+ });
+ }
+ children.forEach(child => {
+ if (typeof child === 'string' || typeof child === 'number') {
+ el.appendChild(document.createTextNode(child));
+ } else if (child instanceof Node) {
+ el.appendChild(child);
+ } else if (Array.isArray(child)) {
+ child.forEach(c => el.appendChild(c));
+ }
+ });
+ return el;
+}
+
+let _rootContainer = null;
+let _rootComponent = null;
+
+function render(component, container) {
+ _rootContainer = container;
+ _rootComponent = component;
+ _render();
+}
+
+function _render() {
+ _rootContainer.innerHTML = '';
+ _rootContainer.appendChild(_rootComponent());
+}
+
+const createSignal = (initialValue) => {
+ let _val = initialValue;
+ const getValue = () => _val;
+ const setValue = (newValue) => {
+ _val = typeof newValue === 'function' ? newValue(_val) : newValue;
+ _render();
+ };
+ return [getValue, setValue];
+};
+
+// --- 2. Bank Application Components ---
+
+// Global State
+const [getView, setView] = createSignal('login'); // 'login', 'dashboard'
+const [getBalance, setBalance] = createSignal(1250000);
+const [getPending, setPending] = createSignal(45250); // Mock pending earnings
+const [getTransactions, setTransactions] = createSignal([
+ { id: 1, type: 'credit', desc: 'Contract Payment: OP-442', amount: 150000, date: '2026-02-05' },
+ { id: 2, type: 'debit', desc: 'Equipment Purchase: Ammunition', amount: -4500, date: '2026-02-04' },
+ { id: 3, type: 'debit', desc: 'Vehicle Maintenance', amount: -1200, date: '2026-02-03' },
+]);
+
+// Header
+function Header() {
+ return h('div', { className: 'header' },
+ h('h1', {
+ style: { cursor: 'pointer' },
+ onClick: () => setView('login')
+ }, 'Global Financial Network'),
+ h('p', null, 'Secure Banking')
+ );
+}
+
+// Login View
+function BankLogin() {
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ setView('dashboard');
+ };
+
+ return h('div', { className: 'card', style: { maxWidth: '400px', margin: '0 auto' } },
+ h('h2', null, 'Secure Access'),
+ h('form', { onSubmit: handleSubmit },
+ h('div', null,
+ h('label', null, 'Account ID'),
+ h('input', { type: 'text', placeholder: 'xxxx-xxxx-xxxx' })
+ ),
+ h('div', null,
+ h('label', null, 'Security PIN'),
+ h('input', { type: 'password', placeholder: '••••' })
+ ),
+ h('div', { className: 'form-actions' },
+ h('button', { type: 'submit', style: { width: '100%' } }, 'Authenticate'),
+ h('p', { style: { fontSize: '0.8rem', color: 'var(--text-muted)', marginTop: '1rem' } }, 'Authorized Personnel Only')
+ )
+ )
+ );
+}
+
+// Transaction History Helper
+function TransactionHistory() {
+ const transactions = getTransactions();
+
+ return h('div', { className: 'card' },
+ h('h3', { style: { textAlign: 'left', borderBottom: '1px solid var(--border)', paddingBottom: '1rem', marginBottom: '1rem' } }, 'Recent Transactions'),
+ h('ul', { style: { listStyle: 'none', padding: 0 } },
+ ...transactions.map(tx => h('li', {
+ style: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ padding: '0.75rem 0',
+ borderBottom: '1px solid var(--bg-surface-hover)'
+ }
+ },
+ h('div', { style: { textAlign: 'left' } },
+ h('div', { style: { fontWeight: '500' } }, tx.desc),
+ h('div', { style: { fontSize: '0.85rem', color: 'var(--text-muted)' } }, tx.date)
+ ),
+ h('div', {
+ style: {
+ fontWeight: '700',
+ color: tx.type === 'credit' ? '#10b981' : '#ef4444'
+ }
+ },
+ (tx.type === 'credit' ? '+' : '') + '$' + Math.abs(tx.amount).toLocaleString()
+ )
+ ))
+ )
+ );
+}
+
+// Transfer Form
+function TransferForm() {
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ const formData = new FormData(e.target);
+ const amount = parseFloat(formData.get('amount'));
+
+ if (amount > 0 && amount <= getBalance()) {
+ setBalance(prev => prev - amount);
+ const newTx = {
+ id: Date.now(),
+ type: 'debit',
+ desc: 'Transfer to ' + formData.get('recipient'),
+ amount: -amount,
+ date: new Date().toISOString().split('T')[0]
+ };
+ setTransactions(prev => [newTx, ...prev]);
+ }
+ };
+
+ return h('div', { className: 'card' },
+ h('h2', null, 'Wire Transfer'),
+ h('form', { onSubmit: handleSubmit },
+ h('div', null,
+ h('label', null, 'Recipient Name / GUID'),
+ h('input', { name: 'recipient', type: 'text', placeholder: 'Enter Name or GUID' })
+ ),
+ h('div', null,
+ h('label', null, 'Amount'),
+ h('input', { name: 'amount', type: 'number', placeholder: '0.00' })
+ ),
+ h('button', { type: 'submit' }, 'Send Funds')
+ )
+ );
+}
+
+// Dashboard View
+function BankDashboard() {
+ return h('div', { className: 'content' },
+ // Top Row: Balance
+ h('div', { className: 'card', style: { gridColumn: 'span 2' } },
+ h('h2', { style: { fontSize: '1.2rem', color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.05em' } }, 'Total Balance'),
+ h('div', { style: { fontSize: '2.8rem', fontWeight: '800', color: 'var(--primary-hover)', margin: '1rem 0' } },
+ '$' + getBalance().toLocaleString()
+ ),
+ h('div', { style: { textAlign: 'center', marginBottom: '1.5rem', color: 'var(--text-muted)', fontSize: '1.2rem' } },
+ 'Pending: ',
+ h('span', { style: { color: '#fbbf24', fontWeight: 'bold' } }, '$' + getPending().toLocaleString())
+ ),
+ h('div', { style: { display: 'flex', gap: '1rem', justifyContent: 'center' } },
+ h('button', {
+ onClick: () => {
+ const pending = getPending();
+ if (pending > 0) {
+ setBalance(prev => prev + pending);
+ setPending(0);
+ const newTx = {
+ id: Date.now(),
+ type: 'credit',
+ desc: 'Field Deposit',
+ amount: pending,
+ date: new Date().toISOString().split('T')[0]
+ };
+ setTransactions(prev => [newTx, ...prev]);
+ }
+ },
+ style: { opacity: getPending() > 0 ? '1' : '0.5', cursor: getPending() > 0 ? 'pointer' : 'default' }
+ }, 'Deposit Pending'),
+ h('button', { style: { background: 'var(--bg-surface-hover)', color: 'var(--text-main)', border: '1px solid var(--border)' } }, 'Statement')
+ )
+ ),
+ // Middle Row: Transfer Form
+ TransferForm(),
+ // Bottom Row: History (Full Width in simplified grid, or separate)
+ TransactionHistory()
+ );
+}
+
+// Footer
+function Footer() {
+ return h('div', { className: 'footer' },
+ h('div', { className: 'wrapper' },
+ h('div', null,
+ h('h3', null, 'Secure Banking'),
+ h('ul', { style: { listStyleType: 'none', padding: 0 } },
+ h('li', null, 'FDIC Insured'),
+ h('li', null, 'Fraud Protection'),
+ h('li', null, '24/7 Support'),
+ h('li', null, 'API Access')
+ )
+ ),
+ h('div', null,
+ h('h3', null, 'Notices'),
+ h('ul', { style: { listStyleType: 'none', padding: 0 } },
+ h('li', null, 'Terms of Service'),
+ h('li', null, 'Privacy Policy'),
+ h('li', null, 'Interest Rates'),
+ h('li', null, 'Report Fraud')
+ )
+ )
+ )
+ );
+}
+
+// Main App
+function App() {
+ const view = getView();
+
+ let mainContent;
+ if (view === 'login') {
+ mainContent = BankLogin();
+ } else if (view === 'dashboard') {
+ mainContent = BankDashboard();
+ }
+
+ return h('main', null,
+ h('div', { className: 'container' },
+ Header(),
+ mainContent
+ ),
+ Footer()
+ );
+}
+
+// Mount
+const root = document.getElementById('app');
+render(App, root);
diff --git a/arma/ui/index.html b/arma/ui/index.html
new file mode 100644
index 0000000..dc62f47
--- /dev/null
+++ b/arma/ui/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ ORBIS - Global Organization Network
+
+
+
+
+
+
+
+
+
diff --git a/arma/ui/style.css b/arma/ui/style.css
new file mode 100644
index 0000000..fe13bdd
--- /dev/null
+++ b/arma/ui/style.css
@@ -0,0 +1,303 @@
+:root {
+ --bg-app: #fdfcf8;
+ /* Warm white */
+ --bg-surface: #ffffff;
+ --bg-surface-hover: #f1f5f9;
+ --primary: #475569;
+ /* Slate gray */
+ --primary-hover: #1e293b;
+ --text-main: #1f2937;
+ --text-muted: #64748b;
+ --text-inverse: #f8fafc;
+ --border: #e2e8f0;
+ --radius: 8px;
+ --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
+ --footer-bg: #1e293b;
+ /* Dark slate for footer */
+}
+
+body {
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
+ margin: 0;
+ padding: 0;
+ background: var(--bg-app);
+ color: var(--text-main);
+ line-height: 1.6;
+}
+
+#app {
+ min-height: 100vh;
+}
+
+main {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+}
+
+.container {
+ max-width: 1200px;
+ width: 100%;
+ margin: 0 auto;
+ padding: 2rem;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+}
+
+/* Header */
+.header {
+ text-align: center;
+ margin-bottom: 3rem;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid var(--border);
+
+ h1 {
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 0.5rem;
+ letter-spacing: -0.025em;
+ color: var(--primary-hover);
+ }
+
+ p {
+ color: var(--text-muted);
+ font-size: 1.1rem;
+ }
+}
+
+.content {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+/* Cards */
+.card {
+ background: var(--bg-surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ padding: 2rem;
+ margin-bottom: 2rem;
+ box-shadow: var(--shadow);
+ text-align: center;
+
+ h2 {
+ margin-top: 0;
+ font-size: 1.8rem;
+ color: var(--primary-hover);
+ }
+}
+
+/* Buttons */
+button {
+ background: var(--primary);
+ color: white;
+ border: none;
+ padding: 0.75rem 1.5rem;
+ border-radius: var(--radius);
+ cursor: pointer;
+ font-size: 1rem;
+ font-weight: 500;
+ transition: all 0.2s ease;
+
+ &:hover {
+ background: var(--primary-hover);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
+ }
+
+ &+& {
+ margin-left: 1rem;
+ }
+}
+
+/* Split Layout */
+.split-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ align-items: center;
+ width: 100%;
+}
+
+.info-panel {
+ text-align: left;
+ padding: 1rem;
+}
+
+/* Forms */
+form {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ text-align: left;
+
+ label {
+ display: block;
+ margin-bottom: 0.5rem;
+ color: var(--text-muted);
+ font-weight: 500;
+ font-size: 0.9rem;
+ }
+
+ input,
+ select {
+ width: 100%;
+ padding: 0.75rem;
+ border-radius: var(--radius);
+ border: 1px solid var(--border);
+ background: var(--bg-app);
+ color: var(--text-main);
+ font-family: inherit;
+ font-size: 1rem;
+ box-sizing: border-box;
+ transition: border-color 0.2s;
+
+ &:focus {
+ outline: none;
+ border-color: var(--primary);
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
+ }
+ }
+
+ .form-actions {
+ margin-top: 1rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: center;
+ }
+
+ .cancel-link {
+ font-size: 0.9rem;
+ color: var(--text-muted);
+ cursor: pointer;
+ text-decoration: underline;
+
+ &:hover {
+ color: var(--primary);
+ }
+ }
+}
+
+/* Footer */
+.footer {
+ margin-top: auto;
+ background: var(--footer-bg);
+ color: var(--text-inverse);
+ display: block;
+
+ .wrapper {
+ max-width: 1200px;
+ width: 100%;
+ margin: 0 auto;
+ padding: 3rem 2rem;
+ box-sizing: border-box;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4rem;
+ }
+
+ h3 {
+ color: var(--text-inverse);
+ font-size: 0.85rem;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ font-weight: 700;
+ margin-bottom: 1.5rem;
+ border-bottom: 1px solid #475569 !important;
+ padding-bottom: 0.5rem;
+ margin-right: 1rem;
+ }
+
+ ul {
+ li {
+ color: #cbd5e1;
+ font-size: 0.95rem;
+ margin-bottom: 0.75rem !important;
+ cursor: pointer;
+ transition: color 0.2s;
+
+ &:hover {
+ color: white;
+ }
+ }
+ }
+}
+
+/* ATM Kiosk Styles */
+.kiosk-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+}
+
+.kiosk-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 1.5rem;
+ margin-top: 2rem;
+ width: 100%;
+ max-width: 600px;
+ /* Constrain width for better look */
+}
+
+.kiosk-menu-stack {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+ margin-top: 2rem;
+ width: 100%;
+ max-width: 600px;
+ /* Narrower for vertical stack */
+}
+
+.kiosk-btn {
+ padding: 2rem;
+ font-size: 1.25rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ height: 100%;
+ min-height: 120px;
+ margin: 0;
+}
+
+.numpad {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 1rem;
+ max-width: 300px;
+ margin: 0 auto;
+
+ button {
+ padding: 1.5rem;
+ font-size: 1.5rem;
+ background: var(--bg-surface);
+ color: var(--text-main);
+ border: 1px solid var(--border);
+ box-shadow: var(--shadow);
+ margin: 0;
+
+ &:hover {
+ background: var(--primary);
+ color: white;
+ border-color: var(--primary);
+ }
+ }
+}
+
+.pin-display {
+ font-size: 2.5rem;
+ letter-spacing: 0.5rem;
+ text-align: center;
+ margin-bottom: 2rem;
+ font-family: monospace;
+ color: var(--primary);
+}