*~
*.bak
-# so that .gitignore is not required in user/release
-/user/release
+# so that .gitignore is not required in /consumer/release
+/consumer/release
+
+++ /dev/null
-/*
- 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;
+++ /dev/null
-/*
- 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;
+++ /dev/null
-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>');
-};
+++ /dev/null
-/*
- 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'
- ,'scroll'
- ]),
-
- active_tokens: new Set([
- 'term'
- ]),
-*/
-
- active_tokens: new Set([
- ]),
-
- 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');
- }
-};
+++ /dev/null
-window.RT_REPO_ROOT = "../../../../";
-document.write('<script src="' + window.RT_REPO_ROOT + 'shared/style_directory_dict.js"></script>');
-document.write('<script src="' + window.RT_REPO_ROOT + 'developer/authored/RT/core/loader.js"></script>');
-document.write('<script src="' + window.RT_REPO_ROOT + 'developer/authored/RT/core/body_visibility_hidden.js"></script>');
+++ /dev/null
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>RT Style System: Reference Manual</title>
- <script src="setup.js"></script>
- <script>
- window.StyleRT.include('RT/theme');
- window.StyleRT.include('RT/layout/article_tech_ref');
- </script>
- </head>
- <body>
-
- <RT-article>
- <RT-title author="Gemini" date="2026-01-14" title="RT Style System: Reference Manual"></RT-title>
-
- <RT-TOC level="1"></RT-TOC>
-
- <h1> Table of Custom Tags </h1>
-
- <h2>Style Tag Reference</h2>
-
- <table>
- <thead>
- <tr>
- <th>Tag</th>
- <th>Description</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><RT-code><RT-article></RT-code></td>
- <td>Article container.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-title></RT-code></td>
- <td>
- Title block and metadata.
- </td>
- </tr>
-
- <tr>
- <td><RT-code><RT-TOC></RT-code></td>
- <td>Generates TOC.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-term></RT-code></td>
- <td>Conventional term.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-term-em></RT-code></td>
- <td>Forces emphasis for a term even after first occurrence.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-neologism></RT-code></td>
- <td>Project specific term.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-neologism-em></RT-code></td>
- <td>Forces emphasis for a neologism even after first occurrence.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-code></RT-code></td>
- <td>Code span or code block.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-math></RT-code></td>
- <td>Inline or block math.</td>
- </tr>
-
- <tr>
- <td><RT-code><RT-page></RT-code></td>
- <td>Automatically inserted pagination tag.</td>
- </tr>
- </tbody>
- </table>
-
- <h1>Architecture Overview</h1>
- <p>
- The <RT-term>RT Style System</RT-term> is a client-side, JavaScript-driven publishing framework designed to turn raw HTML into high-readability technical documentation. Unlike standard CSS frameworks, RT uses JavaScript to handle complex layout tasks like <RT-neologism>ink-ratio balancing</RT-neologism> and dynamic pagination.
- </p>
-
- <h2>Pulling style files into a document</h2>
- <p> Put `setup.js` in the directory, and include it at the top of the document,
- `setup.js` points at the style files and is installation specific.</p>
-
-
- <h1>Semantic Tags</h1>
- <p>
- The system relies on a specific set of custom tags in the <RT-code>RT-</RT-code> namespace to separate structure from presentation.
- </p>
-
- <h2>Terminology</h2>
-
- <h3>Conventional Terms</h3>
- <p>
- Use <RT-code><RT-term></RT-code> for standard, industry accepted technical terms. The system decorates only the first occurrence of each unique term so that the first appearance functions as a definition point, and later appearances do not overload the page with styling.
- </p>
-
- <RT-code>
- The <RT-term>Singleton Pattern</RT-term> restricts instantiation...
- </RT-code>
-
- <p>
- <em>Renders as:</em> The <RT-term>Singleton Pattern</RT-term> restricts instantiation...
- </p>
-
- <h3>Neologisms</h3>
- <p>
- Use <RT-code><RT-neologism></RT-code> for terms invented specifically for the current document or project. Neologisms are styled more strongly than conventional terms, visually distinguishing "jargon you should know" from "jargon we just made up."
- </p>
-
- <RT-code>
- We define the <RT-neologism>Hyper Tape</RT-neologism> as a construct...
- </RT-code>
-
- <p>
- <em>Renders as:</em> We define the <RT-neologism>Hyper Tape</RT-neologism> as a construct...
- </p>
-
- <h3>First Occurrence Rule</h3>
- <p>
- The term system is intentionally conservative. For the tags <RT-code><RT-term></RT-code> and <RT-code><RT-neologism></RT-code>, only the first occurrence of a unique term is decorated. Subsequent mentions are rendered as normal prose.
- </p>
-
- <p>
- Uniqueness is tracked by normalizing the term text (trimmed, then lowercased). This means that <RT-code>Symbol</RT-code> and <RT-code>symbol</RT-code> count as the same term.
- </p>
-
- <h3>Forced Emphasis Variants</h3>
- <p>
- Sometimes a later mention of a term should be emphasized again. For that purpose, the system provides explicit emphasis tags:
- </p>
-
- <ul>
- <li><RT-code><RT-term-em></RT-code></li>
- <li><RT-code><RT-neologism-em></RT-code></li>
- </ul>
-
- <p>
- These variants are always decorated, even if the term appeared earlier.
- </p>
-
- <h3>Automatic Definition Anchors</h3>
- <p>
- For first occurrences, the term module automatically assigns an <RT-code>id</RT-code> attribute if one does not already exist. This creates stable anchors for future indexing and linking.
- </p>
-
- <RT-code>
- We define a <RT-term>Symbol</RT-term> as...
- </RT-code>
-
- <p>
- The first occurrence will be given an id similar to <RT-code>def-symbol</RT-code>. For neologisms, an additional marker is used, for example <RT-code>def-neo-hyper-tape</RT-code>.
- </p>
-
- <h2>Technical Content</h2>
-
- <h3>Code</h3>
- <p>
- Use <RT-code><RT-code></RT-code>. If placed inline, it acts like a span. If placed as a block (with newlines), it acts like a pre formatted block with a theme aware border.
- </p>
-
- <RT-code>
- # Block Code Example
- def hello():
- return "World"
- </RT-code>
-
- <h3>Mathematics</h3>
- <p>
- Use <RT-code><RT-math></RT-code>. The system auto detects if it is a block equation or inline variable and wraps it in MathJax delimiters.
- </p>
- <p>
- Inline: Let <RT-math>x</RT-math> be the input.
- </p>
- <p>
- Block:
- </p>
- <RT-math>
- f(x) = \sum_{i=0}^{n} x_i
- </RT-math>
-
- <h1>Navigation & Layout</h1>
-
- <h2>Automatic Table of Contents</h2>
- <p>
- Use <RT-code><RT-TOC></RT-code> to insert a generated table of contents. The tag scans the document <em>forward</em> from its current position to collect headings.
- </p>
-
- <h3>Explicit Mode</h3>
- <p>
- Use the <RT-code>level="N"</RT-code> attribute to target a specific heading depth.
- </p>
- <ul>
- <li><RT-code><RT-TOC level="1"></RT-code>: Collects all <RT-code><h1></RT-code> elements until the end of the document. Best for the main document index.</li>
- <li><RT-code><RT-TOC level="2"></RT-code>: Collects all <RT-code><h2></RT-code> elements until it encounters the next <RT-code><h1></RT-code>. Best for chapter summaries.</li>
- </ul>
-
- <h3>Implicit Mode</h3>
- <p>
- If no level is specified, the TOC scans backwards to find the nearest heading (for example H1) and assumes you want to collect children one level deeper (for example H2).
- </p>
- <p>
- <em>Note: Implicit mode can fail if placed before the first heading of a section. Use explicit levels for robust results.</em>
- </p>
-
- <h2>The Title Block</h2>
- <p>
- Use <RT-code><RT-title></RT-code> as the first element in your <RT-code><body></RT-code> (before the article container). This tag generates a standardized, styled header block with the document title and metadata.
- </p>
-
- <h3>Attributes</h3>
- <ul>
- <li><RT-code>title</RT-code> (Required): The main heading of the document.</li>
- <li><RT-code>author</RT-code> (Optional): The author's name. Renders in a bold accent color.</li>
- <li><RT-code>date</RT-code> (Optional): The publication or revision date.</li>
- </ul>
-
- <h3>Example</h3>
- <RT-code>
- <RT-title
- title="RT Style System: Reference Manual"
- author="Gemini"
- date="2026-01-14">
- </RT-title>
- </RT-code>
-
- <p>
- <em>Renders as:</em> A centered, high contrast H1 followed by a serif styled metadata row containing the author and date.
- </p>
-
- <h2>The Article Container</h2>
- <p>
- The root element must be <RT-code><RT-article></RT-code>. This is the boundary for the pagination logic.
- </p>
-
- <h2>Pagination</h2>
- <p>
- The script <RT-code>paginate_by_element.js</RT-code> scans the article. It calculates the height of every element (including margins) and bundles them into <RT-code><RT-page></RT-code> elements.
- </p>
- <p>
- <RT-neologism>Soft Limit Pagination</RT-neologism>: The system attempts to keep headers with their following paragraphs. It will break a page early rather than stranding a header at the bottom.
- </p>
-
- <h1>Debugging</h1>
-
- <h2>Debug Tokens</h2>
- <p>
- RT provides a lightweight debug logging system in <RT-code>utility.js</RT-code>. Logging is controlled by a set of active debug tokens. Each log message is assigned a token, and the message prints only if that token is enabled.
- </p>
-
- <p>
- Examples of common tokens include <RT-code>style</RT-code>, <RT-code>layout</RT-code>, <RT-code>pagination</RT-code>, <RT-code>selector</RT-code>, <RT-code>config</RT-code>, and <RT-code>term</RT-code>.
- </p>
-
- <h2>How Logging is Gated</h2>
- <p>
- Normal log and warning output are gated. The methods <RT-code>debug.log(token,message)</RT-code> and <RT-code>debug.warn(token,message)</RT-code> will print only when the token exists in <RT-code>debug.active_tokens</RT-code>.
- </p>
-
- <p>
- This prevents the console from being flooded during normal use, while still allowing deep visibility during development.
- </p>
-
- <h2>Errors are Always Printed</h2>
- <p>
- Errors are treated differently. The method <RT-code>debug.error(token,message)</RT-code> always prints, regardless of token state. These messages represent failures that require attention.
- </p>
-
- <h2>Enabling and Disabling Tokens</h2>
- <p>
- Tokens may be enabled or disabled in two ways: by editing the <RT-code>active_tokens</RT-code> set in <RT-code>utility.js</RT-code>, or at runtime by calling:
- </p>
-
- <RT-code>
- window.StyleRT.debug.enable('term')
- window.StyleRT.debug.disable('term')
- </RT-code>
-
- <p>
- For example, the term system (<RT-code>RT_term.js</RT-code>) uses the <RT-code>term</RT-code> token. When that token is enabled, the module will print messages describing how terms were detected and which term definitions were assigned IDs.
- </p>
-
- <h1>Themes</h1>
- <p>
- The system supports hot swapping themes by changing the script import in the head.
- </p>
- <ul>
- <li><strong>Dark:</strong> <RT-code>style/theme_dark_gold.js</RT-code> (Default)</li>
- <li><strong>Light:</strong> <RT-code>style/theme_light_gold.js</RT-code></li>
- </ul>
-
- <h1>Manifest</h1>
- <RT-code>
- 1. style_orchestrator.js (Example/default footer script)
- 2. utility.js (Math/Color physics)
- 3. article_tech_ref.js (Typography and CSS injection)
- 4. RT_code.js (Code block logic)
- 5. RT_math.js (MathJax wrapper)
- 6. RT_term.js (Term styling)
- 7. RT_TOC.js (Navigation generator)
- 8. paginate_by_element.js (Page splitter)
- 9. page_fixed_glow.js (Visual page container)
- </RT-code>
-
- <script src="style/style_orchestrator.js"></script>
- <script>
- window.StyleRT.style_orchestrator();
- </script>
-
- <h1>RT Conventions</h1>
- <p> Headings are first letter capitalized. Remaining words are as they would be in English prose.</p>
-
- <h1>Exercises</h1>
-
- <ol>
- <li>
- <p>
- <strong>Term Occurrences:</strong> If an author tags a word with <RT-code><RT-term></RT-code> five times in a document, how many times will the term be visually decorated by the styling engine? How does a person force the engine to decorate a later occurrence?
- </p>
- </li>
- <li>
- <p>
- <strong>Term Normalization:</strong> A person writes <RT-code><RT-term>Parse Tree</RT-term></RT-code> in paragraph one, and <RT-code><RT-term>parse tree</RT-term></RT-code> in paragraph two. Will the system assign a definition anchor to the second occurrence?
- </p>
- </li>
- <li>
- <p>
- <strong>TOC Generation:</strong> What happens if one places an <RT-code><RT-TOC></RT-code> tag without a level attribute before the first heading of a section?
- </p>
- </li>
- <li>
- <p>
- <strong>Code and Math Formatting:</strong> How does the RT system determine whether to render an <RT-code><RT-code></RT-code> or <RT-code><RT-math></RT-code> element inline with the text versus as a standalone block?
- </p>
- </li>
- <li>
- <p>
- <strong>Pagination Logic:</strong> When the script bundles elements into an <RT-code><RT-page></RT-code> container, how does the soft limit pagination handle a heading that falls at the very bottom of the page capacity?
- </p>
- </li>
- </ol>
-
- </RT-article>
- </body>
-</html>
+++ /dev/null
-/*
- 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).
-
-First heading 1 1
- First heading 2 2
- Next heading 2 2
-Next heading 2 3
-
-*/
-
-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. Parse attribute: single number N or range A-B
- const attr_val = container.getAttribute('level');
- let start_level, end_level;
-
- if (attr_val) {
- const rangeMatch = attr_val.match(/^(\d)-(\d)$/);
- if (rangeMatch) {
- const a = parseInt(rangeMatch[1]);
- const b = parseInt(rangeMatch[2]);
- if (a >= 1 && a <= 6 && b >= 1 && b <= 6 && a <= b) {
- start_level = a;
- end_level = b;
- if (debug.log) debug.log('TOC', `TOC #${TOC_index} range: H${a}-H${b}`);
- } else {
- if (debug.log) debug.log('TOC', `Invalid range "${attr_val}" → implicit mode`);
- }
- } else {
- const single = parseInt(attr_val);
- if (!isNaN(single) && single >= 1 && single <= 6) {
- start_level = single;
- end_level = single;
- if (debug.log) debug.log('TOC', `TOC #${TOC_index} single level: H${single}`);
- } else {
- if (debug.log) debug.log('TOC', `Invalid level "${attr_val}" → implicit mode`);
- }
- }
- }
-
- // 2. Implicit mode (no attribute or invalid)
- if (start_level === undefined || end_level === undefined) {
- let context_level = 0;
- 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;
- }
- const target_level = Math.min(context_level + 1, 6);
- start_level = target_level;
- end_level = target_level;
- if (debug.log) debug.log('TOC', `TOC #${TOC_index} implicit target: H${target_level}`);
- }
-
- // 3. Collect all matching headings until a higher-level heading stops us
- const headings = [];
- 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 if we hit a heading that is a parent of the lowest level we collect
- if (found_level < start_level) break;
-
- // Collect if within the requested range
- if (found_level >= start_level && found_level <= end_level) {
- // Ensure it has an id
- if (!next_el.id) {
- next_el.id = `TOC-ref-${TOC_index}-${found_level}-${headings.length}`;
- }
- headings.push({ el: next_el, level: found_level });
- }
- }
- next_el = next_el.nextElementSibling;
- }
-
- // 4. Build the container (title + list)
- container.innerHTML = '';
- const title = document.createElement('h1');
- title.textContent = start_level === 1 ? 'Table of Contents' : 'Section Contents';
- title.style.textAlign = 'center';
- container.appendChild(title);
-
- if (headings.length === 0) return; // nothing to show
-
- // Top-level list
- const topList = document.createElement('ul');
- topList.style.listStyle = 'none';
- topList.style.paddingLeft = '0';
- container.appendChild(topList);
-
- // Stack of <ul> elements; index 0 = top-level list
- const listStack = [topList];
-
- for (const item of headings) {
- // Depth relative to start_level
- const depth = item.level - start_level; // 0 = top-level, 1 = sub-level, etc.
-
- // Ensure we have the correct nesting depth
- while (listStack.length - 1 > depth) {
- // Pop until we are at the right depth
- listStack.pop();
- }
-
- // If we need to go deeper, open new sub-lists inside the last <li>
- while (listStack.length - 1 < depth) {
- const parentList = listStack[listStack.length - 1];
- const lastLi = parentList.lastElementChild;
- if (lastLi) {
- const subList = document.createElement('ul');
- subList.style.listStyle = 'none';
- subList.style.paddingLeft = '1.5rem'; // indentation for nested items
- lastLi.appendChild(subList);
- listStack.push(subList);
- } else {
- // No parent <li> yet – stay at current depth (flatten)
- break;
- }
- }
-
- // Create the <li> for this heading
- const li = document.createElement('li');
- li.style.marginBottom = '0.5rem';
-
- const a = document.createElement('a');
- a.href = `#${item.el.id}`;
- a.textContent = item.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);
- // Add to the current deepest list
- listStack[listStack.length - 1].appendChild(li);
- }
- });
-};
+++ /dev/null
-/*
- 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;
+++ /dev/null
-/*
- 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;
+++ /dev/null
-/*
- 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)}`);
- }
-};
+++ /dev/null
-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);
+++ /dev/null
-/*
- 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(' — ');
- container.appendChild(meta);
- }
-
- // Replace the raw tag with the generated block
- el.replaceWith(container);
- });
-};
+++ /dev/null
-// debug messsages don't work here, because RT/core/utility isn't loaded until after the function runs.
-(function(){
- const RT = window.StyleRT = window.StyleRT || {};
- const debug = RT.debug || { log: function(){} };
-
- debug.log('scroll', "1. Initializing script.");
-
- // 1. Intercept native history restoration immediately
- if ('scrollRestoration' in history) {
- history.scrollRestoration = 'manual';
- debug.log('scroll', "2. history.scrollRestoration set to manual.");
- }
-
- // 2. Read coordinate from memory before any layout shifts occur
- const raw_target = sessionStorage.getItem('RT_saved_y');
- const target_y = raw_target !== null ? parseInt(raw_target, 10) : 0;
-
- // 3. Determine if the execution is a page reload
- let is_reload = false;
- if (window.performance) {
- const nav_entries = performance.getEntriesByType("navigation");
- if (nav_entries.length > 0) {
- is_reload = (nav_entries[0].type === "reload");
- } else if (performance.navigation) {
- is_reload = (performance.navigation.type === 1);
- }
- }
-
- debug.log('scroll', `3. Target Y: ${target_y} | Is Reload: ${is_reload}`);
-
- // 4. The Lock
- let is_layout_locked = true;
-
- // 5. Declare Dependencies
- 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');
-
- // 6. The Typography Layout
- 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)";
- }
-
- window.StyleRT = window.StyleRT || {};
- window.StyleRT.config = window.StyleRT.config || {};
- window.StyleRT.config.page = window.StyleRT.config.page || {};
- window.StyleRT.config.page.height_limit = 900;
-
- const style_node = document.createElement("style");
- style_node.innerHTML = `
- body, html, rt-article {
- overflow-anchor: none !important;
- }
-
- rt-article {
- font-family: 'Noto Sans JP', Arial, sans-serif;
- background-color: var(--rt-surface-0);
- color: var(--rt-content-main);
- max-width: 46.875rem !important;
- box-sizing: border-box !important;
- }
-
- rt-article:not(:has(rt-page)) {
- padding: 3rem !important;
- }
-
- rt-article:has(rt-page) {
- padding: 0 !important;
- }
-
- rt-article rt-page {
- position: relative;
- display: block;
- padding: 3rem;
- margin: 1.25rem auto;
- background-color: var(--rt-surface-0);
- box-shadow: 0 0 0.625rem var(--rt-brand-primary);
- }
-
- rt-article h1 {
- font-size: 1.5rem;
- text-align: center;
- color: var(--rt-brand-primary);
- font-weight: 500;
- margin-top: 1.5rem;
- line-height: 1.15;
- }
- rt-article h2 {
- font-size: 1.25rem;
- color: var(--rt-brand-secondary);
- text-align: left;
- margin-top: 2rem;
- margin-left: 0;
- }
- rt-article h3 {
- font-size: 1.125rem;
- color: var(--rt-brand-tertiary);
- text-align: left;
- margin-top: 1.5rem;
- margin-left: 4ch;
- }
- rt-article h4 {
- font-size: 1.05rem;
- color: var(--rt-content-main);
- font-weight: 600;
- text-align: left;
- margin-top: 1.25rem;
- margin-left: 8ch;
- }
-
- rt-article p,
- rt-article ul,
- rt-article ol {
- color: var(--rt-content-main);
- text-align: justify;
- margin-bottom: 1rem;
- margin-left: 0;
- }
- rt-article li {
- margin-bottom: 0.5rem;
- }
-
- rt-article rt-code {
- font-family: 'Courier New', Courier, monospace;
- background-color: var(--rt-surface-code);
- padding: 0.125rem 0.25rem;
- color: var(--rt-content-main);
- }
- `;
- document.head.appendChild(style_node);
- };
-
- // 7. The Execution Sequence
- function run_semantics() {
- debug.log('scroll', `4. run_semantics starting.`);
- if(RT.theme) RT.theme();
- RT.article();
- if(RT.title) RT.title();
- if(RT.term) RT.term();
- if(RT.math) RT.math();
- if(RT.code) RT.code();
-
- if(window.MathJax && MathJax.Hub && MathJax.Hub.Queue){
- MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,run_layout );
- }else{
- run_layout();
- }
- }
-
- function run_layout() {
- debug.log('scroll', `5. run_layout starting.`);
- 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();
-
- debug.log('scroll', `6. Pagination complete.`);
-
- let final_target = target_y;
- let use_hash = false;
-
- if (window.location.hash && !is_reload) {
- const hash_target = document.getElementById(window.location.hash.substring(1));
- if (hash_target) {
- use_hash = true;
- }
- }
-
- debug.log('scroll', `7. Commencing viewport enforce loop. Mode: ${use_hash ? 'HASH' : 'Y-COORDINATE'}`);
- enforce_scroll(final_target, use_hash, 0);
- }
-
- // 8. The Enforcer Logic
- function enforce_scroll(target, use_hash, attempts) {
- if (attempts > 15) {
- debug.log('scroll', "8. Scroll enforcement timed out. Unlocking.");
- is_layout_locked = false;
- return;
- }
-
- if (use_hash) {
- const hash_target = document.getElementById(window.location.hash.substring(1));
- if (hash_target) {
- hash_target.scrollIntoView();
- debug.log('scroll', `8a. Attempt ${attempts}: Scrolled to Hash Target. Y is now ${window.scrollY}`);
- }
- } else {
- window.scrollTo(0, target);
- debug.log('scroll', `8b. Attempt ${attempts}: Scrolled to Y=${target}. Current Y is ${window.scrollY}`);
- }
-
- let is_successful = false;
- if (use_hash) {
- is_successful = true;
- } else {
- is_successful = (Math.abs(window.scrollY - target) < 5 || target === 0);
- }
-
- if (is_successful && document.body.scrollHeight > 1000) {
- debug.log('scroll', `9. Viewport anchored successfully.`);
-
- setTimeout(() => {
- if (!use_hash && Math.abs(window.scrollY - target) >= 5) {
- debug.log('scroll', `9a. Browser late-stage rebellion detected. Re-enforcing.`);
- enforce_scroll(target, use_hash, attempts + 1);
- } else {
- is_layout_locked = false;
- debug.log('scroll', "10. Layout fully unlocked.");
- }
- }, 100);
- } else {
- setTimeout(() => enforce_scroll(target, use_hash, attempts + 1), 50);
- }
- }
-
- // 9. The Ledger
- let scroll_timer;
- window.addEventListener('scroll', () => {
- if (is_layout_locked) return;
- clearTimeout(scroll_timer);
- scroll_timer = setTimeout(() => {
- sessionStorage.setItem('RT_saved_y', window.scrollY);
- debug.log('scroll', `X. User stopped scrolling. Saved Y: ${window.scrollY}`);
- }, 200);
- }, { passive: true });
-
- window.addEventListener('beforeunload', () => {
- is_layout_locked = true;
- debug.log('scroll', "Y. Page unloading. Scroll listener locked.");
- });
-
- // 10. Bind to DOM Ready
- document.addEventListener( 'DOMContentLoaded' ,run_semantics );
-
-})();
+++ /dev/null
-/*
- <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);
-
-})();
+++ /dev/null
-/*
- Page Layout: Fixed Glow
- Standard: Theme 1.0
- Description: A variable-height container with a glowing border effect that matches the active theme.
-*/
-(function(){
- const RT = window.StyleRT = window.StyleRT || {};
-
- RT.page = function() {
- RT.config = RT.config || {};
-
- // Default Configuration
- const defaults = {
- width: "100%"
- ,min_height: "15rem" // Replaces fixed height
- ,padding: "3rem"
- ,margin: "4rem auto"
-
- ,bg_color: "var(--rt-surface-0)"
- ,border_color: "var(--rt-brand-primary)"
- ,text_color: "var(--rt-brand-primary)"
-
- ,shadow: "drop-shadow(0px 0px 15px var(--rt-brand-primary))"
- };
-
- 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};
- min-height: ${conf.min_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;
- }
- `;
- document.head.appendChild(style_el);
- }
- };
-})();
+++ /dev/null
-window.StyleRT.paginate_by_element = function () {
- const RT = window.StyleRT;
- 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');
- if (article_seq.length === 0) {
- RT.debug.error('pagination', 'No <RT-article> elements found. Pagination aborted.');
- return;
- }
-
- // ---------- helpers ----------
- const get_el_height = (el) => {
- const wasInDOM = el.parentNode !== null;
- if (!wasInDOM) document.body.appendChild(el);
- const rect = el.getBoundingClientRect();
- const style = window.getComputedStyle(el);
- const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom);
- if (!wasInDOM) el.remove();
- return (rect.height || 0) + (margin || 0);
- };
-
- // Create a hidden measurement container that mimics the article's layout
- let measureContainer = null;
- const getMeasureContainer = () => {
- if (measureContainer && measureContainer.parentNode) return measureContainer;
- const article = document.querySelector('RT-article');
- if (!article) {
- const temp = document.createElement('div');
- temp.style.visibility = 'hidden';
- temp.style.position = 'absolute';
- temp.style.width = '100%'; // fallback
- document.body.appendChild(temp);
- measureContainer = temp;
- return temp;
- }
- const container = document.createElement('div');
- // Copy the computed width and font styles from the article
- const articleStyle = window.getComputedStyle(article);
- container.style.visibility = 'hidden';
- container.style.position = 'absolute';
- container.style.width = articleStyle.width;
- container.style.fontFamily = articleStyle.fontFamily;
- container.style.fontSize = articleStyle.fontSize;
- container.style.lineHeight = articleStyle.lineHeight;
- container.style.fontWeight = articleStyle.fontWeight;
- document.body.appendChild(container);
- measureContainer = container;
- return container;
- };
-
- // Measure a fragment by temporarily inserting it into the measurement container
- const measureFragment = (frag) => {
- const container = getMeasureContainer();
- container.appendChild(frag);
- const h = get_el_height(frag);
- container.removeChild(frag);
- return h;
- };
-
- const isSplittable = (el) => {
- const tag = el.tagName;
- if (tag === 'UL' || tag === 'OL') {
- const items = Array.from(el.children).filter(c => c.tagName === 'LI');
- if (items.length === 0) return null;
-
- // Measure item heights once (still in DOM)
- const itemHeights = items.map(li => get_el_height(li));
-
- // Measure empty list overhead
- const emptyClone = el.cloneNode(false);
- const overhead = get_el_height(emptyClone);
-
- // Store info on the original element (and on rest fragments later)
- el._splitInfo = { type: 'list', itemHeights, overhead, offset: 0 };
- return makeListSplitter(el, el._splitInfo);
- }
-
- if (tag === 'TABLE') {
- const thead = el.querySelector('thead');
- const tbody = el.querySelector('tbody');
- const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows);
- if (rows.length === 0) return null;
-
- const theadHeight = thead ? get_el_height(thead) : 0;
- const rowHeights = rows.map(row => get_el_height(row));
-
- const emptyClone = el.cloneNode(false);
- if (thead) {
- const theadClone = thead.cloneNode(true);
- emptyClone.appendChild(theadClone);
- }
- const tbodyClone = document.createElement('tbody');
- emptyClone.appendChild(tbodyClone);
- const overhead = get_el_height(emptyClone) - theadHeight;
-
- el._splitInfo = { type: 'table', rowHeights, overhead, theadHeight, offset: 0 };
- return makeTableSplitter(el, el._splitInfo);
- }
-
- return null; // not splittable
- };
-
- function makeListSplitter(el, info) {
- return (remaining) => {
- const children = Array.from(el.children).filter(c => c.tagName === 'LI');
- const start = info.offset;
- const relevantHeights = info.itemHeights.slice(start, start + children.length);
-
- // Build fragments iteratively and measure them for exact height
- let bestCount = 0;
- let bestHeight = 0;
- // Try to include as many items as possible
- const tempList = el.cloneNode(false);
- for (let i = 0; i < children.length; i++) {
- const itemClone = children[i].cloneNode(true);
- tempList.appendChild(itemClone);
- const fragHeight = measureFragment(tempList);
- if (fragHeight <= remaining) {
- bestCount = i + 1;
- bestHeight = fragHeight;
- } else {
- // Remove the last item
- tempList.removeChild(itemClone);
- break;
- }
- }
-
- if (bestCount === 0) {
- return { first: null, rest: el, firstHeight: 0 };
- }
-
- // Build first fragment (with exactly bestCount items)
- const first = el.cloneNode(false);
- for (let i = 0; i < bestCount; i++) {
- first.appendChild(children[i].cloneNode(true));
- }
-
- // Build rest fragment
- const rest = el.cloneNode(false);
- for (let i = bestCount; i < children.length; i++) {
- rest.appendChild(children[i].cloneNode(true));
- }
-
- // Explicitly inject the starting index for ordered lists
- if (el.tagName === 'OL') {
- const currentStart = parseInt(el.getAttribute('start'), 10) || 1;
- rest.setAttribute('start', currentStart + bestCount);
- }
-
- // Forward split info
- rest._splitInfo = {
- type: 'list',
- itemHeights: info.itemHeights,
- overhead: info.overhead,
- offset: start + bestCount
- };
-
- return { first, rest, firstHeight: bestHeight };
- };
- }
-
- function makeTableSplitter(el, info) {
- const thead = el.querySelector('thead');
- const createShell = () => {
- const shell = el.cloneNode(false);
- if (thead) {
- shell.appendChild(thead.cloneNode(true));
- }
- const newTbody = document.createElement('tbody');
- shell.appendChild(newTbody);
- return shell;
- };
-
- return (remaining) => {
- const tbody = el.querySelector('tbody');
- const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows);
- const start = info.offset;
- const relevantRows = rows.slice(start, start + rows.length);
-
- let bestCount = 0;
- let bestHeight = 0;
- const tempTable = createShell();
- const tempBody = tempTable.querySelector('tbody');
- for (let i = 0; i < relevantRows.length; i++) {
- tempBody.appendChild(relevantRows[i].cloneNode(true));
- const h = measureFragment(tempTable);
- if (h <= remaining) {
- bestCount = i + 1;
- bestHeight = h;
- } else {
- // Remove the last row
- tempBody.removeChild(tempBody.lastChild);
- break;
- }
- }
-
- if (bestCount === 0) {
- return { first: null, rest: el, firstHeight: 0 };
- }
-
- const first = createShell();
- const firstBody = first.querySelector('tbody');
- for (let i = 0; i < bestCount; i++) {
- firstBody.appendChild(relevantRows[i].cloneNode(true));
- }
-
- const rest = createShell();
- const restBody = rest.querySelector('tbody');
- for (let i = bestCount; i < relevantRows.length; i++) {
- restBody.appendChild(relevantRows[i].cloneNode(true));
- }
-
- rest._splitInfo = {
- type: 'table',
- rowHeights: info.rowHeights,
- overhead: info.overhead,
- theadHeight: info.theadHeight,
- offset: start + bestCount
- };
-
- return { first, rest, firstHeight: bestHeight };
- };
- }
-
- // ---------- main pagination loop ----------
- let article_index = 0;
- while (article_index < article_seq.length) {
- const article = article_seq[article_index];
-
- const raw_element_seq = Array.from(article.children).filter(el =>
- !['SCRIPT', 'STYLE', 'RT-PAGE'].includes(el.tagName)
- );
-
- if (raw_element_seq.length === 0) {
- article_index++;
- continue;
- }
-
- const page_seq = [];
- let current_batch_seq = [];
- let current_h = 0;
-
- let i = 0;
- while (i < raw_element_seq.length) {
- const el = raw_element_seq[i];
- const splitter = isSplittable(el);
-
- // --- Splittable element ---
- if (splitter) {
- const remaining = page_height_limit - current_h;
- const { first, rest, firstHeight } = splitter(remaining);
-
- if (first) {
- // Place the fitting fragment
- current_batch_seq.push(first);
- current_h += firstHeight; // exact measured height
-
- // Replace original with remainder
- raw_element_seq.splice(i, 1, rest);
- // Do not increment i - rest will be processed next
- } else {
- // Not even one item fits on this page
- if (current_batch_seq.length === 0) {
- // Empty page -> wrap whole element in a scroll frame
- const frame = document.createElement('rt-scroll-frame');
- frame.style.display = 'block';
- frame.style.overflowY = 'auto';
- frame.style.maxHeight = page_height_limit + 'px';
- frame.appendChild(el);
- current_batch_seq.push(frame);
- i++; // element consumed
- } else {
- // Page has content -> start a new page and keep rest for later
- page_seq.push(current_batch_seq);
- current_batch_seq = [];
- current_h = 0;
- raw_element_seq[i] = rest;
- }
- }
- continue;
- }
-
- // --- Ordinary (non-splittable) element ---
- const h = get_el_height(el);
-
- if (current_h + h > page_height_limit && current_batch_seq.length > 0) {
- // Backtrack widowed headings
- let backtrack_seq = [];
- let backtrack_h = 0;
- while (current_batch_seq.length > 0) {
- const last = current_batch_seq[current_batch_seq.length - 1];
- if (!/^H[1-6]/.test(last.tagName)) break;
- const popped = current_batch_seq.pop();
- backtrack_seq.unshift(popped);
- backtrack_h += get_el_height(popped);
- }
-
- if (current_batch_seq.length > 0) {
- page_seq.push(current_batch_seq);
- current_batch_seq = backtrack_seq;
- current_h = backtrack_h;
- } else {
- page_seq.push(backtrack_seq);
- current_batch_seq = [];
- current_h = 0;
- }
- }
-
- current_batch_seq.push(el);
- current_h += h;
- i++;
- }
-
- if (current_batch_seq.length > 0) {
- page_seq.push(current_batch_seq);
- }
-
- // Rebuild article with <rt-page> wrappers
- article.innerHTML = '';
- let p = 0;
- while (p < page_seq.length) {
- const batch = page_seq[p];
- const page_el = document.createElement('rt-page');
- page_el.id = `page-${p + 1}`;
- batch.forEach(item => page_el.appendChild(item));
- article.appendChild(page_el);
- p++;
- }
-
- if (RT.debug) {
- RT.debug.log('pagination', `Article paginated into ${page_seq.length} pages.`);
- }
-
- article_index++;
- }
-
- // Clean up measurement container
- if (measureContainer && measureContainer.parentNode) {
- measureContainer.remove();
- measureContainer = null;
- }
-};
+++ /dev/null
-/*
- 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);
- }
- };
-
-} )();
+++ /dev/null
-/*
- 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);
- }
- };
-} )();
+++ /dev/null
-/*
- 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);
- }
- };
-
-} )();