diff --git a/newtab.html b/newtab.html
index aa1eac3..dd0bd02 100644
--- a/newtab.html
+++ b/newtab.html
@@ -509,6 +509,7 @@
+
diff --git a/src/css/main.css b/src/css/main.css
index bc0c866..4233370 100644
--- a/src/css/main.css
+++ b/src/css/main.css
@@ -1452,6 +1452,88 @@ body.show-desc .bm-desc { display: block; }
border-top: 1px solid var(--border);
}
+/* Calculator Game Modes (shared) */
+.calc-game-subtabs {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 8px;
+}
+.calc-game-subtab {
+ flex: 1;
+ padding: 5px 4px;
+ background: rgba(255,255,255,0.04);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-sm);
+ color: var(--text-muted);
+ font-size: 10px;
+ font-family: 'Rajdhani', sans-serif;
+ cursor: pointer;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ transition: all 0.15s;
+}
+.calc-game-subtab:hover {
+ color: var(--text-secondary);
+}
+.calc-game-subtab.active {
+ background: var(--accent-dim);
+ border-color: var(--accent);
+ color: var(--accent);
+ font-weight: 600;
+}
+.calc-game-field {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 4px;
+}
+.calc-game-field label {
+ font-size: 11px;
+ color: var(--text-secondary);
+ min-width: 90px;
+ flex-shrink: 0;
+}
+.calc-game-input {
+ flex: 1;
+ padding: 5px 8px;
+ background: rgba(0,0,0,0.3);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-sm);
+ color: var(--text-primary);
+ font-size: 13px;
+ font-family: 'Rajdhani', monospace;
+}
+.calc-game-output {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 6px 8px;
+ background: rgba(0,0,0,0.2);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-sm);
+ margin-top: 4px;
+}
+.calc-game-output span:first-child {
+ font-size: 11px;
+ color: var(--text-muted);
+}
+.calc-game-value {
+ font-size: 14px;
+ color: var(--accent);
+ font-weight: 600;
+ font-family: 'Rajdhani', monospace;
+}
+.calc-game-warning {
+ font-size: 10px;
+ color: var(--danger);
+ padding: 2px 0;
+}
+.calc-game-content {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
/* ============================================
TIMER WIDGET
============================================ */
diff --git a/src/js/calc-satisfactory.js b/src/js/calc-satisfactory.js
new file mode 100644
index 0000000..9eb60ae
--- /dev/null
+++ b/src/js/calc-satisfactory.js
@@ -0,0 +1,184 @@
+/* =============================================
+ HELLION NEWTAB — calc-satisfactory.js
+ Satisfactory Calculator Modus
+ ============================================= */
+
+(function() {
+ 'use strict';
+
+ const POWER_EXPONENT = 1.321928;
+ const SUB_MODES = ['itemsPerMin', 'power', 'machines'];
+ let _activeSubMode = 'itemsPerMin';
+
+ function createField(labelKey, defaultVal, opts) {
+ opts = opts || {};
+ const row = document.createElement('div');
+ row.className = 'calc-game-field';
+ const label = document.createElement('label');
+ label.textContent = t(labelKey);
+ const input = document.createElement('input');
+ input.type = 'number';
+ input.className = 'calc-game-input';
+ input.value = defaultVal;
+ if (opts.step) input.step = opts.step;
+ if (opts.min !== undefined) input.min = opts.min;
+ if (opts.max !== undefined) input.max = opts.max;
+ row.append(label, input);
+ return { row, input };
+ }
+
+ function createOutput(labelKey) {
+ const row = document.createElement('div');
+ row.className = 'calc-game-output';
+ const label = document.createElement('span');
+ label.textContent = t(labelKey);
+ const value = document.createElement('span');
+ value.className = 'calc-game-value';
+ row.append(label, value);
+ return { row, value };
+ }
+
+ function renderItemsPerMin(container) {
+ const itemsField = createField('calculator.sat.items_per_craft', 1, { step: 1, min: 1 });
+ const timeField = createField('calculator.sat.craft_time', 4, { step: 0.1, min: 0.1 });
+ const clockField = createField('calculator.sat.clock_speed', 100, { step: 1, min: 1, max: 250 });
+ const output = createOutput('calculator.sat.output_per_min');
+
+ function calc() {
+ const items = parseFloat(itemsField.input.value) || 0;
+ const time = parseFloat(timeField.input.value) || 1;
+ const clock = parseFloat(clockField.input.value) || 100;
+ const result = (items * 60) / time * (clock / 100);
+ output.value.textContent = Calculator._formatResult(result) + ' items/min';
+ }
+
+ [itemsField, timeField, clockField].forEach(f => f.input.addEventListener('input', calc));
+ container.append(itemsField.row, timeField.row, clockField.row, output.row);
+ calc();
+ }
+
+ function renderPower(container) {
+ const basePowerField = createField('calculator.sat.base_power', 30, { step: 1, min: 0.1 });
+ const clockField = createField('calculator.sat.clock_speed', 100, { step: 1, min: 1, max: 250 });
+ const powerOutput = createOutput('calculator.sat.power_usage');
+ const effOutput = createOutput('calculator.sat.efficiency');
+
+ function calc() {
+ const basePower = parseFloat(basePowerField.input.value) || 0;
+ const clock = parseFloat(clockField.input.value) || 100;
+ const ratio = clock / 100;
+ const power = basePower * Math.pow(ratio, POWER_EXPONENT);
+ const effPerItem = Math.pow(ratio, POWER_EXPONENT - 1);
+
+ powerOutput.value.textContent = Calculator._formatResult(power) + ' MW';
+
+ if (clock > 100) {
+ const overhead = (effPerItem - 1) * 100;
+ effOutput.value.textContent = '+' + Calculator._formatResult(overhead) + '% ' + t('calculator.sat.per_item');
+ effOutput.row.style.display = '';
+ } else {
+ effOutput.row.style.display = 'none';
+ }
+ }
+
+ [basePowerField, clockField].forEach(f => f.input.addEventListener('input', calc));
+ container.append(basePowerField.row, clockField.row, powerOutput.row, effOutput.row);
+ calc();
+ }
+
+ function renderMachines(container) {
+ const targetField = createField('calculator.sat.target_output', 60, { step: 1, min: 1 });
+ const itemsField = createField('calculator.sat.items_per_craft', 1, { step: 1, min: 1 });
+ const timeField = createField('calculator.sat.craft_time', 4, { step: 0.1, min: 0.1 });
+ const clockField = createField('calculator.sat.clock_speed', 100, { step: 1, min: 1, max: 250 });
+ const basePowerField = createField('calculator.sat.base_power', 30, { step: 1, min: 0.1 });
+ const machinesOutput = createOutput('calculator.sat.machines_needed');
+ const totalPowerOutput = createOutput('calculator.sat.total_power');
+
+ function calc() {
+ const target = parseFloat(targetField.input.value) || 0;
+ const items = parseFloat(itemsField.input.value) || 1;
+ const time = parseFloat(timeField.input.value) || 1;
+ const clock = parseFloat(clockField.input.value) || 100;
+ const basePower = parseFloat(basePowerField.input.value) || 0;
+ const ratio = clock / 100;
+ const itemsPerMin = (items * 60) / time * ratio;
+ const machines = itemsPerMin > 0 ? Math.ceil(target / itemsPerMin) : 0;
+ const totalPower = machines * basePower * Math.pow(ratio, POWER_EXPONENT);
+ machinesOutput.value.textContent = machines;
+ totalPowerOutput.value.textContent = Calculator._formatResult(totalPower) + ' MW';
+ }
+
+ [targetField, itemsField, timeField, clockField, basePowerField].forEach(f => f.input.addEventListener('input', calc));
+ container.append(targetField.row, itemsField.row, timeField.row, clockField.row, basePowerField.row, machinesOutput.row, totalPowerOutput.row);
+ calc();
+ }
+
+ async function loadState() {
+ const data = await Store.get(Calculator.STORAGE_KEY);
+ if (data && data.calculator && data.calculator.satisfactory) {
+ const s = data.calculator.satisfactory;
+ if (s.lastSubMode && SUB_MODES.includes(s.lastSubMode)) _activeSubMode = s.lastSubMode;
+ }
+ }
+
+ async function saveState() {
+ const data = await Store.get(Calculator.STORAGE_KEY) || {};
+ if (!data.calculator) data.calculator = {};
+ data.calculator.satisfactory = { lastSubMode: _activeSubMode };
+ await Store.set(Calculator.STORAGE_KEY, data);
+ }
+
+ function renderSubMode(container) {
+ container.textContent = '';
+ switch (_activeSubMode) {
+ case 'itemsPerMin': renderItemsPerMin(container); break;
+ case 'power': renderPower(container); break;
+ case 'machines': renderMachines(container); break;
+ }
+ }
+
+ Calculator.registerMode('satisfactory', {
+ label: '⚙️',
+ shortName: 'SAT',
+ titleKey: 'calculator.tab.satisfactory',
+
+ render(bodyEl) {
+ bodyEl.style.padding = '8px';
+ bodyEl.style.display = 'flex';
+ bodyEl.style.flexDirection = 'column';
+ bodyEl.style.gap = '8px';
+
+ loadState().then(() => {
+ const subContent = document.createElement('div');
+ subContent.className = 'calc-game-content';
+
+ const bar = document.createElement('div');
+ bar.className = 'calc-game-subtabs';
+
+ SUB_MODES.forEach(mode => {
+ const btn = document.createElement('button');
+ btn.type = 'button';
+ btn.className = 'calc-game-subtab' + (mode === _activeSubMode ? ' active' : '');
+ btn.textContent = t('calculator.sat.tab.' + mode);
+ btn.dataset.mode = mode;
+ btn.addEventListener('click', () => {
+ bar.querySelectorAll('.calc-game-subtab').forEach(b => b.classList.remove('active'));
+ btn.classList.add('active');
+ _activeSubMode = mode;
+ renderSubMode(subContent);
+ saveState();
+ });
+ bar.appendChild(btn);
+ });
+
+ bodyEl.append(bar, subContent);
+ renderSubMode(subContent);
+ });
+ },
+
+ destroy() {
+ saveState();
+ }
+ });
+})();
diff --git a/src/js/i18n.js b/src/js/i18n.js
index 59a1e13..5bfc326 100644
--- a/src/js/i18n.js
+++ b/src/js/i18n.js
@@ -107,6 +107,21 @@ const STRINGS = {
'calculator.conv.cat.volume': 'Volumen',
'calculator.conv.cat.speed': 'Geschwindigkeit',
'calculator.conv.cat.area': 'Fläche',
+ 'calculator.tab.satisfactory': 'Satisfactory',
+ 'calculator.sat.tab.itemsPerMin': 'Items/Min',
+ 'calculator.sat.tab.power': 'Strom',
+ 'calculator.sat.tab.machines': 'Maschinen',
+ 'calculator.sat.items_per_craft': 'Items/Craft',
+ 'calculator.sat.craft_time': 'Craftzeit (s)',
+ 'calculator.sat.clock_speed': 'Taktrate (%)',
+ 'calculator.sat.base_power': 'Grundleistung (MW)',
+ 'calculator.sat.target_output': 'Ziel Output/Min',
+ 'calculator.sat.output_per_min': 'Output',
+ 'calculator.sat.power_usage': 'Stromverbrauch',
+ 'calculator.sat.efficiency': 'Effizienz',
+ 'calculator.sat.per_item': 'pro Item',
+ 'calculator.sat.machines_needed': 'Maschinen benötigt',
+ 'calculator.sat.total_power': 'Gesamtleistung',
// Timer
'timer.title': 'Timer',
@@ -439,6 +454,21 @@ const STRINGS = {
'calculator.conv.cat.volume': 'Volume',
'calculator.conv.cat.speed': 'Speed',
'calculator.conv.cat.area': 'Area',
+ 'calculator.tab.satisfactory': 'Satisfactory',
+ 'calculator.sat.tab.itemsPerMin': 'Items/Min',
+ 'calculator.sat.tab.power': 'Power',
+ 'calculator.sat.tab.machines': 'Machines',
+ 'calculator.sat.items_per_craft': 'Items/Craft',
+ 'calculator.sat.craft_time': 'Craft Time (s)',
+ 'calculator.sat.clock_speed': 'Clock Speed (%)',
+ 'calculator.sat.base_power': 'Base Power (MW)',
+ 'calculator.sat.target_output': 'Target Output/Min',
+ 'calculator.sat.output_per_min': 'Output',
+ 'calculator.sat.power_usage': 'Power Usage',
+ 'calculator.sat.efficiency': 'Efficiency',
+ 'calculator.sat.per_item': 'per item',
+ 'calculator.sat.machines_needed': 'Machines needed',
+ 'calculator.sat.total_power': 'Total Power',
// Timer
'timer.title': 'Timer',