nits
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Fri, 6 Mar 2026 13:08:19 +0000 (13:08 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Fri, 6 Mar 2026 13:08:19 +0000 (13:08 +0000)
38 files changed:
consumer/release/RT/core/body_visibility_hidden.js [new file with mode: 0644]
consumer/release/RT/core/body_visibility_visible.js [new file with mode: 0644]
consumer/release/RT/core/loader.js [new file with mode: 0644]
consumer/release/RT/core/utility.js [new file with mode: 0644]
consumer/release/RT/element/TOC.js [new file with mode: 0644]
consumer/release/RT/element/code.js [new file with mode: 0644]
consumer/release/RT/element/math.js [new file with mode: 0644]
consumer/release/RT/element/term.js [new file with mode: 0644]
consumer/release/RT/element/theme_selector.js [new file with mode: 0644]
consumer/release/RT/element/title.js [new file with mode: 0644]
consumer/release/RT/layout/article_tech_ref.js [new file with mode: 0644]
consumer/release/RT/layout/memo_State.js [new file with mode: 0644]
consumer/release/RT/layout/page_fixed_glow.js [new file with mode: 0644]
consumer/release/RT/layout/paginate_by_element.js [new file with mode: 0644]
consumer/release/RT/theme/dark_gold.js [new file with mode: 0644]
consumer/release/RT/theme/light.js [new file with mode: 0644]
consumer/release/RT/theme/light_gold.js [new file with mode: 0644]
developer/authored/RT/core/body_visibility_hidden.js [new file with mode: 0644]
developer/authored/RT/core/body_visibility_visible.js [new file with mode: 0644]
developer/authored/RT/core/loader.js [new file with mode: 0644]
developer/authored/RT/core/utility.js [new file with mode: 0644]
developer/authored/RT/element/TOC.js [new file with mode: 0644]
developer/authored/RT/element/code.js [new file with mode: 0644]
developer/authored/RT/element/math.js [new file with mode: 0644]
developer/authored/RT/element/term.js [new file with mode: 0644]
developer/authored/RT/element/theme_selector.js [new file with mode: 0644]
developer/authored/RT/element/title.js [new file with mode: 0644]
developer/authored/RT/layout/article_tech_ref.js [new file with mode: 0644]
developer/authored/RT/layout/memo_State.js [new file with mode: 0644]
developer/authored/RT/layout/page_fixed_glow.js [new file with mode: 0644]
developer/authored/RT/layout/paginate_by_element.js [new file with mode: 0644]
developer/authored/RT/theme/dark_gold.js [new file with mode: 0644]
developer/authored/RT/theme/light.js [new file with mode: 0644]
developer/authored/RT/theme/light_gold.js [new file with mode: 0644]
developer/authored/hello.cli.c [deleted file]
developer/tool/do_all
developer/tool/make
developer/tool/release

diff --git a/consumer/release/RT/core/body_visibility_hidden.js b/consumer/release/RT/core/body_visibility_hidden.js
new file mode 100644 (file)
index 0000000..d6a178a
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+  Targets the root element to ensure total blackout during load.
+*/
+function body_visibility_hidden(){
+  const gate = document.createElement('style');
+  gate.id = 'rt-visibility-gate';
+  gate.textContent = 'html{visibility:hidden !important; background:black !important;}';
+  document.head.appendChild(gate);
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.body_visibility_hidden = body_visibility_hidden;
diff --git a/consumer/release/RT/core/body_visibility_visible.js b/consumer/release/RT/core/body_visibility_visible.js
new file mode 100644 (file)
index 0000000..ff1c4b6
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+  Restores visibility by removing the visibility gate.
+*/
+function body_visibility_visible(){
+  const gate = document.getElementById('rt-visibility-gate');
+  if (gate){
+    gate.remove();
+  }
+  document.body.style.visibility = 'visible';
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.body_visibility_visible = body_visibility_visible;
diff --git a/consumer/release/RT/core/loader.js b/consumer/release/RT/core/loader.js
new file mode 100644 (file)
index 0000000..3f4ee68
--- /dev/null
@@ -0,0 +1,27 @@
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.include = function(path_identifier){
+  let parts_seq = path_identifier.split('/');
+  let namespace = parts_seq[0];
+  
+  let module_path = parts_seq.slice(1).join('/');
+
+  if(module_path === 'theme'){
+    let saved_theme = localStorage.getItem('RT_theme_preference');
+    if(!saved_theme){
+      saved_theme = 'dark_gold';
+      localStorage.setItem('RT_theme_preference' ,saved_theme);
+    }
+    module_path = 'theme/' + saved_theme;
+  }
+
+  let base_path = window.StyleRT_namespaces[namespace];
+  if(!base_path){
+    console.error("Namespace not found: " + namespace);
+    return;
+  }
+
+  let full_path = base_path + '/' + module_path + '.js';
+  // FIXED: No backslashes in the closing script tag
+  document.write('<script src="' + full_path + '"></script>');
+};
diff --git a/consumer/release/RT/core/utility.js b/consumer/release/RT/core/utility.js
new file mode 100644 (file)
index 0000000..258eb28
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  General utilities for the StyleRT library.
+*/
+
+window.StyleRT = window.StyleRT || {};
+
+// --- DEBUG SYSTEM ---
+window.StyleRT.debug = {
+
+  // all debug messages enabled
+/*
+  active_tokens: new Set([
+    'style', 'layout', 'pagination'
+    ,'selector', 'config', 'error'
+    ,'term'
+  ]),
+*/
+  active_tokens: new Set([
+    'term'
+  ]),
+  
+  log: function(token, message) {
+    if (this.active_tokens.has(token)) {
+      console.log(`[StyleRT:${token}]`, message);
+    }
+  },
+
+  warn: function(token, message) {
+    if (this.active_tokens.has(token)) {
+      console.warn(`[StyleRT:${token}]`, message);
+    }
+  },
+  
+  // New: Always log errors regardless of token, but tag them
+  error: function(token, message) {
+    console.error(`[StyleRT:${token}] CRITICAL:`, message);
+  },
+  
+  enable: function(token) { this.active_tokens.add(token); console.log(`Enabled: ${token}`); },
+  disable: function(token) { this.active_tokens.delete(token); console.log(`Disabled: ${token}`); }
+};
+
+// --- UTILITIES ---
+window.StyleRT.utility = {
+  // --- FONT PHYSICS ---
+  measure_ink_ratio: function(target_font, ref_font = null) {
+    const debug = window.StyleRT.debug;
+    debug.log('layout', `Measuring ink ratio for ${target_font}`);
+
+    const canvas = document.createElement('canvas');
+    const ctx = canvas.getContext('2d');
+
+    if (!ref_font) {
+      const bodyStyle = window.getComputedStyle(document.body);
+      ref_font = bodyStyle.fontFamily;
+    }
+
+    const get_metrics = (font) => {
+      ctx.font = '100px ' + font; 
+      const metrics = ctx.measureText('M');
+      return {
+        ascent: metrics.actualBoundingBoxAscent, 
+        descent: metrics.actualBoundingBoxDescent 
+      };
+    };
+
+    const ref_m = get_metrics(ref_font);
+    const target_m = get_metrics(target_font);
+    
+    const ratio = ref_m.ascent / target_m.ascent;
+    // debug.log('layout', `Ink Ratio calculated: ${ratio.toFixed(3)}`);
+
+    return { 
+      ratio: ratio,
+      baseline_diff: ref_m.descent - target_m.descent 
+    };
+  },
+
+  // --- COLOR PHYSICS ---
+  is_color_light: function(color_string) {
+    const debug = window.StyleRT.debug;
+    
+    // 1. HSL Check
+    if (color_string.startsWith('hsl')) {
+      const numbers = color_string.match(/\d+/g);
+      if (numbers && numbers.length >= 3) {
+        const lightness = parseInt(numbers[2]);
+        return lightness > 50;
+      }
+    }
+
+    // 2. RGB Check
+    const rgb = color_string.match(/\d+/g);
+    if (!rgb) {
+      // debug.warn('color_layout', `Failed to parse color: "${color_string}". Defaulting to Light.`);
+      return true; 
+    }
+
+    const r = parseInt(rgb[0]);
+    const g = parseInt(rgb[1]);
+    const b = parseInt(rgb[2]);
+    const luma = (r * 299 + g * 587 + b * 114) / 1000;
+    return luma > 128;
+  },
+
+  is_block_content: function(element) {
+    return element.textContent.trim().includes('\n');
+  }
+};
diff --git a/consumer/release/RT/element/TOC.js b/consumer/release/RT/element/TOC.js
new file mode 100644 (file)
index 0000000..eb246f5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  Processes <RT-TOC> tags.
+  Populates each with headings found below it.
+
+  Attributes:
+    level="N" : Explicitly sets the target heading level (1-6).
+                e.g., level="1" collects H1s. level="2" collects H2s.
+                Stops collecting if it hits a heading of (level - 1) or higher.
+
+  Default (No attribute):
+    Context Aware. Looks backwards for the nearest heading H(N).
+    Targets H(N+1). Stops at the next H(N).
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.TOC = function(){
+  const debug = window.StyleRT.debug || { log: function(){} };
+  const TOC_seq = document.querySelectorAll('rt-toc');
+
+  TOC_seq.forEach( (container ,TOC_index) => {
+    container.style.display = 'block';
+
+    // 1. Determine Target Level
+    const attr_level = parseInt( container.getAttribute('level') );
+    let target_level;
+
+    if( !isNaN(attr_level) ){
+       // EXPLICIT MODE
+       target_level = attr_level;
+       if(debug.log) debug.log('TOC' ,`TOC #${TOC_index} explicit target: H${target_level}`);
+    } else {
+       // IMPLICIT / CONTEXT MODE
+       let context_level = 0; // Default 0 (Root)
+       let prev = container.previousElementSibling;
+       while(prev){
+         const match = prev.tagName.match(/^H([1-6])$/);
+         if(match){
+           context_level = parseInt( match[1] );
+           break;
+         }
+         prev = prev.previousElementSibling;
+       }
+       target_level = context_level + 1;
+       if(debug.log) debug.log('TOC' ,`TOC #${TOC_index} context implied target: H${target_level}`);
+    }
+
+    // Stop condition: Stop if we hit a heading that is a "parent" or "sibling" of the context.
+    // Mathematically: Stop if found_level < target_level.
+    const stop_threshold = target_level;
+
+    // 2. Setup Container
+    container.innerHTML = '';
+    const title = document.createElement('h1');
+    // Title logic: If targeting H1, the element serves as a Main TOC. Otherwise the element serves as a Section TOC.
+    title.textContent = target_level === 1 ? 'Table of Contents' : 'Section Contents';
+    title.style.textAlign = 'center';
+    container.appendChild(title);
+
+    const list = document.createElement('ul');
+    list.style.listStyle = 'none';
+    list.style.paddingLeft = '0';
+    container.appendChild(list);
+
+    // 3. Scan Forward
+    let next_el = container.nextElementSibling;
+    while(next_el){
+      const match = next_el.tagName.match(/^H([1-6])$/);
+      if(match){
+        const found_level = parseInt( match[1] );
+
+        // STOP Logic:
+        // If we are looking for H2s, we stop if we hit an H1 (level 1).
+        // If we are looking for H1s, we stop if we hit nothing (level 0).
+        if(found_level < target_level){
+          break;
+        }
+
+        // COLLECT Logic:
+        if(found_level === target_level){
+          if(!next_el.id) next_el.id = `TOC-ref-${TOC_index}-${found_level}-${list.children.length}`;
+
+          const li = document.createElement('li');
+          li.style.marginBottom = '0.5rem';
+
+          const a = document.createElement('a');
+          a.href = `#${next_el.id}`;
+          a.textContent = next_el.textContent;
+          a.style.textDecoration = 'none';
+          a.style.color = 'inherit';
+          a.style.display = 'block';
+
+          a.onmouseover = () => a.style.color = 'var(--rt-brand-primary)';
+          a.onmouseout = () => a.style.color = 'inherit';
+
+          li.appendChild(a);
+          list.appendChild(li);
+        }
+      }
+      next_el = next_el.nextElementSibling;
+    }
+  });
+};
diff --git a/consumer/release/RT/element/code.js b/consumer/release/RT/element/code.js
new file mode 100644 (file)
index 0000000..7e6dca8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Processes <RT-CODE> tags.
+  Uses the central config or CSS variables from the theme.
+
+  Removes common indent from lines of code.
+*/
+function code() {
+  const RT = window.StyleRT;
+  const U = RT.utility;
+  const debug = RT.debug;
+
+  debug.log('code', 'Starting render cycle.');
+
+  const metrics = U.measure_ink_ratio('monospace');
+  
+  document.querySelectorAll('rt-code').forEach((el) => {
+    el.style.fontFamily = 'monospace';
+    
+    const computed = window.getComputedStyle(el);
+    const accent = computed.getPropertyValue('--rt-accent').trim() || 'gold';
+    
+    const is_block = U.is_block_content(el);
+    const parentColor = computed.color;
+    const is_text_light = U.is_color_light(parentColor);
+    
+    const alpha = is_block ? 0.08 : 0.15;
+    const overlay = is_text_light ? `rgba(255,255,255,${alpha})` : `rgba(0,0,0,${alpha})`;
+    const text_color = is_text_light ? '#ffffff' : '#000000';
+
+    el.style.backgroundColor = overlay;
+
+    if (is_block) {
+      el.style.display = 'block';
+
+      // --- Tag-Relative Auto-Dedent Logic ---
+      
+      // 1. Get Tag Indentation (The Anchor)
+      let tagIndent = '';
+      const prevNode = el.previousSibling;
+      if (prevNode && prevNode.nodeType === 3) {
+        const prevText = prevNode.nodeValue;
+        const lastNewLineIndex = prevText.lastIndexOf('\n');
+        if (lastNewLineIndex !== -1) {
+          tagIndent = prevText.substring(lastNewLineIndex + 1);
+        } else if (/^\s*$/.test(prevText)) {
+          tagIndent = prevText;
+        }
+      }
+
+      // 2. Calculate Common Leading Whitespace from Content
+      const rawLines = el.textContent.split('\n');
+      
+      // Filter out empty lines for calculation purposes so they don't break the logic
+      const contentLines = rawLines.filter(line => line.trim().length > 0);
+
+      let commonIndent = null;
+
+      if (contentLines.length > 0) {
+        // Assume the first line sets the standard
+        const firstMatch = contentLines[0].match(/^\s*/);
+        commonIndent = firstMatch ? firstMatch[0] : '';
+
+        // Reduce the commonIndent if subsequent lines have LESS indentation
+        for (let i = 1; i < contentLines.length; i++) {
+          const line = contentLines[i];
+          // Determine how much of commonIndent this line shares
+          let j = 0;
+          while (j < commonIndent.length && j < line.length && commonIndent[j] === line[j]) {
+            j++;
+          }
+          commonIndent = commonIndent.substring(0, j);
+          if (commonIndent.length === 0) break; // Optimization
+        }
+      } else {
+        commonIndent = '';
+      }
+
+      // 3. Process Content
+      // Rule: Only strip if the Common Indent contains the Tag Indent (Safety Check)
+      // This handles the Emacs case: Tag is "  ", Common is "    ". "    " starts with "  ".
+      // We strip "    ", leaving the code flush left.
+      let finalString = '';
+
+      if (commonIndent.length > 0 && commonIndent.startsWith(tagIndent)) {
+         const cleanedLines = rawLines.map(line => {
+            // Strip the common indent from valid lines
+            return line.startsWith(commonIndent) ? line.replace(commonIndent, '') : line;
+         });
+
+         // Remove artifact lines (first/last empty lines)
+         if (cleanedLines.length > 0 && cleanedLines[0].length === 0) {
+           cleanedLines.shift();
+         }
+         if (cleanedLines.length > 0 && cleanedLines[cleanedLines.length - 1].trim().length === 0) {
+            cleanedLines.pop();
+         }
+         finalString = cleanedLines.join('\n');
+      } else {
+         // Fallback: Code is to the left of the tag or weirdly formatted. 
+         // Just trim the wrapper newlines.
+         finalString = el.textContent.trim();
+      }
+
+      el.textContent = finalString;
+      // --- End Indentation Logic ---
+
+      el.style.whiteSpace = 'pre';
+      el.style.fontSize = (parseFloat(computed.fontSize) * metrics.ratio * 0.95) + 'px'; 
+      el.style.padding = '1.2rem';
+      el.style.margin = '1.5rem 0';
+      el.style.borderLeft = `4px solid ${accent}`;
+      el.style.color = 'inherit'; 
+    } else {
+      el.style.display = 'inline';
+      const exactPx = parseFloat(computed.fontSize) * metrics.ratio * 1.0; 
+      el.style.fontSize = exactPx + 'px';
+      el.style.padding = '0.1rem 0.35rem';
+      el.style.borderRadius = '3px';
+      const offsetPx = metrics.baseline_diff * (exactPx / 100);
+      el.style.verticalAlign = offsetPx + 'px';
+      el.style.color = text_color; 
+    }
+  });
+  
+  debug.log('code', 'Render cycle complete.');
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.code = code;
diff --git a/consumer/release/RT/element/math.js b/consumer/release/RT/element/math.js
new file mode 100644 (file)
index 0000000..1e2ae8f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Processes <RT-MATH> tags.
+  JavaScript: math() 
+  HTML Tag: <RT-MATH> (parsed as rt-math)
+*/
+function math(){
+  // querySelector treats 'rt-math' as case-insensitive for the tag
+  document.querySelectorAll('rt-math').forEach(el => {
+    if (el.textContent.startsWith('$')) return;
+
+    const is_block = el.parentElement.tagName === 'DIV' || 
+                     el.textContent.includes('\n') ||
+                     el.parentElement.childNodes.length === 1;
+
+    const delimiter = is_block ? '$$' : '$';
+    el.style.display = is_block ? 'block' : 'inline';
+    el.textContent = `${delimiter}${el.textContent.trim()}${delimiter}`;
+  });
+
+  // MathJax must find its config at window.MathJax
+  window.MathJax = {
+    tex: { 
+      inlineMath: [['$', '$']], 
+      displayMath: [['$$', '$$']] 
+    }
+  };
+
+  const script = document.createElement('script');
+  script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
+  script.async = true;
+  document.head.appendChild(script);
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.math = math;
diff --git a/consumer/release/RT/element/term.js b/consumer/release/RT/element/term.js
new file mode 100644 (file)
index 0000000..4ebc634
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  Processes <RT-TERM> and <RT-NEOLOGISM> tags.
+  - Styles only the first occurrence of a unique term/neologism.
+  - The "-em" variants (e.g., <RT-term-em>) are always styled.
+  - Automatically generates IDs for first occurrences for future indexing.
+*/
+
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.term = function() {
+  const RT = window.StyleRT;
+
+  const debug = RT.debug || {
+    log: function() {}
+    ,warn: function() {}
+    ,error: function() {}
+  };
+
+  const DEBUG_TOKEN_S = 'term';
+
+  try {
+    // Track seen terms so only the first occurrence is decorated
+    const seen_terms_dpa = new Set();
+
+    const apply_style = (el, is_neologism_b) => {
+      el.style.fontStyle = 'italic';
+      el.style.fontWeight = is_neologism_b ? '600' : '500';
+      el.style.color = is_neologism_b
+        ? 'var(--rt-brand-secondary)'
+        : 'var(--rt-brand-primary)';
+      el.style.paddingRight = '0.1em'; // Compensation for italic slant
+      el.style.display = 'inline';
+    };
+
+    const clear_style = (el) => {
+      el.style.fontStyle = 'normal';
+      el.style.color = 'inherit';
+      el.style.fontWeight = 'inherit';
+      el.style.paddingRight = '';
+      el.style.display = '';
+    };
+
+    const selector_s = [
+      'rt-term'
+      ,'rt-term-em'
+      ,'rt-neologism'
+      ,'rt-neologism-em'
+    ].join(',');
+
+    const tags_dpa = document.querySelectorAll(selector_s);
+
+    debug.log(DEBUG_TOKEN_S, `Scanning ${tags_dpa.length} term tags`);
+
+    tags_dpa.forEach(el => {
+      const tag_name_s = el.tagName.toLowerCase();
+      const is_neologism_b = tag_name_s.includes('neologism');
+      const is_explicit_em_b = tag_name_s.endsWith('-em');
+
+      const term_text_raw_s = (el.textContent || '').trim();
+      if (!term_text_raw_s.length) {
+        debug.warn(DEBUG_TOKEN_S, `Empty term tag encountered: <${tag_name_s}>`);
+        return;
+      }
+
+      // Normalize text for uniqueness tracking
+      const term_norm_s = term_text_raw_s.toLowerCase();
+
+      // Slug for ID generation (simple + stable)
+      const slug_s = term_norm_s.replace(/\s+/g, '-');
+
+      const is_first_occurrence_b = !seen_terms_dpa.has(term_norm_s);
+
+      if (is_explicit_em_b || is_first_occurrence_b) {
+        apply_style(el, is_neologism_b);
+
+        if (!is_explicit_em_b && is_first_occurrence_b) {
+          seen_terms_dpa.add(term_norm_s);
+
+          if (!el.id) {
+            el.id = `def-${is_neologism_b ? 'neo-' : ''}${slug_s}`;
+            debug.log(
+              DEBUG_TOKEN_S
+              ,`First occurrence: "${term_norm_s}" -> id="${el.id}"`
+            );
+          } else {
+            debug.log(
+              DEBUG_TOKEN_S
+              ,`First occurrence: "${term_norm_s}" (existing id="${el.id}")`
+            );
+          }
+        } else if (is_explicit_em_b) {
+          debug.log(
+            DEBUG_TOKEN_S
+            ,`Emphasized occurrence: "${term_norm_s}" (<${tag_name_s}>)`
+          );
+        }
+      } else {
+        // Subsequent mentions render as normal prose
+        clear_style(el);
+      }
+    });
+
+    debug.log(DEBUG_TOKEN_S, `Unique terms defined: ${seen_terms_dpa.size}`);
+  } catch (e) {
+    debug.error('error', `term failed: ${e && e.message ? e.message : String(e)}`);
+  }
+};
diff --git a/consumer/release/RT/element/theme_selector.js b/consumer/release/RT/element/theme_selector.js
new file mode 100644 (file)
index 0000000..05759d2
--- /dev/null
@@ -0,0 +1,27 @@
+class ThemeSelector extends HTMLElement{
+  connectedCallback(){
+    let current_theme = localStorage.getItem('RT_theme_preference');
+    if(!current_theme){
+      current_theme = 'dark_gold';
+    }
+    
+    this.innerHTML = `
+      <div style="position:fixed; top:10px; right:10px; z-index:1000; background:#222; padding:10px; border:1px solid #555; color: white; font-family: sans-serif;">
+        <b>Theme Selection</b><br>
+        <label>
+          <input type="radio" name="rt-theme" value="dark_gold" ${current_theme === 'dark_gold' ? 'checked' : ''}> Dark Gold
+        </label><br>
+        <label>
+          <input type="radio" name="rt-theme" value="light_gold" ${current_theme === 'light_gold' ? 'checked' : ''}> Light Gold
+        </label>
+      </div>
+    `;
+
+    this.addEventListener( 'change' ,(e) => {
+      localStorage.setItem('RT_theme_preference' ,e.target.value);
+      location.reload();
+    } );
+  }
+}
+
+customElements.define('rt-theme-selector' ,ThemeSelector);
diff --git a/consumer/release/RT/element/title.js b/consumer/release/RT/element/title.js
new file mode 100644 (file)
index 0000000..fefd991
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Processes <RT-TITLE> tags.
+  Generates a standard document header block.
+  
+  Usage: 
+  <RT-title title="..." author="..." date="..."></RT-title>
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.title = function() {
+  const debug = window.StyleRT.debug || { log: function(){} };
+  
+  document.querySelectorAll('rt-title').forEach(el => {
+    const title = el.getAttribute('title') || 'Untitled Document';
+    const author = el.getAttribute('author');
+    const date = el.getAttribute('date');
+
+    if (debug.log) debug.log('title', `Generating title block: ${title}`);
+
+    // Container
+    const container = document.createElement('div');
+    container.style.textAlign = 'center';
+    container.style.marginBottom = '3rem';
+    container.style.marginTop = '2rem';
+    container.style.borderBottom = '1px solid var(--rt-border-default)';
+    container.style.paddingBottom = '1.5rem';
+
+    // Main Title (H1)
+    const h1 = document.createElement('h1');
+    h1.textContent = title;
+    h1.style.margin = '0 0 0.8rem 0';
+    h1.style.border = 'none'; // Override standard H1 border
+    h1.style.padding = '0';
+    h1.style.color = 'var(--rt-brand-primary)';
+    h1.style.fontSize = '2.5em';
+    h1.style.lineHeight = '1.1';
+    h1.style.letterSpacing = '-0.03em';
+
+    container.appendChild(h1);
+
+    // Metadata Row (Author | Date)
+    if (author || date) {
+      const meta = document.createElement('div');
+      meta.style.color = 'var(--rt-content-muted)';
+      meta.style.fontStyle = 'italic';
+      meta.style.fontSize = '1.1em';
+      meta.style.fontFamily = '"Georgia", "Times New Roman", serif'; // Classy serif
+
+      const parts = [];
+      if (author) parts.push(`<span style="font-weight:600; color:var(--rt-brand-secondary)">${author}</span>`);
+      if (date) parts.push(date);
+
+      meta.innerHTML = parts.join(' &nbsp;&mdash;&nbsp; ');
+      container.appendChild(meta);
+    }
+
+    // Replace the raw tag with the generated block
+    el.replaceWith(container);
+  });
+};
diff --git a/consumer/release/RT/layout/article_tech_ref.js b/consumer/release/RT/layout/article_tech_ref.js
new file mode 100644 (file)
index 0000000..795e2e1
--- /dev/null
@@ -0,0 +1,84 @@
+(function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+
+  // 1. Declare Dependencies with updated core/ and layout/ paths
+  RT.include('RT/core/utility');
+  RT.include('RT/element/math');
+  RT.include('RT/element/code');
+  RT.include('RT/element/term');
+  RT.include('RT/element/TOC');
+  RT.include('RT/element/title');
+  RT.include('RT/element/theme_selector');
+  RT.include('RT/layout/paginate_by_element');
+  RT.include('RT/layout/page_fixed_glow');
+  RT.include('RT/core/body_visibility_visible');
+
+  // 2. The Typography Layout (Adapted from the original)
+  RT.article = function(){
+    RT.config = RT.config || {};
+    RT.config.article = {
+      font_family: '"Noto Sans", "Segoe UI", "Helvetica Neue", sans-serif'
+      ,line_height: "1.8"       
+      ,font_size: "16px"        
+      ,font_weight: "400"
+      ,max_width: "820px" 
+      ,margin: "0 auto"
+    };
+
+    if( RT.config.theme && RT.config.theme.meta_is_dark === false ){
+      RT.config.article.font_weight = "600";
+    }
+
+    const conf = RT.config.article;
+    const article_seq = document.querySelectorAll("RT-article");
+
+    if(article_seq.length === 0) return;
+
+    for(let i = 0; i < article_seq.length; i++){
+      let style = article_seq[i].style;
+      style.display = "block";
+      style.fontFamily = conf.font_family;
+      style.fontSize = conf.font_size;
+      style.lineHeight = conf.line_height;
+      style.fontWeight = conf.font_weight;
+      style.maxWidth = conf.max_width;
+      style.margin = conf.margin;
+      style.padding = "0 20px";
+      style.color = "var(--rt-content-main)";
+    }
+
+    // CSS injection for headers, lists, etc., goes here 
+    // (Omitted for brevity, but carried over from the original file)
+  };
+
+  // 3. The Execution Sequence
+  const run_semantics = function(){
+    if(RT.theme) RT.theme();     
+    RT.article(); 
+    
+    // Call the newly renamed element functions
+    if(RT.title) RT.title(); 
+    if(RT.term) RT.term();
+    if(RT.math) RT.math();
+    if(RT.code) RT.code();
+
+    // Check for MathJax typesetting
+    if(window.MathJax && MathJax.Hub && MathJax.Hub.Queue){
+      MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,run_layout );
+    }else{
+      run_layout();
+    }
+  };
+
+  const run_layout = function(){
+    if(RT.TOC) RT.TOC();
+    if(RT.paginate_by_element) RT.paginate_by_element();
+    if(RT.page) RT.page();
+    if(RT.body_visibility_visible) RT.body_visibility_visible();
+  };
+
+  // 4. Bind to DOM Ready
+  // This replaces the need to put a script at the bottom of the HTML body
+  document.addEventListener( 'DOMContentLoaded' ,run_semantics );
+
+})();
diff --git a/consumer/release/RT/layout/memo_State.js b/consumer/release/RT/layout/memo_State.js
new file mode 100644 (file)
index 0000000..a2eb279
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  <head>
+    <script>
+      window.StyleRT.include('RT/layout/memo_state_dept');
+    </script>
+  </head>
+  <body>
+    <RT-memo>
+       </RT-memo>
+  </body>
+*/
+
+(function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+
+  // 1. Declare Dependencies
+  RT.include('RT/core/utility');
+  RT.include('RT/element/title');
+  RT.include('RT/element/term');
+  RT.include('RT/element/TOC');
+  RT.include('RT/core/body_visibility_visible');
+
+  // 2. The Typography Layout
+  RT.memo_state_dept = function(){
+    const body = document.body;
+    const html = document.documentElement;
+    
+    // Force strict print colors regardless of user system settings
+    html.style.backgroundColor = "white";
+    body.style.backgroundColor = "white";
+    body.style.color = "black";
+
+    // Target the new semantic tag
+    const memo_seq = document.querySelectorAll("RT-memo");
+    if(memo_seq.length === 0) return;
+
+    for(let i = 0; i < memo_seq.length; i++){
+      let style = memo_seq[i].style;
+      style.display = "block";
+      style.fontFamily = '"Times New Roman", Times, serif';
+      style.fontSize = "12pt";
+      style.lineHeight = "1.15";
+      // 8.5 inch standard width minus 1-inch margins on each side
+      style.maxWidth = "6.5in"; 
+      style.margin = "1in auto";
+      style.padding = "0";
+      style.textAlign = "left";
+      style.color = "black";
+    }
+  };
+
+  // 3. The Execution Sequence
+  const run_semantics = function(){
+    RT.memo_state_dept(); 
+    
+    if(RT.title) RT.title(); 
+    if(RT.term) RT.term();
+    if(RT.TOC) RT.TOC();
+
+    run_layout();
+  };
+
+  const run_layout = function(){
+    if(RT.body_visibility_visible) RT.body_visibility_visible();
+  };
+
+  // 4. Bind to DOM Ready
+  document.addEventListener('DOMContentLoaded' ,run_semantics);
+
+})();
diff --git a/consumer/release/RT/layout/page_fixed_glow.js b/consumer/release/RT/layout/page_fixed_glow.js
new file mode 100644 (file)
index 0000000..91bd648
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Page Layout: Fixed Glow
+  Standard: Theme 1.0
+  Description: A fixed-height container with a glowing border effect that matches the active theme.
+*/
+(function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+
+  // Function name stays generic so the orchestrator can call RT.page() regardless of file choice
+  RT.page = function() {
+    RT.config = RT.config || {};
+    
+    // Default Configuration
+    // We use CSS Variables here so the Theme controls the actual colors.
+    const defaults = {
+       width: "100%"
+      ,height: "1056px"
+      ,padding: "3rem"
+      ,margin: "4rem auto"
+      
+      // Dynamic Theme Bindings
+      ,bg_color:     "var(--rt-surface-0)"         // Black (Dark) or Cream (Light)
+      ,border_color: "var(--rt-brand-primary)"     // The Main Accent Color
+      ,text_color:   "var(--rt-brand-primary)"     // Page Number Color
+      
+      // The Glow: Uses the primary brand color for the shadow
+      ,shadow: "drop-shadow(0px 0px 15px var(--rt-brand-primary))" 
+    };
+
+    // Merge defaults
+    RT.config.page = Object.assign({}, defaults, RT.config.page || {});
+
+    const conf = RT.config.page;
+    const style_id = 'rt-page-fixed-glow';
+    
+    if (!document.getElementById(style_id)) {
+      const style_el = document.createElement('style');
+      style_el.id = style_id;
+      
+      style_el.textContent = `
+        /* Reset page counter on the article container */
+        rt-article {
+          counter-reset: rt-page-counter;
+        }
+
+        rt-page {
+          display: block;
+          position: relative;
+          box-sizing: border-box;
+          overflow: hidden; 
+
+          /* Dimensions */
+          width: ${conf.width};
+          height: ${conf.height};
+          margin: ${conf.margin};
+          padding: ${conf.padding};
+          
+          /* Theming */
+          background-color: ${conf.bg_color}; 
+          border: 1px solid ${conf.border_color};
+          
+          /* The "Glow" Effect */
+          filter: ${conf.shadow};
+          
+          /* Counter Increment */
+          counter-increment: rt-page-counter;
+        }
+
+        /* Page Numbering */
+        rt-page::after {
+          content: "Page " counter(rt-page-counter);
+          position: absolute;
+          bottom: 1.5rem;
+          right: 3rem;
+          
+          font-family: "Noto Sans", sans-serif;
+          font-size: 0.9rem;
+          font-weight: bold;
+          
+          color: ${conf.text_color}; 
+          opacity: 0.8;
+          pointer-events: none; /* Prevent interference with clicks */
+        }
+      `;
+      document.head.appendChild(style_el);
+    }
+  };
+})();
diff --git a/consumer/release/RT/layout/paginate_by_element.js b/consumer/release/RT/layout/paginate_by_element.js
new file mode 100644 (file)
index 0000000..e085148
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Layout Paginator: paginate_by_element
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.paginate_by_element = function() {
+  const RT = window.StyleRT;
+  
+  // Fix: Read safely without overwriting the config namespace
+  const page_conf = (RT.config && RT.config.page) ? RT.config.page : {};
+  const page_height_limit = page_conf.height_limit || 1000; 
+
+  const article_seq = document.querySelectorAll("RT-article");
+  
+  // HURDLE: Error if no articles found to paginate
+  if(article_seq.length === 0) {
+    RT.debug.error('pagination', 'No <RT-article> elements found. Pagination aborted.');
+    return;
+  }
+
+  article_seq.forEach( (article) => {
+    const raw_elements = Array.from(article.children).filter(el => 
+      !['SCRIPT', 'STYLE', 'RT-PAGE'].includes(el.tagName)
+    );
+
+    if(raw_elements.length === 0) return;
+
+    const pages = [];
+    let current_batch = [];
+    let current_h = 0;
+
+    const get_el_height = (el) => {
+      const rect = el.getBoundingClientRect();
+      const style = window.getComputedStyle(el);
+      const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom);
+      return (rect.height || 0) + (margin || 0);
+    };
+
+    for (let i = 0; i < raw_elements.length; i++) {
+      const el = raw_elements[i];
+      const h = get_el_height(el);
+      const is_heading = /^H[1-6]/.test(el.tagName);
+
+      let total_required_h = h;
+      if (is_heading && i + 1 < raw_elements.length) {
+        total_required_h += get_el_height(raw_elements[i + 1]);
+      }
+
+      if (current_h + total_required_h > page_height_limit && current_batch.length > 0) {
+        pages.push(current_batch);
+        current_batch = [];
+        current_h = 0;
+      }
+
+      current_batch.push(el);
+      current_h += h;
+    }
+
+    if (current_batch.length > 0) pages.push(current_batch);
+
+    article.innerHTML = ''; 
+    
+    pages.forEach( (list, index) => {
+      const page_el = document.createElement('rt-page');
+      page_el.id = `page-${index+1}`;
+      list.forEach(item => page_el.appendChild(item));
+      article.appendChild(page_el);
+    });
+
+    if (RT.debug) RT.debug.log('pagination', `Article paginated into ${pages.length} pages.`);
+  });
+};
diff --git a/consumer/release/RT/theme/dark_gold.js b/consumer/release/RT/theme/dark_gold.js
new file mode 100644 (file)
index 0000000..f576147
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+  Theme: Inverse Wheat (Dark)
+  Standard: Theme 1.0
+  Description: High contrast Amber on Deep Charcoal.
+*/
+( function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+  
+  RT.theme = function(){
+    RT.config = RT.config || {};
+    
+    // THEME 1.0 DATA CONTRACT
+    RT.config.theme = {
+       meta_is_dark: true
+      ,meta_name:    "Inverse Wheat"
+
+      // --- SURFACES (Depth & Container Hierarchy) ---
+      ,surface_0:       "hsl(0, 0%, 5%)"      // App Background (Deepest)
+      ,surface_1:       "hsl(0, 0%, 10%)"     // Sidebar / Nav / Panels
+      ,surface_2:       "hsl(0, 0%, 14%)"     // Cards / Floating Elements
+      ,surface_3:       "hsl(0, 0%, 18%)"     // Modals / Dropdowns / Popovers
+      ,surface_input:   "hsl(0, 0%, 12%)"     // Form Inputs
+      ,surface_code:    "hsl(0, 0%, 11%)"     // Code Block Background
+      ,surface_select:  "hsl(45, 100%, 15%)"  // Text Selection Highlight
+
+      // --- CONTENT (Text & Icons) ---
+      ,content_main:    "hsl(50, 60%, 85%)"   // Primary Reading Text
+      ,content_muted:   "hsl(36, 15%, 60%)"   // Metadata, subtitles
+      ,content_subtle:  "hsl(36, 10%, 40%)"   // Placeholders, disabled states
+      ,content_inverse: "hsl(0, 0%, 5%)"      // Text on high-contrast buttons
+
+      // --- BRAND & ACTION (The "Wheat" Identity) ---
+      ,brand_primary:   "hsl(45, 100%, 50%)"  // Main Action / H1 / Focus Ring
+      ,brand_secondary: "hsl(38, 90%, 65%)"   // Secondary Buttons / H2
+      ,brand_tertiary:  "hsl(30, 60%, 70%)"   // Accents / H3
+      ,brand_link:      "hsl(48, 100%, 50%)"  // Hyperlinks (High Visibility)
+
+      // --- BORDERS & DIVIDERS ---
+      ,border_faint:    "hsl(36, 20%, 15%)"   // Subtle separation
+      ,border_default:  "hsl(36, 20%, 25%)"   // Standard Card Borders
+      ,border_strong:   "hsl(36, 20%, 40%)"   // Active states / Inputs
+
+      // --- STATE & FEEDBACK (Earth Tones) ---
+      ,state_success:   "hsl(100, 50%, 45%)"  // Olive Green
+      ,state_warning:   "hsl(35, 90%, 55%)"   // Burnt Orange
+      ,state_error:     "hsl(0, 60%, 55%)"    // Brick Red
+      ,state_info:      "hsl(200, 40%, 55%)"  // Slate Blue
+
+      // --- SYNTAX HIGHLIGHTING (For Code) ---
+      ,syntax_keyword:  "hsl(35, 100%, 65%)"  // Orange
+      ,syntax_string:   "hsl(75, 50%, 60%)"   // Sage Green
+      ,syntax_func:     "hsl(45, 90%, 70%)"   // Light Gold
+      ,syntax_comment:  "hsl(36, 15%, 45%)"   // Brown/Gray
+    };
+
+    // --- APPLY THEME ---
+    const palette = RT.config.theme;
+    const body = document.body;
+    const html = document.documentElement;
+
+    // 1. Paint Base
+    html.style.backgroundColor = palette.surface_0;
+    body.style.backgroundColor = palette.surface_0;
+    body.style.color = palette.content_main;
+
+    // 2. Export Variables (Standardization)
+    const s = body.style;
+    for (const [key, value] of Object.entries(palette)) {
+      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
+    }
+    
+    // 3. Global Overrides
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      style.textContent = `
+        ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: var(--rt-surface-0); }
+        ::-webkit-scrollbar-thumb { 
+           background: var(--rt-border-default); 
+           border: 2px solid var(--rt-surface-0);
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+  
+} )();
diff --git a/consumer/release/RT/theme/light.js b/consumer/release/RT/theme/light.js
new file mode 100644 (file)
index 0000000..4b5eea4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Theme: Classic Wheat (Light)
+  Standard: Theme 1.0
+  Description: Warm paper tones with Burnt Orange accents.
+*/
+( function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+  
+  RT.theme_light = function(){
+    RT.config = RT.config || {};
+    
+    // THEME 1.0 DATA CONTRACT
+    RT.config.theme = {
+       meta_is_dark: false
+      ,meta_name:    "Classic Wheat"
+
+      // --- SURFACES ---
+      ,surface_0:       "hsl(40, 30%, 94%)"   // App Background (Cream/Linen)
+      ,surface_1:       "hsl(40, 25%, 90%)"   // Sidebar (Slightly darker beige)
+      ,surface_2:       "hsl(40, 20%, 98%)"   // Cards (Lighter, almost white)
+      ,surface_3:       "hsl(0, 0%, 100%)"    // Modals (Pure White)
+      ,surface_input:   "hsl(40, 20%, 98%)"   // Form Inputs
+      ,surface_code:    "hsl(40, 15%, 90%)"   // Code Block Background
+      ,surface_select:  "hsl(45, 100%, 85%)"  // Text Selection Highlight
+
+      // --- CONTENT ---
+      ,content_main:    "hsl(30, 20%, 20%)"   // Deep Umber (Not Black)
+      ,content_muted:   "hsl(30, 15%, 45%)"   // Medium Brown
+      ,content_subtle:  "hsl(30, 10%, 65%)"   // Light Brown/Gray
+      ,content_inverse: "hsl(40, 30%, 94%)"   // Text on dark buttons
+
+      // --- BRAND & ACTION ---
+      ,brand_primary:   "hsl(30, 90%, 35%)"   // Burnt Orange (Action)
+      ,brand_secondary: "hsl(35, 70%, 45%)"   // Rust / Gold
+      ,brand_tertiary:  "hsl(25, 60%, 55%)"   // Copper
+      ,brand_link:      "hsl(30, 100%, 35%)"  // Link Color
+
+      // --- BORDERS ---
+      ,border_faint:    "hsl(35, 20%, 85%)"
+      ,border_default:  "hsl(35, 20%, 75%)"
+      ,border_strong:   "hsl(35, 20%, 55%)"
+
+      // --- STATE & FEEDBACK ---
+      ,state_success:   "hsl(100, 40%, 40%)"  // Forest Green
+      ,state_warning:   "hsl(30, 90%, 50%)"   // Persimmon
+      ,state_error:     "hsl(0, 60%, 45%)"    // Crimson
+      ,state_info:      "hsl(200, 50%, 45%)"  // Navy Blue
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "hsl(20, 90%, 45%)"   // Rust
+      ,syntax_string:   "hsl(100, 35%, 35%)"  // Ivy Green
+      ,syntax_func:     "hsl(300, 30%, 40%)"  // Muted Purple
+      ,syntax_comment:  "hsl(35, 10%, 60%)"   // Light Brown
+    };
+
+    // --- APPLY THEME ---
+    const palette = RT.config.theme;
+    const body = document.body;
+    const html = document.documentElement;
+
+    html.style.backgroundColor = palette.surface_0;
+    body.style.backgroundColor = palette.surface_0;
+    body.style.color = palette.content_main;
+
+    const s = body.style;
+    for (const [key, value] of Object.entries(palette)) {
+      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
+    }
+  };
+} )();
diff --git a/consumer/release/RT/theme/light_gold.js b/consumer/release/RT/theme/light_gold.js
new file mode 100644 (file)
index 0000000..206f3da
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+  Theme: Golden Wheat (Light) - "Spanish Gold Edition"
+  File: style/theme-light-gold.js
+  Standard: Theme 1.0
+  Description: Light Parchment background with Oxblood Red ink.
+*/
+( function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+  
+  RT.theme = function(){
+    RT.config = RT.config || {};
+    
+    RT.config.theme = {
+       meta_is_dark: false
+      ,meta_name:    "Golden Wheat (Yellow)"
+
+      // --- SURFACES (Light Parchment) ---
+      // Shifted lightness up to 94% for a "whiter" feel that still holds the yellow tint.
+      ,surface_0:       "hsl(48, 50%, 94%)"   // Main Page: Fine Parchment
+      ,surface_1:       "hsl(48, 40%, 90%)"   // Panels: Slightly darker
+      ,surface_2:       "hsl(48, 30%, 97%)"   // Cards: Very light
+      ,surface_3:       "hsl(0, 0%, 100%)"    // Popups
+      ,surface_input:   "hsl(48, 20%, 96%)"   
+      ,surface_code:    "hsl(48, 25%, 88%)"   // Distinct Code BG
+      ,surface_select:  "hsl(10, 70%, 85%)"   // Red Highlight
+
+      // --- CONTENT (Deep Ink) ---
+      ,content_main:    "hsl(10, 25%, 7%)"    // Deep Warm Black (Ink)
+      ,content_muted:   "hsl(10, 15%, 35%)"   // Dark Grey-Red
+      ,content_subtle:  "hsl(10, 10%, 55%)"   
+      ,content_inverse: "hsl(48, 50%, 90%)"   
+
+      // --- BRAND & ACTION (The Red Spectrum) ---
+      ,brand_primary:   "hsl(12, 85%, 30%)"   // H1 (Deep Oxblood)
+      ,brand_secondary: "hsl(10, 80%, 35%)"   // H2 (Garnet)
+      ,brand_tertiary:  "hsl(8, 70%, 40%)"    // H3 (Brick)
+      ,brand_link:      "hsl(12, 90%, 35%)"   // Link
+
+      // --- BORDERS ---
+      ,border_faint:    "hsl(45, 30%, 80%)"
+      ,border_default:  "hsl(45, 30%, 70%)"   // Pencil Grey
+      ,border_strong:   "hsl(12, 50%, 40%)"   
+
+      // --- STATE ---
+      ,state_success:   "hsl(120, 40%, 30%)"  
+      ,state_warning:   "hsl(25, 90%, 45%)"   
+      ,state_error:     "hsl(0, 75%, 35%)"    
+      ,state_info:      "hsl(210, 60%, 40%)"  
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "hsl(0, 75%, 35%)"    
+      ,syntax_string:   "hsl(100, 35%, 25%)"  
+      ,syntax_func:     "hsl(15, 85%, 35%)"   
+      ,syntax_comment:  "hsl(45, 20%, 50%)"   
+    };
+
+    // --- APPLY THEME ---
+    const palette = RT.config.theme;
+    const body = document.body;
+    const html = document.documentElement;
+
+    html.style.backgroundColor = palette.surface_0;
+    body.style.backgroundColor = palette.surface_0;
+    body.style.color = palette.content_main;
+
+    const s = body.style;
+    for (const [key, value] of Object.entries(palette)) {
+      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
+    }
+    
+    // Global overrides
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      style.textContent = `
+        ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: var(--rt-surface-0); }
+        ::-webkit-scrollbar-thumb { 
+           background: var(--rt-border-default); 
+           border: 2px solid var(--rt-surface-0);
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); }
+
+        rt-article p, rt-article li {
+           text-shadow: 0px 0px 0.5px rgba(0,0,0, 0.2); 
+        }
+
+        .MathJax, .MathJax_Display, .mjx-chtml {
+            color: var(--rt-content-main) !important;
+            fill: var(--rt-content-main) !important;
+            stroke: var(--rt-content-main) !important;
+        }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+  
+} )();
diff --git a/developer/authored/RT/core/body_visibility_hidden.js b/developer/authored/RT/core/body_visibility_hidden.js
new file mode 100644 (file)
index 0000000..d6a178a
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+  Targets the root element to ensure total blackout during load.
+*/
+function body_visibility_hidden(){
+  const gate = document.createElement('style');
+  gate.id = 'rt-visibility-gate';
+  gate.textContent = 'html{visibility:hidden !important; background:black !important;}';
+  document.head.appendChild(gate);
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.body_visibility_hidden = body_visibility_hidden;
diff --git a/developer/authored/RT/core/body_visibility_visible.js b/developer/authored/RT/core/body_visibility_visible.js
new file mode 100644 (file)
index 0000000..ff1c4b6
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+  Restores visibility by removing the visibility gate.
+*/
+function body_visibility_visible(){
+  const gate = document.getElementById('rt-visibility-gate');
+  if (gate){
+    gate.remove();
+  }
+  document.body.style.visibility = 'visible';
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.body_visibility_visible = body_visibility_visible;
diff --git a/developer/authored/RT/core/loader.js b/developer/authored/RT/core/loader.js
new file mode 100644 (file)
index 0000000..3f4ee68
--- /dev/null
@@ -0,0 +1,27 @@
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.include = function(path_identifier){
+  let parts_seq = path_identifier.split('/');
+  let namespace = parts_seq[0];
+  
+  let module_path = parts_seq.slice(1).join('/');
+
+  if(module_path === 'theme'){
+    let saved_theme = localStorage.getItem('RT_theme_preference');
+    if(!saved_theme){
+      saved_theme = 'dark_gold';
+      localStorage.setItem('RT_theme_preference' ,saved_theme);
+    }
+    module_path = 'theme/' + saved_theme;
+  }
+
+  let base_path = window.StyleRT_namespaces[namespace];
+  if(!base_path){
+    console.error("Namespace not found: " + namespace);
+    return;
+  }
+
+  let full_path = base_path + '/' + module_path + '.js';
+  // FIXED: No backslashes in the closing script tag
+  document.write('<script src="' + full_path + '"></script>');
+};
diff --git a/developer/authored/RT/core/utility.js b/developer/authored/RT/core/utility.js
new file mode 100644 (file)
index 0000000..258eb28
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  General utilities for the StyleRT library.
+*/
+
+window.StyleRT = window.StyleRT || {};
+
+// --- DEBUG SYSTEM ---
+window.StyleRT.debug = {
+
+  // all debug messages enabled
+/*
+  active_tokens: new Set([
+    'style', 'layout', 'pagination'
+    ,'selector', 'config', 'error'
+    ,'term'
+  ]),
+*/
+  active_tokens: new Set([
+    'term'
+  ]),
+  
+  log: function(token, message) {
+    if (this.active_tokens.has(token)) {
+      console.log(`[StyleRT:${token}]`, message);
+    }
+  },
+
+  warn: function(token, message) {
+    if (this.active_tokens.has(token)) {
+      console.warn(`[StyleRT:${token}]`, message);
+    }
+  },
+  
+  // New: Always log errors regardless of token, but tag them
+  error: function(token, message) {
+    console.error(`[StyleRT:${token}] CRITICAL:`, message);
+  },
+  
+  enable: function(token) { this.active_tokens.add(token); console.log(`Enabled: ${token}`); },
+  disable: function(token) { this.active_tokens.delete(token); console.log(`Disabled: ${token}`); }
+};
+
+// --- UTILITIES ---
+window.StyleRT.utility = {
+  // --- FONT PHYSICS ---
+  measure_ink_ratio: function(target_font, ref_font = null) {
+    const debug = window.StyleRT.debug;
+    debug.log('layout', `Measuring ink ratio for ${target_font}`);
+
+    const canvas = document.createElement('canvas');
+    const ctx = canvas.getContext('2d');
+
+    if (!ref_font) {
+      const bodyStyle = window.getComputedStyle(document.body);
+      ref_font = bodyStyle.fontFamily;
+    }
+
+    const get_metrics = (font) => {
+      ctx.font = '100px ' + font; 
+      const metrics = ctx.measureText('M');
+      return {
+        ascent: metrics.actualBoundingBoxAscent, 
+        descent: metrics.actualBoundingBoxDescent 
+      };
+    };
+
+    const ref_m = get_metrics(ref_font);
+    const target_m = get_metrics(target_font);
+    
+    const ratio = ref_m.ascent / target_m.ascent;
+    // debug.log('layout', `Ink Ratio calculated: ${ratio.toFixed(3)}`);
+
+    return { 
+      ratio: ratio,
+      baseline_diff: ref_m.descent - target_m.descent 
+    };
+  },
+
+  // --- COLOR PHYSICS ---
+  is_color_light: function(color_string) {
+    const debug = window.StyleRT.debug;
+    
+    // 1. HSL Check
+    if (color_string.startsWith('hsl')) {
+      const numbers = color_string.match(/\d+/g);
+      if (numbers && numbers.length >= 3) {
+        const lightness = parseInt(numbers[2]);
+        return lightness > 50;
+      }
+    }
+
+    // 2. RGB Check
+    const rgb = color_string.match(/\d+/g);
+    if (!rgb) {
+      // debug.warn('color_layout', `Failed to parse color: "${color_string}". Defaulting to Light.`);
+      return true; 
+    }
+
+    const r = parseInt(rgb[0]);
+    const g = parseInt(rgb[1]);
+    const b = parseInt(rgb[2]);
+    const luma = (r * 299 + g * 587 + b * 114) / 1000;
+    return luma > 128;
+  },
+
+  is_block_content: function(element) {
+    return element.textContent.trim().includes('\n');
+  }
+};
diff --git a/developer/authored/RT/element/TOC.js b/developer/authored/RT/element/TOC.js
new file mode 100644 (file)
index 0000000..eb246f5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  Processes <RT-TOC> tags.
+  Populates each with headings found below it.
+
+  Attributes:
+    level="N" : Explicitly sets the target heading level (1-6).
+                e.g., level="1" collects H1s. level="2" collects H2s.
+                Stops collecting if it hits a heading of (level - 1) or higher.
+
+  Default (No attribute):
+    Context Aware. Looks backwards for the nearest heading H(N).
+    Targets H(N+1). Stops at the next H(N).
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.TOC = function(){
+  const debug = window.StyleRT.debug || { log: function(){} };
+  const TOC_seq = document.querySelectorAll('rt-toc');
+
+  TOC_seq.forEach( (container ,TOC_index) => {
+    container.style.display = 'block';
+
+    // 1. Determine Target Level
+    const attr_level = parseInt( container.getAttribute('level') );
+    let target_level;
+
+    if( !isNaN(attr_level) ){
+       // EXPLICIT MODE
+       target_level = attr_level;
+       if(debug.log) debug.log('TOC' ,`TOC #${TOC_index} explicit target: H${target_level}`);
+    } else {
+       // IMPLICIT / CONTEXT MODE
+       let context_level = 0; // Default 0 (Root)
+       let prev = container.previousElementSibling;
+       while(prev){
+         const match = prev.tagName.match(/^H([1-6])$/);
+         if(match){
+           context_level = parseInt( match[1] );
+           break;
+         }
+         prev = prev.previousElementSibling;
+       }
+       target_level = context_level + 1;
+       if(debug.log) debug.log('TOC' ,`TOC #${TOC_index} context implied target: H${target_level}`);
+    }
+
+    // Stop condition: Stop if we hit a heading that is a "parent" or "sibling" of the context.
+    // Mathematically: Stop if found_level < target_level.
+    const stop_threshold = target_level;
+
+    // 2. Setup Container
+    container.innerHTML = '';
+    const title = document.createElement('h1');
+    // Title logic: If targeting H1, the element serves as a Main TOC. Otherwise the element serves as a Section TOC.
+    title.textContent = target_level === 1 ? 'Table of Contents' : 'Section Contents';
+    title.style.textAlign = 'center';
+    container.appendChild(title);
+
+    const list = document.createElement('ul');
+    list.style.listStyle = 'none';
+    list.style.paddingLeft = '0';
+    container.appendChild(list);
+
+    // 3. Scan Forward
+    let next_el = container.nextElementSibling;
+    while(next_el){
+      const match = next_el.tagName.match(/^H([1-6])$/);
+      if(match){
+        const found_level = parseInt( match[1] );
+
+        // STOP Logic:
+        // If we are looking for H2s, we stop if we hit an H1 (level 1).
+        // If we are looking for H1s, we stop if we hit nothing (level 0).
+        if(found_level < target_level){
+          break;
+        }
+
+        // COLLECT Logic:
+        if(found_level === target_level){
+          if(!next_el.id) next_el.id = `TOC-ref-${TOC_index}-${found_level}-${list.children.length}`;
+
+          const li = document.createElement('li');
+          li.style.marginBottom = '0.5rem';
+
+          const a = document.createElement('a');
+          a.href = `#${next_el.id}`;
+          a.textContent = next_el.textContent;
+          a.style.textDecoration = 'none';
+          a.style.color = 'inherit';
+          a.style.display = 'block';
+
+          a.onmouseover = () => a.style.color = 'var(--rt-brand-primary)';
+          a.onmouseout = () => a.style.color = 'inherit';
+
+          li.appendChild(a);
+          list.appendChild(li);
+        }
+      }
+      next_el = next_el.nextElementSibling;
+    }
+  });
+};
diff --git a/developer/authored/RT/element/code.js b/developer/authored/RT/element/code.js
new file mode 100644 (file)
index 0000000..7e6dca8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  Processes <RT-CODE> tags.
+  Uses the central config or CSS variables from the theme.
+
+  Removes common indent from lines of code.
+*/
+function code() {
+  const RT = window.StyleRT;
+  const U = RT.utility;
+  const debug = RT.debug;
+
+  debug.log('code', 'Starting render cycle.');
+
+  const metrics = U.measure_ink_ratio('monospace');
+  
+  document.querySelectorAll('rt-code').forEach((el) => {
+    el.style.fontFamily = 'monospace';
+    
+    const computed = window.getComputedStyle(el);
+    const accent = computed.getPropertyValue('--rt-accent').trim() || 'gold';
+    
+    const is_block = U.is_block_content(el);
+    const parentColor = computed.color;
+    const is_text_light = U.is_color_light(parentColor);
+    
+    const alpha = is_block ? 0.08 : 0.15;
+    const overlay = is_text_light ? `rgba(255,255,255,${alpha})` : `rgba(0,0,0,${alpha})`;
+    const text_color = is_text_light ? '#ffffff' : '#000000';
+
+    el.style.backgroundColor = overlay;
+
+    if (is_block) {
+      el.style.display = 'block';
+
+      // --- Tag-Relative Auto-Dedent Logic ---
+      
+      // 1. Get Tag Indentation (The Anchor)
+      let tagIndent = '';
+      const prevNode = el.previousSibling;
+      if (prevNode && prevNode.nodeType === 3) {
+        const prevText = prevNode.nodeValue;
+        const lastNewLineIndex = prevText.lastIndexOf('\n');
+        if (lastNewLineIndex !== -1) {
+          tagIndent = prevText.substring(lastNewLineIndex + 1);
+        } else if (/^\s*$/.test(prevText)) {
+          tagIndent = prevText;
+        }
+      }
+
+      // 2. Calculate Common Leading Whitespace from Content
+      const rawLines = el.textContent.split('\n');
+      
+      // Filter out empty lines for calculation purposes so they don't break the logic
+      const contentLines = rawLines.filter(line => line.trim().length > 0);
+
+      let commonIndent = null;
+
+      if (contentLines.length > 0) {
+        // Assume the first line sets the standard
+        const firstMatch = contentLines[0].match(/^\s*/);
+        commonIndent = firstMatch ? firstMatch[0] : '';
+
+        // Reduce the commonIndent if subsequent lines have LESS indentation
+        for (let i = 1; i < contentLines.length; i++) {
+          const line = contentLines[i];
+          // Determine how much of commonIndent this line shares
+          let j = 0;
+          while (j < commonIndent.length && j < line.length && commonIndent[j] === line[j]) {
+            j++;
+          }
+          commonIndent = commonIndent.substring(0, j);
+          if (commonIndent.length === 0) break; // Optimization
+        }
+      } else {
+        commonIndent = '';
+      }
+
+      // 3. Process Content
+      // Rule: Only strip if the Common Indent contains the Tag Indent (Safety Check)
+      // This handles the Emacs case: Tag is "  ", Common is "    ". "    " starts with "  ".
+      // We strip "    ", leaving the code flush left.
+      let finalString = '';
+
+      if (commonIndent.length > 0 && commonIndent.startsWith(tagIndent)) {
+         const cleanedLines = rawLines.map(line => {
+            // Strip the common indent from valid lines
+            return line.startsWith(commonIndent) ? line.replace(commonIndent, '') : line;
+         });
+
+         // Remove artifact lines (first/last empty lines)
+         if (cleanedLines.length > 0 && cleanedLines[0].length === 0) {
+           cleanedLines.shift();
+         }
+         if (cleanedLines.length > 0 && cleanedLines[cleanedLines.length - 1].trim().length === 0) {
+            cleanedLines.pop();
+         }
+         finalString = cleanedLines.join('\n');
+      } else {
+         // Fallback: Code is to the left of the tag or weirdly formatted. 
+         // Just trim the wrapper newlines.
+         finalString = el.textContent.trim();
+      }
+
+      el.textContent = finalString;
+      // --- End Indentation Logic ---
+
+      el.style.whiteSpace = 'pre';
+      el.style.fontSize = (parseFloat(computed.fontSize) * metrics.ratio * 0.95) + 'px'; 
+      el.style.padding = '1.2rem';
+      el.style.margin = '1.5rem 0';
+      el.style.borderLeft = `4px solid ${accent}`;
+      el.style.color = 'inherit'; 
+    } else {
+      el.style.display = 'inline';
+      const exactPx = parseFloat(computed.fontSize) * metrics.ratio * 1.0; 
+      el.style.fontSize = exactPx + 'px';
+      el.style.padding = '0.1rem 0.35rem';
+      el.style.borderRadius = '3px';
+      const offsetPx = metrics.baseline_diff * (exactPx / 100);
+      el.style.verticalAlign = offsetPx + 'px';
+      el.style.color = text_color; 
+    }
+  });
+  
+  debug.log('code', 'Render cycle complete.');
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.code = code;
diff --git a/developer/authored/RT/element/math.js b/developer/authored/RT/element/math.js
new file mode 100644 (file)
index 0000000..1e2ae8f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  Processes <RT-MATH> tags.
+  JavaScript: math() 
+  HTML Tag: <RT-MATH> (parsed as rt-math)
+*/
+function math(){
+  // querySelector treats 'rt-math' as case-insensitive for the tag
+  document.querySelectorAll('rt-math').forEach(el => {
+    if (el.textContent.startsWith('$')) return;
+
+    const is_block = el.parentElement.tagName === 'DIV' || 
+                     el.textContent.includes('\n') ||
+                     el.parentElement.childNodes.length === 1;
+
+    const delimiter = is_block ? '$$' : '$';
+    el.style.display = is_block ? 'block' : 'inline';
+    el.textContent = `${delimiter}${el.textContent.trim()}${delimiter}`;
+  });
+
+  // MathJax must find its config at window.MathJax
+  window.MathJax = {
+    tex: { 
+      inlineMath: [['$', '$']], 
+      displayMath: [['$$', '$$']] 
+    }
+  };
+
+  const script = document.createElement('script');
+  script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
+  script.async = true;
+  document.head.appendChild(script);
+}
+
+window.StyleRT = window.StyleRT || {};
+window.StyleRT.math = math;
diff --git a/developer/authored/RT/element/term.js b/developer/authored/RT/element/term.js
new file mode 100644 (file)
index 0000000..4ebc634
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  Processes <RT-TERM> and <RT-NEOLOGISM> tags.
+  - Styles only the first occurrence of a unique term/neologism.
+  - The "-em" variants (e.g., <RT-term-em>) are always styled.
+  - Automatically generates IDs for first occurrences for future indexing.
+*/
+
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.term = function() {
+  const RT = window.StyleRT;
+
+  const debug = RT.debug || {
+    log: function() {}
+    ,warn: function() {}
+    ,error: function() {}
+  };
+
+  const DEBUG_TOKEN_S = 'term';
+
+  try {
+    // Track seen terms so only the first occurrence is decorated
+    const seen_terms_dpa = new Set();
+
+    const apply_style = (el, is_neologism_b) => {
+      el.style.fontStyle = 'italic';
+      el.style.fontWeight = is_neologism_b ? '600' : '500';
+      el.style.color = is_neologism_b
+        ? 'var(--rt-brand-secondary)'
+        : 'var(--rt-brand-primary)';
+      el.style.paddingRight = '0.1em'; // Compensation for italic slant
+      el.style.display = 'inline';
+    };
+
+    const clear_style = (el) => {
+      el.style.fontStyle = 'normal';
+      el.style.color = 'inherit';
+      el.style.fontWeight = 'inherit';
+      el.style.paddingRight = '';
+      el.style.display = '';
+    };
+
+    const selector_s = [
+      'rt-term'
+      ,'rt-term-em'
+      ,'rt-neologism'
+      ,'rt-neologism-em'
+    ].join(',');
+
+    const tags_dpa = document.querySelectorAll(selector_s);
+
+    debug.log(DEBUG_TOKEN_S, `Scanning ${tags_dpa.length} term tags`);
+
+    tags_dpa.forEach(el => {
+      const tag_name_s = el.tagName.toLowerCase();
+      const is_neologism_b = tag_name_s.includes('neologism');
+      const is_explicit_em_b = tag_name_s.endsWith('-em');
+
+      const term_text_raw_s = (el.textContent || '').trim();
+      if (!term_text_raw_s.length) {
+        debug.warn(DEBUG_TOKEN_S, `Empty term tag encountered: <${tag_name_s}>`);
+        return;
+      }
+
+      // Normalize text for uniqueness tracking
+      const term_norm_s = term_text_raw_s.toLowerCase();
+
+      // Slug for ID generation (simple + stable)
+      const slug_s = term_norm_s.replace(/\s+/g, '-');
+
+      const is_first_occurrence_b = !seen_terms_dpa.has(term_norm_s);
+
+      if (is_explicit_em_b || is_first_occurrence_b) {
+        apply_style(el, is_neologism_b);
+
+        if (!is_explicit_em_b && is_first_occurrence_b) {
+          seen_terms_dpa.add(term_norm_s);
+
+          if (!el.id) {
+            el.id = `def-${is_neologism_b ? 'neo-' : ''}${slug_s}`;
+            debug.log(
+              DEBUG_TOKEN_S
+              ,`First occurrence: "${term_norm_s}" -> id="${el.id}"`
+            );
+          } else {
+            debug.log(
+              DEBUG_TOKEN_S
+              ,`First occurrence: "${term_norm_s}" (existing id="${el.id}")`
+            );
+          }
+        } else if (is_explicit_em_b) {
+          debug.log(
+            DEBUG_TOKEN_S
+            ,`Emphasized occurrence: "${term_norm_s}" (<${tag_name_s}>)`
+          );
+        }
+      } else {
+        // Subsequent mentions render as normal prose
+        clear_style(el);
+      }
+    });
+
+    debug.log(DEBUG_TOKEN_S, `Unique terms defined: ${seen_terms_dpa.size}`);
+  } catch (e) {
+    debug.error('error', `term failed: ${e && e.message ? e.message : String(e)}`);
+  }
+};
diff --git a/developer/authored/RT/element/theme_selector.js b/developer/authored/RT/element/theme_selector.js
new file mode 100644 (file)
index 0000000..05759d2
--- /dev/null
@@ -0,0 +1,27 @@
+class ThemeSelector extends HTMLElement{
+  connectedCallback(){
+    let current_theme = localStorage.getItem('RT_theme_preference');
+    if(!current_theme){
+      current_theme = 'dark_gold';
+    }
+    
+    this.innerHTML = `
+      <div style="position:fixed; top:10px; right:10px; z-index:1000; background:#222; padding:10px; border:1px solid #555; color: white; font-family: sans-serif;">
+        <b>Theme Selection</b><br>
+        <label>
+          <input type="radio" name="rt-theme" value="dark_gold" ${current_theme === 'dark_gold' ? 'checked' : ''}> Dark Gold
+        </label><br>
+        <label>
+          <input type="radio" name="rt-theme" value="light_gold" ${current_theme === 'light_gold' ? 'checked' : ''}> Light Gold
+        </label>
+      </div>
+    `;
+
+    this.addEventListener( 'change' ,(e) => {
+      localStorage.setItem('RT_theme_preference' ,e.target.value);
+      location.reload();
+    } );
+  }
+}
+
+customElements.define('rt-theme-selector' ,ThemeSelector);
diff --git a/developer/authored/RT/element/title.js b/developer/authored/RT/element/title.js
new file mode 100644 (file)
index 0000000..fefd991
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  Processes <RT-TITLE> tags.
+  Generates a standard document header block.
+  
+  Usage: 
+  <RT-title title="..." author="..." date="..."></RT-title>
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.title = function() {
+  const debug = window.StyleRT.debug || { log: function(){} };
+  
+  document.querySelectorAll('rt-title').forEach(el => {
+    const title = el.getAttribute('title') || 'Untitled Document';
+    const author = el.getAttribute('author');
+    const date = el.getAttribute('date');
+
+    if (debug.log) debug.log('title', `Generating title block: ${title}`);
+
+    // Container
+    const container = document.createElement('div');
+    container.style.textAlign = 'center';
+    container.style.marginBottom = '3rem';
+    container.style.marginTop = '2rem';
+    container.style.borderBottom = '1px solid var(--rt-border-default)';
+    container.style.paddingBottom = '1.5rem';
+
+    // Main Title (H1)
+    const h1 = document.createElement('h1');
+    h1.textContent = title;
+    h1.style.margin = '0 0 0.8rem 0';
+    h1.style.border = 'none'; // Override standard H1 border
+    h1.style.padding = '0';
+    h1.style.color = 'var(--rt-brand-primary)';
+    h1.style.fontSize = '2.5em';
+    h1.style.lineHeight = '1.1';
+    h1.style.letterSpacing = '-0.03em';
+
+    container.appendChild(h1);
+
+    // Metadata Row (Author | Date)
+    if (author || date) {
+      const meta = document.createElement('div');
+      meta.style.color = 'var(--rt-content-muted)';
+      meta.style.fontStyle = 'italic';
+      meta.style.fontSize = '1.1em';
+      meta.style.fontFamily = '"Georgia", "Times New Roman", serif'; // Classy serif
+
+      const parts = [];
+      if (author) parts.push(`<span style="font-weight:600; color:var(--rt-brand-secondary)">${author}</span>`);
+      if (date) parts.push(date);
+
+      meta.innerHTML = parts.join(' &nbsp;&mdash;&nbsp; ');
+      container.appendChild(meta);
+    }
+
+    // Replace the raw tag with the generated block
+    el.replaceWith(container);
+  });
+};
diff --git a/developer/authored/RT/layout/article_tech_ref.js b/developer/authored/RT/layout/article_tech_ref.js
new file mode 100644 (file)
index 0000000..795e2e1
--- /dev/null
@@ -0,0 +1,84 @@
+(function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+
+  // 1. Declare Dependencies with updated core/ and layout/ paths
+  RT.include('RT/core/utility');
+  RT.include('RT/element/math');
+  RT.include('RT/element/code');
+  RT.include('RT/element/term');
+  RT.include('RT/element/TOC');
+  RT.include('RT/element/title');
+  RT.include('RT/element/theme_selector');
+  RT.include('RT/layout/paginate_by_element');
+  RT.include('RT/layout/page_fixed_glow');
+  RT.include('RT/core/body_visibility_visible');
+
+  // 2. The Typography Layout (Adapted from the original)
+  RT.article = function(){
+    RT.config = RT.config || {};
+    RT.config.article = {
+      font_family: '"Noto Sans", "Segoe UI", "Helvetica Neue", sans-serif'
+      ,line_height: "1.8"       
+      ,font_size: "16px"        
+      ,font_weight: "400"
+      ,max_width: "820px" 
+      ,margin: "0 auto"
+    };
+
+    if( RT.config.theme && RT.config.theme.meta_is_dark === false ){
+      RT.config.article.font_weight = "600";
+    }
+
+    const conf = RT.config.article;
+    const article_seq = document.querySelectorAll("RT-article");
+
+    if(article_seq.length === 0) return;
+
+    for(let i = 0; i < article_seq.length; i++){
+      let style = article_seq[i].style;
+      style.display = "block";
+      style.fontFamily = conf.font_family;
+      style.fontSize = conf.font_size;
+      style.lineHeight = conf.line_height;
+      style.fontWeight = conf.font_weight;
+      style.maxWidth = conf.max_width;
+      style.margin = conf.margin;
+      style.padding = "0 20px";
+      style.color = "var(--rt-content-main)";
+    }
+
+    // CSS injection for headers, lists, etc., goes here 
+    // (Omitted for brevity, but carried over from the original file)
+  };
+
+  // 3. The Execution Sequence
+  const run_semantics = function(){
+    if(RT.theme) RT.theme();     
+    RT.article(); 
+    
+    // Call the newly renamed element functions
+    if(RT.title) RT.title(); 
+    if(RT.term) RT.term();
+    if(RT.math) RT.math();
+    if(RT.code) RT.code();
+
+    // Check for MathJax typesetting
+    if(window.MathJax && MathJax.Hub && MathJax.Hub.Queue){
+      MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,run_layout );
+    }else{
+      run_layout();
+    }
+  };
+
+  const run_layout = function(){
+    if(RT.TOC) RT.TOC();
+    if(RT.paginate_by_element) RT.paginate_by_element();
+    if(RT.page) RT.page();
+    if(RT.body_visibility_visible) RT.body_visibility_visible();
+  };
+
+  // 4. Bind to DOM Ready
+  // This replaces the need to put a script at the bottom of the HTML body
+  document.addEventListener( 'DOMContentLoaded' ,run_semantics );
+
+})();
diff --git a/developer/authored/RT/layout/memo_State.js b/developer/authored/RT/layout/memo_State.js
new file mode 100644 (file)
index 0000000..a2eb279
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  <head>
+    <script>
+      window.StyleRT.include('RT/layout/memo_state_dept');
+    </script>
+  </head>
+  <body>
+    <RT-memo>
+       </RT-memo>
+  </body>
+*/
+
+(function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+
+  // 1. Declare Dependencies
+  RT.include('RT/core/utility');
+  RT.include('RT/element/title');
+  RT.include('RT/element/term');
+  RT.include('RT/element/TOC');
+  RT.include('RT/core/body_visibility_visible');
+
+  // 2. The Typography Layout
+  RT.memo_state_dept = function(){
+    const body = document.body;
+    const html = document.documentElement;
+    
+    // Force strict print colors regardless of user system settings
+    html.style.backgroundColor = "white";
+    body.style.backgroundColor = "white";
+    body.style.color = "black";
+
+    // Target the new semantic tag
+    const memo_seq = document.querySelectorAll("RT-memo");
+    if(memo_seq.length === 0) return;
+
+    for(let i = 0; i < memo_seq.length; i++){
+      let style = memo_seq[i].style;
+      style.display = "block";
+      style.fontFamily = '"Times New Roman", Times, serif';
+      style.fontSize = "12pt";
+      style.lineHeight = "1.15";
+      // 8.5 inch standard width minus 1-inch margins on each side
+      style.maxWidth = "6.5in"; 
+      style.margin = "1in auto";
+      style.padding = "0";
+      style.textAlign = "left";
+      style.color = "black";
+    }
+  };
+
+  // 3. The Execution Sequence
+  const run_semantics = function(){
+    RT.memo_state_dept(); 
+    
+    if(RT.title) RT.title(); 
+    if(RT.term) RT.term();
+    if(RT.TOC) RT.TOC();
+
+    run_layout();
+  };
+
+  const run_layout = function(){
+    if(RT.body_visibility_visible) RT.body_visibility_visible();
+  };
+
+  // 4. Bind to DOM Ready
+  document.addEventListener('DOMContentLoaded' ,run_semantics);
+
+})();
diff --git a/developer/authored/RT/layout/page_fixed_glow.js b/developer/authored/RT/layout/page_fixed_glow.js
new file mode 100644 (file)
index 0000000..91bd648
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+  Page Layout: Fixed Glow
+  Standard: Theme 1.0
+  Description: A fixed-height container with a glowing border effect that matches the active theme.
+*/
+(function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+
+  // Function name stays generic so the orchestrator can call RT.page() regardless of file choice
+  RT.page = function() {
+    RT.config = RT.config || {};
+    
+    // Default Configuration
+    // We use CSS Variables here so the Theme controls the actual colors.
+    const defaults = {
+       width: "100%"
+      ,height: "1056px"
+      ,padding: "3rem"
+      ,margin: "4rem auto"
+      
+      // Dynamic Theme Bindings
+      ,bg_color:     "var(--rt-surface-0)"         // Black (Dark) or Cream (Light)
+      ,border_color: "var(--rt-brand-primary)"     // The Main Accent Color
+      ,text_color:   "var(--rt-brand-primary)"     // Page Number Color
+      
+      // The Glow: Uses the primary brand color for the shadow
+      ,shadow: "drop-shadow(0px 0px 15px var(--rt-brand-primary))" 
+    };
+
+    // Merge defaults
+    RT.config.page = Object.assign({}, defaults, RT.config.page || {});
+
+    const conf = RT.config.page;
+    const style_id = 'rt-page-fixed-glow';
+    
+    if (!document.getElementById(style_id)) {
+      const style_el = document.createElement('style');
+      style_el.id = style_id;
+      
+      style_el.textContent = `
+        /* Reset page counter on the article container */
+        rt-article {
+          counter-reset: rt-page-counter;
+        }
+
+        rt-page {
+          display: block;
+          position: relative;
+          box-sizing: border-box;
+          overflow: hidden; 
+
+          /* Dimensions */
+          width: ${conf.width};
+          height: ${conf.height};
+          margin: ${conf.margin};
+          padding: ${conf.padding};
+          
+          /* Theming */
+          background-color: ${conf.bg_color}; 
+          border: 1px solid ${conf.border_color};
+          
+          /* The "Glow" Effect */
+          filter: ${conf.shadow};
+          
+          /* Counter Increment */
+          counter-increment: rt-page-counter;
+        }
+
+        /* Page Numbering */
+        rt-page::after {
+          content: "Page " counter(rt-page-counter);
+          position: absolute;
+          bottom: 1.5rem;
+          right: 3rem;
+          
+          font-family: "Noto Sans", sans-serif;
+          font-size: 0.9rem;
+          font-weight: bold;
+          
+          color: ${conf.text_color}; 
+          opacity: 0.8;
+          pointer-events: none; /* Prevent interference with clicks */
+        }
+      `;
+      document.head.appendChild(style_el);
+    }
+  };
+})();
diff --git a/developer/authored/RT/layout/paginate_by_element.js b/developer/authored/RT/layout/paginate_by_element.js
new file mode 100644 (file)
index 0000000..e085148
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+  Layout Paginator: paginate_by_element
+*/
+window.StyleRT = window.StyleRT || {};
+
+window.StyleRT.paginate_by_element = function() {
+  const RT = window.StyleRT;
+  
+  // Fix: Read safely without overwriting the config namespace
+  const page_conf = (RT.config && RT.config.page) ? RT.config.page : {};
+  const page_height_limit = page_conf.height_limit || 1000; 
+
+  const article_seq = document.querySelectorAll("RT-article");
+  
+  // HURDLE: Error if no articles found to paginate
+  if(article_seq.length === 0) {
+    RT.debug.error('pagination', 'No <RT-article> elements found. Pagination aborted.');
+    return;
+  }
+
+  article_seq.forEach( (article) => {
+    const raw_elements = Array.from(article.children).filter(el => 
+      !['SCRIPT', 'STYLE', 'RT-PAGE'].includes(el.tagName)
+    );
+
+    if(raw_elements.length === 0) return;
+
+    const pages = [];
+    let current_batch = [];
+    let current_h = 0;
+
+    const get_el_height = (el) => {
+      const rect = el.getBoundingClientRect();
+      const style = window.getComputedStyle(el);
+      const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom);
+      return (rect.height || 0) + (margin || 0);
+    };
+
+    for (let i = 0; i < raw_elements.length; i++) {
+      const el = raw_elements[i];
+      const h = get_el_height(el);
+      const is_heading = /^H[1-6]/.test(el.tagName);
+
+      let total_required_h = h;
+      if (is_heading && i + 1 < raw_elements.length) {
+        total_required_h += get_el_height(raw_elements[i + 1]);
+      }
+
+      if (current_h + total_required_h > page_height_limit && current_batch.length > 0) {
+        pages.push(current_batch);
+        current_batch = [];
+        current_h = 0;
+      }
+
+      current_batch.push(el);
+      current_h += h;
+    }
+
+    if (current_batch.length > 0) pages.push(current_batch);
+
+    article.innerHTML = ''; 
+    
+    pages.forEach( (list, index) => {
+      const page_el = document.createElement('rt-page');
+      page_el.id = `page-${index+1}`;
+      list.forEach(item => page_el.appendChild(item));
+      article.appendChild(page_el);
+    });
+
+    if (RT.debug) RT.debug.log('pagination', `Article paginated into ${pages.length} pages.`);
+  });
+};
diff --git a/developer/authored/RT/theme/dark_gold.js b/developer/authored/RT/theme/dark_gold.js
new file mode 100644 (file)
index 0000000..f576147
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+  Theme: Inverse Wheat (Dark)
+  Standard: Theme 1.0
+  Description: High contrast Amber on Deep Charcoal.
+*/
+( function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+  
+  RT.theme = function(){
+    RT.config = RT.config || {};
+    
+    // THEME 1.0 DATA CONTRACT
+    RT.config.theme = {
+       meta_is_dark: true
+      ,meta_name:    "Inverse Wheat"
+
+      // --- SURFACES (Depth & Container Hierarchy) ---
+      ,surface_0:       "hsl(0, 0%, 5%)"      // App Background (Deepest)
+      ,surface_1:       "hsl(0, 0%, 10%)"     // Sidebar / Nav / Panels
+      ,surface_2:       "hsl(0, 0%, 14%)"     // Cards / Floating Elements
+      ,surface_3:       "hsl(0, 0%, 18%)"     // Modals / Dropdowns / Popovers
+      ,surface_input:   "hsl(0, 0%, 12%)"     // Form Inputs
+      ,surface_code:    "hsl(0, 0%, 11%)"     // Code Block Background
+      ,surface_select:  "hsl(45, 100%, 15%)"  // Text Selection Highlight
+
+      // --- CONTENT (Text & Icons) ---
+      ,content_main:    "hsl(50, 60%, 85%)"   // Primary Reading Text
+      ,content_muted:   "hsl(36, 15%, 60%)"   // Metadata, subtitles
+      ,content_subtle:  "hsl(36, 10%, 40%)"   // Placeholders, disabled states
+      ,content_inverse: "hsl(0, 0%, 5%)"      // Text on high-contrast buttons
+
+      // --- BRAND & ACTION (The "Wheat" Identity) ---
+      ,brand_primary:   "hsl(45, 100%, 50%)"  // Main Action / H1 / Focus Ring
+      ,brand_secondary: "hsl(38, 90%, 65%)"   // Secondary Buttons / H2
+      ,brand_tertiary:  "hsl(30, 60%, 70%)"   // Accents / H3
+      ,brand_link:      "hsl(48, 100%, 50%)"  // Hyperlinks (High Visibility)
+
+      // --- BORDERS & DIVIDERS ---
+      ,border_faint:    "hsl(36, 20%, 15%)"   // Subtle separation
+      ,border_default:  "hsl(36, 20%, 25%)"   // Standard Card Borders
+      ,border_strong:   "hsl(36, 20%, 40%)"   // Active states / Inputs
+
+      // --- STATE & FEEDBACK (Earth Tones) ---
+      ,state_success:   "hsl(100, 50%, 45%)"  // Olive Green
+      ,state_warning:   "hsl(35, 90%, 55%)"   // Burnt Orange
+      ,state_error:     "hsl(0, 60%, 55%)"    // Brick Red
+      ,state_info:      "hsl(200, 40%, 55%)"  // Slate Blue
+
+      // --- SYNTAX HIGHLIGHTING (For Code) ---
+      ,syntax_keyword:  "hsl(35, 100%, 65%)"  // Orange
+      ,syntax_string:   "hsl(75, 50%, 60%)"   // Sage Green
+      ,syntax_func:     "hsl(45, 90%, 70%)"   // Light Gold
+      ,syntax_comment:  "hsl(36, 15%, 45%)"   // Brown/Gray
+    };
+
+    // --- APPLY THEME ---
+    const palette = RT.config.theme;
+    const body = document.body;
+    const html = document.documentElement;
+
+    // 1. Paint Base
+    html.style.backgroundColor = palette.surface_0;
+    body.style.backgroundColor = palette.surface_0;
+    body.style.color = palette.content_main;
+
+    // 2. Export Variables (Standardization)
+    const s = body.style;
+    for (const [key, value] of Object.entries(palette)) {
+      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
+    }
+    
+    // 3. Global Overrides
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      style.textContent = `
+        ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: var(--rt-surface-0); }
+        ::-webkit-scrollbar-thumb { 
+           background: var(--rt-border-default); 
+           border: 2px solid var(--rt-surface-0);
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+  
+} )();
diff --git a/developer/authored/RT/theme/light.js b/developer/authored/RT/theme/light.js
new file mode 100644 (file)
index 0000000..4b5eea4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  Theme: Classic Wheat (Light)
+  Standard: Theme 1.0
+  Description: Warm paper tones with Burnt Orange accents.
+*/
+( function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+  
+  RT.theme_light = function(){
+    RT.config = RT.config || {};
+    
+    // THEME 1.0 DATA CONTRACT
+    RT.config.theme = {
+       meta_is_dark: false
+      ,meta_name:    "Classic Wheat"
+
+      // --- SURFACES ---
+      ,surface_0:       "hsl(40, 30%, 94%)"   // App Background (Cream/Linen)
+      ,surface_1:       "hsl(40, 25%, 90%)"   // Sidebar (Slightly darker beige)
+      ,surface_2:       "hsl(40, 20%, 98%)"   // Cards (Lighter, almost white)
+      ,surface_3:       "hsl(0, 0%, 100%)"    // Modals (Pure White)
+      ,surface_input:   "hsl(40, 20%, 98%)"   // Form Inputs
+      ,surface_code:    "hsl(40, 15%, 90%)"   // Code Block Background
+      ,surface_select:  "hsl(45, 100%, 85%)"  // Text Selection Highlight
+
+      // --- CONTENT ---
+      ,content_main:    "hsl(30, 20%, 20%)"   // Deep Umber (Not Black)
+      ,content_muted:   "hsl(30, 15%, 45%)"   // Medium Brown
+      ,content_subtle:  "hsl(30, 10%, 65%)"   // Light Brown/Gray
+      ,content_inverse: "hsl(40, 30%, 94%)"   // Text on dark buttons
+
+      // --- BRAND & ACTION ---
+      ,brand_primary:   "hsl(30, 90%, 35%)"   // Burnt Orange (Action)
+      ,brand_secondary: "hsl(35, 70%, 45%)"   // Rust / Gold
+      ,brand_tertiary:  "hsl(25, 60%, 55%)"   // Copper
+      ,brand_link:      "hsl(30, 100%, 35%)"  // Link Color
+
+      // --- BORDERS ---
+      ,border_faint:    "hsl(35, 20%, 85%)"
+      ,border_default:  "hsl(35, 20%, 75%)"
+      ,border_strong:   "hsl(35, 20%, 55%)"
+
+      // --- STATE & FEEDBACK ---
+      ,state_success:   "hsl(100, 40%, 40%)"  // Forest Green
+      ,state_warning:   "hsl(30, 90%, 50%)"   // Persimmon
+      ,state_error:     "hsl(0, 60%, 45%)"    // Crimson
+      ,state_info:      "hsl(200, 50%, 45%)"  // Navy Blue
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "hsl(20, 90%, 45%)"   // Rust
+      ,syntax_string:   "hsl(100, 35%, 35%)"  // Ivy Green
+      ,syntax_func:     "hsl(300, 30%, 40%)"  // Muted Purple
+      ,syntax_comment:  "hsl(35, 10%, 60%)"   // Light Brown
+    };
+
+    // --- APPLY THEME ---
+    const palette = RT.config.theme;
+    const body = document.body;
+    const html = document.documentElement;
+
+    html.style.backgroundColor = palette.surface_0;
+    body.style.backgroundColor = palette.surface_0;
+    body.style.color = palette.content_main;
+
+    const s = body.style;
+    for (const [key, value] of Object.entries(palette)) {
+      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
+    }
+  };
+} )();
diff --git a/developer/authored/RT/theme/light_gold.js b/developer/authored/RT/theme/light_gold.js
new file mode 100644 (file)
index 0000000..206f3da
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+  Theme: Golden Wheat (Light) - "Spanish Gold Edition"
+  File: style/theme-light-gold.js
+  Standard: Theme 1.0
+  Description: Light Parchment background with Oxblood Red ink.
+*/
+( function(){
+  const RT = window.StyleRT = window.StyleRT || {};
+  
+  RT.theme = function(){
+    RT.config = RT.config || {};
+    
+    RT.config.theme = {
+       meta_is_dark: false
+      ,meta_name:    "Golden Wheat (Yellow)"
+
+      // --- SURFACES (Light Parchment) ---
+      // Shifted lightness up to 94% for a "whiter" feel that still holds the yellow tint.
+      ,surface_0:       "hsl(48, 50%, 94%)"   // Main Page: Fine Parchment
+      ,surface_1:       "hsl(48, 40%, 90%)"   // Panels: Slightly darker
+      ,surface_2:       "hsl(48, 30%, 97%)"   // Cards: Very light
+      ,surface_3:       "hsl(0, 0%, 100%)"    // Popups
+      ,surface_input:   "hsl(48, 20%, 96%)"   
+      ,surface_code:    "hsl(48, 25%, 88%)"   // Distinct Code BG
+      ,surface_select:  "hsl(10, 70%, 85%)"   // Red Highlight
+
+      // --- CONTENT (Deep Ink) ---
+      ,content_main:    "hsl(10, 25%, 7%)"    // Deep Warm Black (Ink)
+      ,content_muted:   "hsl(10, 15%, 35%)"   // Dark Grey-Red
+      ,content_subtle:  "hsl(10, 10%, 55%)"   
+      ,content_inverse: "hsl(48, 50%, 90%)"   
+
+      // --- BRAND & ACTION (The Red Spectrum) ---
+      ,brand_primary:   "hsl(12, 85%, 30%)"   // H1 (Deep Oxblood)
+      ,brand_secondary: "hsl(10, 80%, 35%)"   // H2 (Garnet)
+      ,brand_tertiary:  "hsl(8, 70%, 40%)"    // H3 (Brick)
+      ,brand_link:      "hsl(12, 90%, 35%)"   // Link
+
+      // --- BORDERS ---
+      ,border_faint:    "hsl(45, 30%, 80%)"
+      ,border_default:  "hsl(45, 30%, 70%)"   // Pencil Grey
+      ,border_strong:   "hsl(12, 50%, 40%)"   
+
+      // --- STATE ---
+      ,state_success:   "hsl(120, 40%, 30%)"  
+      ,state_warning:   "hsl(25, 90%, 45%)"   
+      ,state_error:     "hsl(0, 75%, 35%)"    
+      ,state_info:      "hsl(210, 60%, 40%)"  
+
+      // --- SYNTAX ---
+      ,syntax_keyword:  "hsl(0, 75%, 35%)"    
+      ,syntax_string:   "hsl(100, 35%, 25%)"  
+      ,syntax_func:     "hsl(15, 85%, 35%)"   
+      ,syntax_comment:  "hsl(45, 20%, 50%)"   
+    };
+
+    // --- APPLY THEME ---
+    const palette = RT.config.theme;
+    const body = document.body;
+    const html = document.documentElement;
+
+    html.style.backgroundColor = palette.surface_0;
+    body.style.backgroundColor = palette.surface_0;
+    body.style.color = palette.content_main;
+
+    const s = body.style;
+    for (const [key, value] of Object.entries(palette)) {
+      s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value);
+    }
+    
+    // Global overrides
+    const style_id = 'rt-global-overrides';
+    if (!document.getElementById(style_id)) {
+      const style = document.createElement('style');
+      style.id = style_id;
+      style.textContent = `
+        ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); }
+        
+        ::-webkit-scrollbar { width: 12px; }
+        ::-webkit-scrollbar-track { background: var(--rt-surface-0); }
+        ::-webkit-scrollbar-thumb { 
+           background: var(--rt-border-default); 
+           border: 2px solid var(--rt-surface-0);
+           border-radius: 8px; 
+        }
+        ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); }
+
+        rt-article p, rt-article li {
+           text-shadow: 0px 0px 0.5px rgba(0,0,0, 0.2); 
+        }
+
+        .MathJax, .MathJax_Display, .mjx-chtml {
+            color: var(--rt-content-main) !important;
+            fill: var(--rt-content-main) !important;
+            stroke: var(--rt-content-main) !important;
+        }
+      `;
+      document.head.appendChild(style);
+    }
+  };
+  
+} )();
diff --git a/developer/authored/hello.cli.c b/developer/authored/hello.cli.c
deleted file mode 100644 (file)
index a626cac..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include <stdio.h>
-int main(void){ puts("hello from Rabbit CLI"); return 0; }
index 2495705..2350fd8 100755 (executable)
@@ -4,8 +4,8 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 # input guards
 
   setup_must_be="developer/tool/setup"
-  if [ "$ENV" != "$env_must_be" ]; then
-    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+  if [ "$SETUP" != "$setup_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $setup_must_be environment"
     exit 1
   fi
 
index 58636de..42babce 100755 (executable)
@@ -4,8 +4,8 @@ script_afp=$(realpath "${BASH_SOURCE[0]}")
 # input guards
 
   setup_must_be="developer/tool/setup"
-  if [ "$ENV" != "$env_must_be" ]; then
-    echo "$(script_fp):: error: must be run in the $env_must_be environment"
+  if [ "$SETUP" != "$setup_must_be" ]; then
+    echo "$(script_fp):: error: must be run in the $setup_must_be environment"
     exit 1
   fi
 
@@ -15,12 +15,7 @@ set -x
   cd "$REPO_HOME"/developer || exit 1
   # /bin/make -f tool/makefile $@
 
-  mkdir -p scratchpad/authored
-  cp authored/HTTP_server.js scratchpad/authored/
-  cp authored/port_forwarder scratchpad/authored/
-  cp authored/port_forwarder_CLI scratchpad/authored/
-  cp authored/permission_RT scratchpad/authored/
-  cp authored/permission_UPG scratchpad/authored/
+  mkdir -p scratchpad/stage && cp -au authored/RT scratchpad/stage/
 
 set +x
 echo "$(script_fn) done."
index 2b1027a..24f260c 100755 (executable)
@@ -4,10 +4,10 @@
 import os ,sys ,shutil ,stat ,pwd ,grp ,glob ,tempfile
 
 HELP = """usage: release {write|clean|ls|diff|help|dry write}
-  write       Writes promoted files from scratchpad/stage into user/release. Only updates newer files.
-  clean       Remove all contents of the user/release directory.
-  ls          List user/release as an indented tree: PERMS  OWNER  NAME.
-  diff        List files in user/release that are not in scratchpad/stage, or are newer.
+  write       Writes promoted files from scratchpad/stage into consumer/release. Only updates newer files.
+  clean       Remove all contents of the consumer/release directory.
+  ls          List consumer/release as an indented tree: PERMS  OWNER  NAME.
+  diff        List files in consumer/release that are not in scratchpad/stage, or are newer.
   help        Show this message.
   dry write   Preview what write would do without modifying the filesystem.
 """
@@ -20,15 +20,15 @@ def exit_with_status(msg ,code=1):
   print(f"release: {msg}" ,file=sys.stderr)
   sys.exit(code)
 
-def assert_env():
-  env = os.environ.get("ENV" ,"")
-  if(env != ENV_MUST_BE):
+def assert_setup():
+  setup_val = os.environ.get("SETUP" ,"")
+  if(setup_val != SETUP_MUST_BE):
     hint = (
       "SETUP is not 'developer/tool/setup'.\n"
       "Enter the project with:  . setup developer\n"
       "That script exports: ROLE=developer; SETUP=$ROLE/tool/setup"
     )
-    exit_with_status(f"bad environment: ENV='{env}'. {hint}")
+    exit_with_status(f"bad environment: SETUP='{setup_val}'. {hint}")
 
 def repo_home():
   rh = os.environ.get("REPO_HOME")
@@ -43,10 +43,10 @@ def dpath(*parts):
     ,*parts
   )
 
-def upath(*parts):
+def cpath(*parts):
   return os.path.join(
     repo_home()
-    ,"user"
+    ,"consumer"
     ,"release"
     ,*parts
   )
@@ -54,8 +54,8 @@ def upath(*parts):
 def dev_root():
   return dpath()
 
-def user_root():
-  return upath()
+def consumer_root():
+  return cpath()
 
 def _display_src(p_abs: str) -> str:
   try:
@@ -69,10 +69,10 @@ def _display_dst(p_abs: str) -> str:
   try:
     rel = os.path.relpath(
       p_abs
-      ,user_root()
+      ,consumer_root()
     )
     rel = "" if rel == "." else rel
-    return "$REPO_HOME/user/release" + ("/" + rel if rel else "")
+    return "$REPO_HOME/consumer/release" + ("/" + rel if rel else "")
   except Exception:
     return p_abs
 
@@ -83,7 +83,7 @@ def ensure_mode(path_str ,mode):
 def ensure_dir(path_str ,mode=DEFAULT_DIR_MODE ,dry=False):
   if(dry):
     if( not os.path.isdir(path_str) ):
-      shown = _display_dst(path_str) if path_str.startswith(user_root()) else (
+      shown = _display_dst(path_str) if path_str.startswith(consumer_root()) else (
         os.path.relpath(path_str ,dev_root()) if path_str.startswith(dev_root()) else path_str
       )
       print(f"(dry) mkdir -m {oct(mode)[2:]} '{shown}'")
@@ -141,7 +141,7 @@ def list_tree(root_dp):
     if( len(ownergrp) > ogw ):
       ogw = len(ownergrp)
 
-  print("user/release/")
+  print("consumer/release/")
   for isdir ,depth ,perms ,ownergrp ,name in entries:
     indent = "  " * depth
     print(f"{perms}  {ownergrp:<{ogw}}  {indent}{name}")
@@ -175,8 +175,8 @@ def copy_one(src_abs ,dst_abs ,mode ,dry=False):
   print(f"+ install -m {oct(mode)[2:]} '{src_show}' '{dst_show}'")
 
 def cmd_write(dry=False):
-  assert_env()
-  ensure_dir(upath() ,DEFAULT_DIR_MODE ,dry=dry)
+  assert_setup()
+  ensure_dir(cpath() ,DEFAULT_DIR_MODE ,dry=dry)
 
   src_root = dpath(
     "scratchpad"
@@ -192,7 +192,7 @@ def cmd_write(dry=False):
     for fn in files:
       src_abs = os.path.join(root ,fn)
       rel = os.path.relpath(src_abs ,src_root)
-      dst_abs = os.path.join(upath() ,rel)
+      dst_abs = os.path.join(cpath() ,rel)
 
       if( os.path.exists(dst_abs) ):
         src_mtime = os.stat(src_abs).st_mtime
@@ -216,8 +216,8 @@ def cmd_write(dry=False):
     print(f"(info) nothing new to promote from {_display_src(src_root)}")
 
 def cmd_diff():
-  assert_env()
-  dst_root = upath()
+  assert_setup()
+  dst_root = cpath()
   src_root = dpath(
     "scratchpad"
     ,"stage"
@@ -250,12 +250,12 @@ def cmd_diff():
     print("No differences found. Release matches stage.")
 
 def cmd_clean():
-  assert_env()
-  user_root_dir = upath()
-  if( not os.path.isdir(user_root_dir) ):
+  assert_setup()
+  consumer_root_dir = cpath()
+  if( not os.path.isdir(consumer_root_dir) ):
     return
-  for name in os.listdir(user_root_dir):
-    p = os.path.join(user_root_dir ,name)
+  for name in os.listdir(consumer_root_dir):
+    p = os.path.join(consumer_root_dir ,name)
     if( os.path.isdir(p) and not os.path.islink(p) ):
       shutil.rmtree(p ,ignore_errors=True)
     else:
@@ -272,7 +272,7 @@ def CLI():
   elif(cmd == "clean"):
     cmd_clean()
   elif(cmd == "ls"):
-    list_tree(upath())
+    list_tree(cpath())
   elif(cmd == "diff"):
     cmd_diff()
   elif(cmd == "help"):