const fs = require('fs');
const path = require('path');

// Original nightTab source (input) lives next to this script.
const root = path.join(__dirname, 'quelle-nightTab');
// Output HTML: explicit arg, else default to the WebView2 project.
const out = process.argv[2] || path.join(__dirname, 'webview2', 'app-index.html');
const APPNAME = 'MyStart';

let css = fs.readFileSync(path.join(root, 'index.41b2d2a8cee846b032b5.css'), 'utf8');

const mime = { woff2: 'font/woff2', woff: 'font/woff', ttf: 'font/ttf' };
css = css.replace(/url\((font\/[^)]+)\)/g, (m, rel) => {
  const p = path.join(root, rel);
  const ext = rel.split('.').pop();
  const b64 = fs.readFileSync(p).toString('base64');
  return `url(data:${mime[ext] || 'application/octet-stream'};base64,${b64})`;
});

let initJs = fs.readFileSync(path.join(root, 'initialBackground.js'), 'utf8');
let mainJs = fs.readFileSync(path.join(root, 'index.09153abdbaa791fa4f0e.js'), 'utf8');

// --- 1) Remove the "Support" and "Coffee" entries from the settings menu ---
const navSnippet = '{name:"Support",active:!1,overscroll:!1},{name:"Coffee",active:!1,overscroll:!1},';
if (!mainJs.includes(navSnippet)) throw new Error('navData snippet not found — aborting');
mainJs = mainJs.replace(navSnippet, '');

// --- 1b) Rebuild the About page: logo + name + version + own website & git links ---
const aStart = 'const t=new Pa({text:"GitHub.';
const aEndMarker = ',s,o,n]))';
const i = mainJs.indexOf(aStart);
if (i < 0) throw new Error('About block start not found — aborting');
const j = mainJs.indexOf(aEndMarker, i);
if (j < 0) throw new Error('About block end not found — aborting');
const aboutBody =
  'const t=new Pa({text:"m-viper.de",href:"https://m-viper.de",openNew:!0}),' +
  'a=new Pa({text:"git.viper.ipv64.net",href:"https://git.viper.ipv64.net",openNew:!0}),' +
  's=y("p");s.innerHTML=`Website: ${t.link().outerHTML}`;' +
  'const o=y("p");o.innerHTML=`Git: ${a.link().outerHTML}`,' +
  'e.appendChild(y("div",[y("div|class:version",[_t.render(),' +
  'y("div|class:version-details",[y("h1:MyStart|class:version-app-name"),' +
  'y("p:Version 1.0.1|class:version-number")])]),y("hr"),s,o,y("div|id:mystart-autostart-row,class:mystart-autostart-row")]))';
mainJs = mainJs.slice(0, i) + aboutBody + mainJs.slice(j + aEndMarker.length);

// --- 2) Rename branding (visible text + storage keys) consistently ---
const rename = (s) => s.split('nightTab').join(APPNAME);
mainJs = rename(mainJs);
initJs = rename(initJs);

// --- 3) Import: accept BOTH original nightTab backups and MyStart backups ---
// After rename the two validation gates only accept the "MyStart" marker key;
// re-add acceptance of the original "nightTab" marker so old backups import too.
const importGates = [
  ['JSON.parse(t).MyStart||JSON.parse(t)[nt.toLowerCase()]',
   'JSON.parse(t).MyStart||JSON.parse(t).nightTab||JSON.parse(t)[nt.toLowerCase()]'],
  ['JSON.parse(r.target.result).MyStart||JSON.parse(r.target.result)[nt.toLowerCase()]',
   'JSON.parse(r.target.result).MyStart||JSON.parse(r.target.result).nightTab||JSON.parse(r.target.result)[nt.toLowerCase()]'],
];
for (const [from, to] of importGates) {
  if (!mainJs.includes(from)) throw new Error('import gate not found: ' + from);
  mainJs = mainJs.replace(from, to);
}

// --- 4) German UI: translate the DISPLAY of menu tabs/sub-tabs/headers only.
// The underlying name stays English because it is used as a routing key
// (makeId = first word lowercased). __TR maps display text, keyed by that id.
const menuMap = {
  theme:'Design', layout:'Layout', header:'Kopfzeile', bookmark:'Lesezeichen',
  group:'Gruppe', toolbar:'Werkzeugleiste', data:'Daten', mystart:'MyStart',
  preset:'Vorlage', saved:'Gespeichert', style:'Stil', colour:'Farbe',
  accent:'Akzent', font:'Schrift', radius:'Radius', shadow:'Schatten',
  shade:'Schattierung', opacity:'Deckkraft', background:'Hintergrund',
  search:'Suche', scaling:'Skalierung', area:'Bereich', padding:'Innenabstand',
  gutter:'Abstand', alignment:'Ausrichtung', page:'Seite', greeting:'Begrüßung',
  transitional:'Übergangswörter', clock:'Uhr', date:'Datum', general:'Allgemein',
  orientation:'Ausrichtung', sort:'Sortierung', name:'Name', size:'Größe',
  location:'Ort', position:'Position', controls:'Steuerung',
  restore:'Wiederherstellen', backup:'Sichern', clear:'Löschen',
};
const trInfra =
  'window.__MT=' + JSON.stringify(menuMap) + ';' +
  'window.__TR=function(s){if(s==null)return s;var k=String(s).split(" ")[0].toLowerCase();return window.__MT[k]||s;};';

// Autostart toggle: renders a CUSTOM slider switch into the About page's
// #mystart-autostart-row (native checkboxes are hidden by nightTab's CSS:
// opacity:0/position:absolute/pointer-events:none). Talks to the native host
// via postMessage; the host reads/writes the HKCU Run key.
const autostartJs = `(function(){
  var A={enabled:false,supported:!!(window.chrome&&window.chrome.webview)};
  window.__mystartAutostart=A;
  function paint(){
    var tr=document.getElementById('mystart-autostart-track');
    var kn=document.getElementById('mystart-autostart-knob');
    if(!tr||!kn)return;
    tr.style.background=A.enabled?'#2ea043':'#565d68';
    kn.style.left=A.enabled?'23px':'3px';
  }
  if(A.supported){
    window.chrome.webview.addEventListener('message',function(ev){
      var d=ev.data;if(d&&d.type==='autostart'){A.enabled=!!d.enabled;paint();}
    });
  }
  function render(row){
    var wrap=document.createElement('div');
    wrap.style.cssText='display:flex;align-items:center;gap:10px;margin-top:18px;cursor:pointer;user-select:none;';
    var track=document.createElement('div');
    track.id='mystart-autostart-track';
    track.style.cssText='position:relative;width:46px;height:26px;border-radius:13px;background:#565d68;flex:0 0 auto;transition:background .15s;box-sizing:border-box;';
    var knob=document.createElement('div');
    knob.id='mystart-autostart-knob';
    knob.style.cssText='position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;transition:left .15s;box-shadow:0 1px 2px rgba(0,0,0,.4);box-sizing:border-box;';
    track.appendChild(knob);
    var txt=document.createElement('span');
    txt.textContent='Mit Windows starten (minimiert)';
    if(!A.supported){wrap.style.opacity='0.5';wrap.style.cursor='default';wrap.title='Nur in der MyStart-App verfügbar.';}
    wrap.appendChild(track);wrap.appendChild(txt);row.appendChild(wrap);
    paint();
    wrap.addEventListener('click',function(){
      if(!A.supported)return;
      A.enabled=!A.enabled;paint();
      try{window.chrome.webview.postMessage({type:'autostart-set',value:A.enabled});}catch(e){}
    });
    if(A.supported){try{window.chrome.webview.postMessage({type:'autostart-get'});}catch(e){}}
  }
  function ensure(){
    var row=document.getElementById('mystart-autostart-row');
    if(row&&!document.getElementById('mystart-autostart-track'))render(row);
  }
  new MutationObserver(ensure).observe(document.documentElement,{childList:true,subtree:true});
  ensure();
})();`;

// Frameless-window controls (minimize / maximize-restore / close) in the top-right
// corner. Only shown inside the app (WebView2 host); they postMessage to the host.
const windowControlsJs = `(function(){
  if(!(window.chrome&&window.chrome.webview))return;
  function send(t){try{window.chrome.webview.postMessage({type:t});}catch(e){}}
  function mk(glyph,title,type,isClose){
    var b=document.createElement('div');
    b.textContent=glyph;b.title=title;
    b.style.cssText='width:44px;height:30px;display:flex;align-items:center;justify-content:center;font-family:"Segoe UI",system-ui,sans-serif;font-size:14px;line-height:1;color:#d0d4db;cursor:pointer;transition:background .1s,color .1s;-webkit-user-select:none;user-select:none;';
    b.onmouseenter=function(){b.style.background=isClose?'#e81123':'rgba(255,255,255,0.18)';b.style.color='#fff';};
    b.onmouseleave=function(){b.style.background='transparent';b.style.color='#d0d4db';};
    b.onclick=function(){send(type);};
    return b;
  }
  function mkGrip(){
    var g=document.createElement('div');
    g.title='Fenster verschieben (ziehen) — oder Alt + ziehen';
    g.style.cssText='width:34px;height:30px;display:flex;align-items:center;justify-content:center;color:#9aa0aa;cursor:move;-webkit-user-select:none;user-select:none;';
    g.innerHTML='<svg width="10" height="16" viewBox="0 0 10 16" fill="currentColor"><circle cx="2" cy="2" r="1.4"/><circle cx="8" cy="2" r="1.4"/><circle cx="2" cy="8" r="1.4"/><circle cx="8" cy="8" r="1.4"/><circle cx="2" cy="14" r="1.4"/><circle cx="8" cy="14" r="1.4"/></svg>';
    g.onmouseenter=function(){g.style.color='#fff';};
    g.onmouseleave=function(){g.style.color='#9aa0aa';};
    g.addEventListener('mousedown',function(ev){if(ev.button!==0)return;ev.preventDefault();send('window-drag');});
    return g;
  }
  function add(){
    if(!document.body||document.getElementById('mystart-winctrls'))return;
    var bar=document.createElement('div');
    bar.id='mystart-winctrls';
    bar.style.cssText='position:fixed;top:0;right:0;display:flex;align-items:center;z-index:2147483647;';
    bar.appendChild(mkGrip());
    bar.appendChild(mk('\\u2013','Minimieren','window-min',false));
    bar.appendChild(mk('\\u25A1','Maximieren / Wiederherstellen','window-max',false));
    bar.appendChild(mk('\\u2715','Schließen','window-close',true));
    document.body.appendChild(bar);
  }
  if(document.body)add();else document.addEventListener('DOMContentLoaded',add);
  new MutationObserver(function(){if(!document.getElementById('mystart-winctrls'))add();}).observe(document.documentElement,{childList:true,subtree:true});
  // Alt + left-drag anywhere -> move the window (non-blocking).
  document.addEventListener('mousedown',function(ev){
    if(ev.button===0&&ev.altKey){ev.preventDefault();send('window-drag');}
  },true);
  // Edge/corner resize: the WebView fills the whole window, so the OS never
  // sees the real window border to hit-test for a resize drag -- every mouse
  // event lands in the page first. Watch the pointer ourselves near the
  // viewport edges and hand off to the native resize loop, same trick as
  // the drag grip above.
  var RM=6; // px from the true edge that counts as a resize zone
  var CURSOR={n:'ns-resize',s:'ns-resize',e:'ew-resize',w:'ew-resize',
    ne:'nesw-resize',sw:'nesw-resize',nw:'nwse-resize',se:'nwse-resize'};
  function edgeAt(x,y){
    var w=window.innerWidth,h=window.innerHeight;
    var l=x<=RM,r=x>=w-RM,t=y<=RM,b=y>=h-RM;
    if(t&&l)return'nw';if(t&&r)return'ne';if(b&&l)return'sw';if(b&&r)return'se';
    if(l)return'w';if(r)return'e';if(t)return'n';if(b)return's';
    return null;
  }
  document.addEventListener('mousemove',function(ev){
    if(ev.buttons)return; // an active drag (e.g. scrollbar) is in progress -> leave it alone
    var onCtrls=ev.target.closest&&ev.target.closest('#mystart-winctrls');
    var edge=onCtrls?null:edgeAt(ev.clientX,ev.clientY);
    document.documentElement.style.cursor=edge?CURSOR[edge]:'';
  },true);
  document.addEventListener('mousedown',function(ev){
    if(ev.button!==0)return;
    if(ev.target.closest&&ev.target.closest('#mystart-winctrls'))return;
    var edge=edgeAt(ev.clientX,ev.clientY);
    if(edge){ev.preventDefault();send2('window-resize',{edge:edge});}
  },true);
  document.addEventListener('mouseleave',function(){document.documentElement.style.cursor='';},true);
  function send2(t,extra){try{window.chrome.webview.postMessage(Object.assign({type:t},extra));}catch(e){}}
})();`;

mainJs = trInfra + autostartJs + windowControlsJs + mainJs;

const trPatches = [
  // panel header (top-level AND sub, both go through element.header)
  ['y("h1:"+e+"|class:menu-item-header-text")',
   'y("h1:"+window.__TR(e)+"|class:menu-item-header-text")'],
  // top-level nav tab label
  ['new Fe({text:e.name,style:["link"],block:!0,classList:["menu-nav-tab"]',
   'new Fe({text:window.__TR(e.name),style:["link"],block:!0,classList:["menu-nav-tab"]'],
  // sub-level nav label (href keeps makeId -> English routing key)
  ['y("a:"+e+"|href:#menu-content-item-"+this.makeId(e)',
   'y("a:"+window.__TR(e)+"|href:#menu-content-item-"+this.makeId(e)'],
];
for (const [from, to] of trPatches) {
  if (!mainJs.includes(from)) throw new Error('translate patch not found: ' + from);
  mainJs = mainJs.replace(from, to);
}

// --- 5) Translate safe, unique display strings (search box, greeting, key texts).
// Tolerant: each is applied only if the exact literal is present. Structural
// names and icon labels are deliberately NOT touched.
const dict = [
  // search box placeholder (base + engine name is appended after it)
  ['?"Find bookmarks or search":"Search"', '?"Lesezeichen finden oder suchen mit":"Suchen mit"'],
  // greeting words
  ['"Good morning"', '"Guten Morgen"'],
  ['"Good afternoon"', '"Guten Tag"'],
  ['"Good evening"', '"Guten Abend"'],
  ['"Good night"', '"Gute Nacht"'],
  ['"Hello"', '"Hallo"'],
  ['"Welcome"', '"Willkommen"'],
  ['"Greetings"', '"Grüße"'],
  // Data panel / confirmation descriptions (post-rename -> contain MyStart)
  ['"Restore a previously exported MyStart backup."', '"Eine zuvor exportierte MyStart-Sicherung wiederherstellen."'],
  ['"Restoring from a MyStart backup"', '"Aus einer MyStart-Sicherung wiederherstellen"'],
  ['"Clear all data to reset MyStart to the default state."', '"Alle Daten löschen, um MyStart auf den Ausgangszustand zurückzusetzen."'],
  ['"Clear MyStart data except bookmarks?"', '"MyStart-Daten außer Lesezeichen löschen?"'],
  ['"Or drop a MyStart backup file here."', '"Oder ziehe eine MyStart-Sicherungsdatei hierher."'],
  // universal button
  ['text:"Add"', 'text:"Hinzufügen"'],
];
for (const [from, to] of dict) {
  if (mainJs.includes(from)) mainJs = mainJs.split(from).join(to);
}

// --- 6) Full German UI: translate every remaining visible control/label/tooltip.
// Applied ONLY to value positions (:"...") so routing names (name:"Theme",
// sub:["Style"], case"layout") and the icon database stay untouched. The button
// behaviour lives in func()/keys, never in the display text, so this is safe.
const chrome = Object.entries(JSON.parse(fs.readFileSync(path.join(__dirname, 'lang', 'de.json'), 'utf8')));
const _unusedChrome = [
  ['Add', 'Hinzufügen'],
  ['Add 10 random bookmarks', '10 zufällige Lesezeichen hinzufügen'],
  ['Add a group', 'Gruppe hinzufügen'],
  ['Add a new Bookmark', 'Neues Lesezeichen hinzufügen'],
  ['Add a new Group', 'Neue Gruppe hinzufügen'],
  ['Add unique accent to each Bookmark', 'Jedem Lesezeichen eigene Akzentfarbe geben'],
  ['Adjust Visual Element position', 'Position des Symbols anpassen'],
  ['Area alignment', 'Ausrichtung des Bereichs'],
  ['Bold', 'Fett'],
  ['Bookmark area alignment', 'Ausrichtung des Lesezeichen-Bereichs'],
  ['Bookmark area background colour', 'Hintergrundfarbe des Lesezeichen-Bereichs'],
  ['By icon', 'Nach Icon'],
  ['By letter', 'Nach Buchstabe'],
  ['By name', 'Nach Name'],
  ['Clear all data', 'Alle Daten löschen'],
  ['Clear all except bookmarks', 'Alles außer Lesezeichen löschen'],
  ['Clear all MyStart data?', 'Alle MyStart-Daten löschen?'],
  ['Clear search', 'Suche leeren'],
  ['Close settings menu', 'Einstellungen schließen'],
  ['Collapse this Group', 'Diese Gruppe einklappen'],
  ['Copy to clipboard', 'In die Zwischenablage kopieren'],
  ['Drag bookmark to reorder', 'Lesezeichen ziehen zum Umsortieren'],
  ['Drag group to reorder', 'Gruppe ziehen zum Umsortieren'],
  ['Drag header item to reorder', 'Kopfzeilen-Element ziehen zum Umsortieren'],
  ['Edit saved themes', 'Gespeicherte Designs bearbeiten'],
  ['Edit this bookmark', 'Dieses Lesezeichen bearbeiten'],
  ['Edit this group', 'Diese Gruppe bearbeiten'],
  ['Edit this saved theme', 'Dieses gespeicherte Design bearbeiten'],
  ['Edit unnamed bookmark', 'Unbenanntes Lesezeichen bearbeiten'],
  ['Edit unnamed group', 'Unbenannte Gruppe bearbeiten'],
  ['Enter edit bookmark mode', 'Bearbeitungsmodus für Lesezeichen'],
  ['Export data', 'Daten exportieren'],
  ['Google Font', 'Google-Schriftart'],
  ['Google font name', 'Name der Google-Schriftart'],
  ['Group details area alignment', 'Ausrichtung des Gruppen-Detailbereichs'],
  ['Header area alignment', 'Ausrichtung des Kopfzeilen-Bereichs'],
  ['Header background colour', 'Hintergrundfarbe der Kopfzeile'],
  ['Header item alignment', 'Ausrichtung der Kopfzeilen-Elemente'],
  ['Hide all', 'Alle ausblenden'],
  ['How to link to a video file.', 'So verlinkst du eine Videodatei.'],
  ['Import', 'Importieren'],
  ['Import from clipboard', 'Aus Zwischenablage importieren'],
  ['Large button', 'Große Schaltfläche'],
  ['Layout Direction', 'Layout-Richtung'],
  ['Layout background colour', 'Hintergrundfarbe des Layouts'],
  ['Light', 'Dünn'],
  ['Line button', 'Linien-Schaltfläche'],
  ['Link button', 'Link-Schaltfläche'],
  ['Medium button', 'Mittlere Schaltfläche'],
  ['More controls', 'Mehr Optionen'],
  ['Move this bookmark left', 'Dieses Lesezeichen nach links'],
  ['Move this bookmark right', 'Dieses Lesezeichen nach rechts'],
  ['Move this group down', 'Diese Gruppe nach unten'],
  ['Move this group right', 'Diese Gruppe nach rechts'],
  ['Move this group up', 'Diese Gruppe nach oben'],
  ['Name hide', 'Name ausblenden'],
  ['Name show', 'Name anzeigen'],
  ['New Bookmark', 'Neues Lesezeichen'],
  ['New Group', 'Neue Gruppe'],
  ['New Tab', 'Neuer Tab'],
  ['Only icons', 'Nur Icons'],
  ['Only images', 'Nur Bilder'],
  ['Only letters', 'Nur Buchstaben'],
  ['Open all Bookmarks in this Group', 'Alle Lesezeichen dieser Gruppe öffnen'],
  ['Open settings menu', 'Einstellungen öffnen'],
  ['Random Group name', 'Zufälliger Gruppenname'],
  ['Random colour', 'Zufällige Farbe'],
  ['Random theme name', 'Zufälliger Designname'],
  ['Randomise now', 'Jetzt zufällig'],
  ['Regular', 'Normal'],
  ['Remove', 'Entfernen'],
  ['Remove all accent overrides', 'Alle Akzent-Überschreibungen entfernen'],
  ['Remove icon', 'Icon entfernen'],
  ['Remove this bookmark', 'Dieses Lesezeichen entfernen'],
  ['Remove this group', 'Diese Gruppe entfernen'],
  ['Remove this saved theme', 'Dieses gespeicherte Design entfernen'],
  ['Remove unnamed bookmark', 'Unbenanntes Lesezeichen entfernen'],
  ['Reset to default', 'Auf Standard zurücksetzen'],
  ['Ring button', 'Ring-Schaltfläche'],
  ['Save', 'Speichern'],
  ['Save current theme', 'Aktuelles Design speichern'],
  ['Scrollbar', 'Bildlaufleiste'],
  ['Search Bookmarks or', 'Lesezeichen durchsuchen oder'],
  ['Search box size', 'Größe des Suchfelds'],
  ['Search box width', 'Breite des Suchfelds'],
  ['Search engine', 'Suchmaschine'],
  ['Search engine name', 'Name der Suchmaschine'],
  ['Search text alignment', 'Textausrichtung der Suche'],
  ['Show all', 'Alle anzeigen'],
  ['Small button', 'Kleine Schaltfläche'],
  ['Start of the week', 'Wochenbeginn'],
  ['Toolbar position', 'Position der Werkzeugleiste'],
  ['Visual Element and Name alignment', 'Ausrichtung von Symbol und Name'],
  ['Why has this changed?', 'Warum hat sich das geändert?'],
  ['Word length', 'Wortlänge'],
  ['Wording', 'Formulierung'],
  ['You can restore all or parts of a backup file. The following data will be restored:',
   'Du kannst eine Sicherung ganz oder teilweise wiederherstellen. Folgende Daten werden wiederhergestellt:'],
  // placeholders
  ['Example', 'Beispiel'],
  ['Example group', 'Beispielgruppe'],
  ['Example theme', 'Beispiel-Design'],
  ['FontAwesome Brands or Icons', 'FontAwesome Brands oder Icons'],
  ['Hex code', 'Hex-Code'],
  ['Nickname, alias or superhero name', 'Spitzname, Alias oder Heldenname'],
];
// Locate the FontAwesome icon array (mr=[{name:"500px"...]) so we NEVER touch it.
const iconStart = mainJs.indexOf('mr=[{name:"500px"');
let iconEnd = -1;
if (iconStart >= 0) {
  const bracket = mainJs.indexOf('[', iconStart);
  let depth = 0;
  for (let i = bracket; i < mainJs.length; i++) {
    const c = mainJs[i];
    if (c === '[') depth++;
    else if (c === ']') { depth--; if (depth === 0) { iconEnd = i + 1; break; } }
    else if (c === '"') { i++; while (i < mainJs.length && mainJs[i] !== '"') { if (mainJs[i] === '\\') i++; i++; } }
  }
}
if (iconStart < 0 || iconEnd < 0) throw new Error('icon region not found — aborting translation');

const before = mainJs.slice(0, iconStart);
const iconRegion = mainJs.slice(iconStart, iconEnd);
const after = mainJs.slice(iconEnd);

// Only translate genuine DISPLAY properties, and only outside the icon data.
const displayProps = ['labelText', 'text', 'description', 'label', 'title', 'placeholder', 'heading', 'successText', 'tabText'];
const jsEsc = (v) => v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
const translateChrome = (s) => {
  for (const [en, de] of chrome) {
    const deEsc = jsEsc(de);
    for (const p of displayProps) {
      const from = p + ':"' + en + '"';
      if (s.includes(from)) s = s.split(from).join(p + ':"' + deEsc + '"');
    }
  }
  return s;
};
mainJs = translateChrome(before) + iconRegion + translateChrome(after);

// --- 7) Long help/feedback/description sentences (y-DSL `y("p:..")`, text:[..] arrays,
// and description:"..."). Safe via exact match because these strings are long & unique.
const de2 = Object.entries(JSON.parse(fs.readFileSync(path.join(__dirname, 'lang', 'de2.json'), 'utf8')));
for (const [en, de] of de2) {
  const deEsc = jsEsc(de);
  // quoted literal (arrays, description:"...", any "..." occurrence)
  mainJs = mainJs.split('"' + en + '"').join('"' + deEsc + '"');
  // y-DSL with trailing attributes:  y("p:TEXT|class:..")
  mainJs = mainJs.split(':' + en + '|').join(':' + deEsc + '|');
  // y-DSL without attributes:  y("p:TEXT")
  mainJs = mainJs.split(':' + en + '"').join(':' + deEsc + '"');
}

// --- 8) Two font-field hints that contain escaped quotes in the source literal. ---
const fontHints = [
  ['Clear the field to use the default font "Fjalla One".', 'Feld leeren, um die Standardschrift "Fjalla One" zu verwenden.'],
  ['Clear the field to use the default font "Open Sans".', 'Feld leeren, um die Standardschrift "Open Sans" zu verwenden.'],
];
for (const [en, de] of fontHints) {
  if (mainJs.includes(en)) mainJs = mainJs.split(en).join(de);
}

const favSvg = fs.readFileSync(path.join(root, 'icon/favicon.svg'));
const favData = 'data:image/svg+xml;base64,' + favSvg.toString('base64');

const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"><title>${APPNAME}</title><link rel="icon" type="image/svg+xml" class="favicon" href="${favData}"/><style media="screen">html,body {background-color: rgb(0, 0, 0);}@media (prefers-color-scheme: dark) {html,body {background-color: rgb(0, 0, 0);}}@media (prefers-color-scheme: light) {html,body {background-color: rgb(255, 255, 255);}}</style>
<style>${css}</style>
<style>/* Scrollbalken ans dunkle MyStart-Design anpassen (schlank, dunkel, ohne Pfeile) */
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background-color:rgba(255,255,255,0.22);border-radius:8px;border:2px solid transparent;background-clip:padding-box;}
::-webkit-scrollbar-thumb:hover{background-color:rgba(255,255,255,0.38);background-clip:padding-box;}
::-webkit-scrollbar-button{display:none;height:0;width:0;}
::-webkit-scrollbar-corner{background:transparent;}</style>
<script>${initJs}</script>
</head><body>
<script>${mainJs}</script>
</body></html>`;

fs.writeFileSync(out, html);
const kb = (fs.statSync(out).size / 1024).toFixed(0);
console.log('Written: ' + out + ' (' + kb + ' KB)  [Support/Coffee removed, renamed to ' + APPNAME + ']');
