splittable counter scopes
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Wed, 5 Aug 2026 13:19:52 +0000 (13:19 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Wed, 5 Aug 2026 13:19:52 +0000 (13:19 +0000)
developer/authored/Manuscript.copy/Document/manual.html
developer/authored/Manuscript.copy/Layout/counter.js
developer/authored/Manuscript.copy/Layout/paginate.js
developer/experiment/RT-Manuscript_locator.js [new file with mode: 0644]
tester/authored/Counter/test_3.html [new file with mode: 0644]
tester/authored/Counter/test_4.html [new file with mode: 0644]

index 8e9a762..3ff0311 100644 (file)
@@ -49,7 +49,7 @@
         </p>
 
         <p>
-          For RT-Style to work, the document will need to include a file that points it at the library, as discussed later in this manual.
+          For RT-Style to work, the document will need to include a file that points it at the library, as discussed in the <RT·Note·read key="env-setup" field="content"></RT·Note·read> section on page <RT·Note·read key="env-setup" field="page"></RT·Note·read>.
         </p>
 
         <p>
@@ -82,7 +82,7 @@
       </RT·section>
 
       <RT·section>
-        <RT·name>Article Environment</RT·name>
+        <RT·name><RT·Note·write key="env-setup">Article Environment</RT·Note·write></RT·name>
         <p>The standard operational header template for an article instance:</p>
 
         <RT·code>
             <RT·entry key="&lt;RT·Counter·make&gt;">
               Initializes the named counter state machine.<br>
               <div class="attr-list">
+
                 <br><strong>Attributes:</strong><br>
+
                 <code>counter</code>: Required state identifier.<br>
-                <code>style</code>: Single style string, or comma-separated hierarchy defining formats at each nesting depth. The terminal format applies to all deeper nestings. Valid arguments: "NaturalNumber", "CountingNumber", "Roman", "roman", "Alpha", "alpha". The "outline" flag translates to a standard mixed document array. (Default: "NaturalNumber")<br>
-                <code>on-first-step</code>: The initial base value. (Default: "0")<br>
-                <code>separator</code>: String appended between depth sequence levels. (Default: ".")<br>
-                <code>separator-placement</code>: "embedded" or "embedded-after". (Default: "embedded")<br>
-                <code>mode</code>: "scoped" (content embedded between count boundaries receives the parent scope's value) or "milestone" (state carries forward sequentially irrespective of lexical depth).
+
+                <br><code>style</code>: Single style string, or comma-separated hierarchy defining formats at each nesting depth. The terminal format applies to all deeper nestings. Valid arguments: "NaturalNumber", "CountingNumber", "Roman", "roman", "Alpha", "alpha". The "outline" flag translates to a standard mixed document array. (Default: "NaturalNumber")<br>
+
+                <br><code>on-first-step</code>: The value returned the first time the counter is stepped. The default is style specific: "NaturalNumber"(0), "CountingNumber"(1), "Roman"(I), "roman"(i), "Alpha"(A), "alpha"(a).<br>
+
+                <br><code>separator</code>: String appended between depth sequence levels. (Default: ".")<br>
+
+                <br><code>separator-placement</code>: "embedded" or "embedded-after". (Default: "embedded")<br>
+
+                <br><code>mode</code>: "scoped" (content embedded between count boundaries receives the parent scope's value) or "milestone" (state carries forward sequentially irrespective of lexical depth).
+
               </div>
             </RT·entry>
             <RT·entry key="&lt;RT·Counter·step&gt;">
               <div class="attr-list">
                 <br><strong>Attributes:</strong><br>
                 <code>snapshot</code>: Required dictionary assignment key.<br>
-                <code>key</code>: Sub-state query property. Resolves dot-notation parameters (e.g., "count.status", "count.list"). Querying "count" triggers the style formatter and separator join parameters. (Default: "count")
+                <code>key</code>: Sub-state query property. Resolves dot-notation parameters (e.g., "count.status", "count.list"). Querying "count" triggers the style formatter and separator join parameters. (Default: "count"). Reading an empty counter (before a first step) causes an error to the console.
               </div>
             </RT·entry>
           </RT·dictionary>
index 7c9562d..270fb7c 100644 (file)
@@ -1,7 +1,7 @@
 /*
   Processes <RT·counter·*> tags.
   Calculates numbering, maintains the explicit status machine, manages snapshots, and outputs values for read tags.
-  Supports two modes: 'scoped' (default) and 'milestone'.
+  Supports 'scoped' and 'milestone' modes. Includes DOM continuation suspension architecture.
 */
 
 (function() {
@@ -18,7 +18,8 @@
   RT.Counter = RT.Counter || {};
   RT.dict_instance = RT.dict_instance || {};
   RT.dict_snapshot = RT.dict_snapshot || {};
-
+  RT.dict_serial = RT.dict_serial || {};
+  RT.serial_id_allocator = RT.serial_id_allocator || 1;
 
   class Count {
     constructor() {
@@ -45,7 +46,6 @@
       }
     }
 
-
     read(...path) {
       if (path.length === 0) return undefined;
       const key = path[0];
       if (this.list && this.list.length > 0) {
         const val = this.list.pop();
         if (this.list.length === 0) {
-            this.list = null; // Revert to strict null state if emptied
+            this.list = null; 
         }
         return val;
       }
       c.list = this.list ? [...this.list] : null;
       return c;
     }
-
   }
 
   class CounterMachine {
       this.style = ['NaturalNumber']; 
       this.separator = '.';
       this.separator_placement = 'embedded';
-      this.mode = 'scoped'; // 'scoped', 'milestone'
+      this.mode = 'scoped';
 
       if (config) {
         this.write(config);
           }
           this.style = parsed;
         } else if (key === 'Count' || key === 'count') {
-          // Support copying from another CounterMachine or Count object
           const source_count = value instanceof CounterMachine ? value.count : (value instanceof Count ? value : null);
           if (source_count) {
             this.count = source_count.clone();
       const current_status = this.count.read('status');
       
       if (current_status === 'empty') {
-        // Transition state strictly before mutating the list
         this.count.write('status', 'preamble');
         this.count.push(first_step_val !== undefined ? first_step_val : 0);
       } else if (current_status === 'preamble') {
-        this.count.push(0); // indent appends 0
+        this.count.push(0); 
         this.count.write('status', 'preamble');
       } else if (current_status === 'between') {
         this.count.increment();
       if (!count_obj) return '';
       
       const status = count_obj.read('status');
-      if (status === 'empty') return '';
+      if (status === 'empty') {
+          console.error("RT-Manuscript Layout Error: Attempted to output an uninitialized empty counter.");
+          return '[Empty Counter]';
+      }
       
       let active_list;
       if (this.mode === 'scoped' && status === 'between') {
         active_list = count_obj.read('list');
       }
       
-      // Safety check catches null or empty arrays
       if (!active_list || active_list.length === 0) {
         return '';
       }
       return count_str;
     }
 
-    // --- Atomic Type Conversions ---
-
     to_NaturalNumber(num) { return num.toString(); }
     from_NaturalNumber(val) { 
       const n = parseInt(val, 10);
     from_roman(val) { return this.from_Roman(val.toUpperCase()); }
 
     to_Roman(num) {
-      let n = num + 1; // 0-indexed to 1-indexed
+      let n = num + 1; 
       if (n < 1) return n.toString();
       const lookup = {M:1000, CM:900, D:500, CD:400, C:100, XC:90, L:50, XL:40, X:10, IX:9, V:5, IV:4, I:1};
       let roman = '';
           i++;
         }
       }
-      return Math.max(0, num - 1); // 1-indexed to 0-indexed
+      return Math.max(0, num - 1); 
     }
 
     to_Alpha(num) { return String.fromCharCode(65 + num); }
       if (tag === 'rt·counter·make') {
         const name = node.getAttribute('counter');
         if (name) {
-          const style_attr = node.getAttribute('style');
-          const parsed_style = style_attr ? style_attr.split(',').map(s => s.trim()) : ['NaturalNumber'];
+          const continues_id = node.getAttribute('continues');
           
-          RT.dict_instance[name] = new CounterMachine({
-            style: parsed_style,
-            separator: node.getAttribute('separator') || '.',
-            separator_placement: node.getAttribute('separator-placement') || 'embedded',
-            mode: node.getAttribute('mode') || 'scoped'
-          });
-
-          const on_first_step_str = node.getAttribute('on-first-step');
-          if (on_first_step_str) {
-            const top_style = RT.dict_instance[name].style[0];
-            const method_name = `from_${top_style}`;
-            const active_machine = RT.dict_instance[name];
-            const initial_val = typeof active_machine[method_name] === 'function' 
-              ? active_machine[method_name](on_first_step_str) 
-              : active_machine.from_NaturalNumber(on_first_step_str);
-              
-            active_machine.first_step_val = initial_val;
+          if (continues_id && RT.dict_serial[continues_id]) {
+            RT.dict_instance[name] = RT.dict_serial[continues_id].clone();
+          } else {
+            const style_attr = node.getAttribute('style');
+            const parsed_style = style_attr ? style_attr.split(',').map(s => s.trim()) : ['NaturalNumber'];
+            
+            RT.dict_instance[name] = new CounterMachine({
+              style: parsed_style,
+              separator: node.getAttribute('separator') || '.',
+              separator_placement: node.getAttribute('separator-placement') || 'embedded',
+              mode: node.getAttribute('mode') || 'scoped'
+            });
+
+            const on_first_step_str = node.getAttribute('on-first-step');
+            if (on_first_step_str) {
+              const top_style = RT.dict_instance[name].style[0];
+              const method_name = `from_${top_style}`;
+              const active_machine = RT.dict_instance[name];
+              const initial_val = typeof active_machine[method_name] === 'function' 
+                ? active_machine[method_name](on_first_step_str) 
+                : active_machine.from_NaturalNumber(on_first_step_str);
+                
+              active_machine.first_step_val = initial_val;
+            }
           }
+
+          const serial = node.getAttribute('serial') || String(RT.serial_id_allocator++);
+          node.setAttribute('serial', serial);
+          RT.dict_serial[serial] = RT.dict_instance[name];
         }
       } else if (tag === 'rt·counter·step') {
         const name = node.getAttribute('counter');
+        const is_continuation = node.getAttribute('continuation') === 'true';
+
         if (name && RT.dict_instance[name]) {
           const active_machine = RT.dict_instance[name];
-          active_machine.enter(active_machine.first_step_val);
-          active_machine.first_step_val = undefined; // consume it
+          if (!is_continuation) {
+            active_machine.enter(active_machine.first_step_val);
+            active_machine.first_step_val = undefined; 
+          }
           machine_to_exit = active_machine;
         }
       } else if (tag === 'rt·counter·snapshot') {
       }
 
       if (machine_to_exit) {
-        machine_to_exit.exit();
+        const is_continued = node.getAttribute('continued') === 'true';
+        if (!is_continued) {
+          machine_to_exit.exit();
+        } else {
+          // Cache the suspended state dynamically via the paginator's injected ID
+          const split_id = node.getAttribute('split-id');
+          if (split_id) {
+            RT.dict_serial[split_id] = machine_to_exit.clone();
+          }
+        }
       }
     }
 
     }
   };
 
-  //------------------------------------------
-  // on module load
-  //
-
   window.RT.counter = counter;
 
 })();
index fd4d564..8f105cf 100644 (file)
     return h;
   }
 
-// =========================================================
+  // =========================================================
   // Splitting Logic
   // =========================================================
   function isSplittable(el){
+
     // Component Dictionary Execution
     const componentId = el.getAttribute('data-rt-component');
     if (componentId && window.RT.Component && window.RT.Component[componentId] && window.RT.Component[componentId].split) {
       return (remaining) => window.RT.Component[componentId].split(el, remaining, measureFragment);
     }
 
+    // Custom RT splitable attribute delegation
+    if (el.hasAttribute('splitable') && window.RT.Splitter && window.RT.Splitter[el.tagName.toLowerCase()]) {
+      return (remaining) => window.RT.Splitter[el.tagName.toLowerCase()](el, remaining, measureFragment, isSplittable);
+    }
+
     // Native HTML Fallbacks
+
     const tag = el.tagName;
     if(tag === 'UL' || tag === 'OL'){
       const items = Array.from(el.children).filter(c => c.tagName === 'LI');
   }
 
 
+  // =========================================================
+  // RT ELEMENT SPLITTERS
+  // =========================================================
+  window.RT.Splitter = window.RT.Splitter || {};
+
+  window.RT.Splitter['rt·counter·step'] = function(el, remaining, measureFn, isSplittableFn) {
+    const children = Array.from(el.children);
+    let bestCount = 0;
+    let bestHeight = 0;
+    const tempContainer = el.cloneNode(false);
+    let splitChildResult = null;
+    let forcedBreak = false;
+
+    for (let i = 0; i < children.length; i++) {
+      const child = children[i];
+
+      // Break on explicit splitting break
+      if (child.tagName && child.tagName.toLowerCase() === 'rt·page-break') {
+        forcedBreak = true;
+        bestCount = i;
+        break;
+      }
+
+      tempContainer.appendChild(child.cloneNode(true));
+      const fragHeight = measureFn(tempContainer);
+
+      if (fragHeight <= remaining) {
+        bestCount = i + 1;
+        bestHeight = fragHeight;
+      } else {
+        tempContainer.removeChild(tempContainer.lastChild);
+        const childSplitter = isSplittableFn(child);
+        if (childSplitter) {
+          const childSplit = childSplitter(remaining - bestHeight);
+          if (childSplit && childSplit.first) {
+            splitChildResult = childSplit;
+            bestHeight += childSplit.firstHeight;
+            bestCount = i;
+          }
+        }
+        break;
+      }
+    }
+
+    if (bestCount === 0 && !splitChildResult && !forcedBreak) {
+      return { first: null, rest: el, firstHeight: 0 };
+    }
+
+    const first = el.cloneNode(false);
+    first.setAttribute('continued', 'true');
+    const splitId = 'split_' + Math.random().toString(36).substr(2, 9);
+    first.setAttribute('split-id', splitId);
+    
+    for (let i = 0; i < bestCount; i++) {
+      first.appendChild(children[i].cloneNode(true));
+    }
+    if (splitChildResult) first.appendChild(splitChildResult.first);
+
+    let rest = null;
+    if (bestCount < children.length || splitChildResult || forcedBreak) {
+      rest = el.cloneNode(false);
+      rest.setAttribute('continuation', 'true');
+      if (splitChildResult && splitChildResult.rest) rest.appendChild(splitChildResult.rest);
+
+      const startIndex = forcedBreak ? bestCount + 1 : (splitChildResult ? bestCount + 1 : bestCount);
+      for (let i = startIndex; i < children.length; i++) {
+        rest.appendChild(children[i].cloneNode(true));
+      }
+
+      const makeTag = document.createElement('rt·counter·make');
+      makeTag.setAttribute('counter', el.getAttribute('counter'));
+      makeTag.setAttribute('continues', splitId); 
+
+      rest = [makeTag, rest];
+    }
+
+    return { first, rest, firstHeight: bestHeight };
+  };
+
   // =========================================================
   // PAGINATE 0: CHUNKING & INJECTING STRUCTURE
   // =========================================================
             current_h += firstHeight;
 
             if(rest){
-              raw_element_seq.splice(i ,1 ,rest);
+              if (Array.isArray(rest)) {
+                raw_element_seq.splice(i, 1, ...rest);
+              } else {
+                raw_element_seq.splice(i, 1, rest);
+              }
+              // Force page boundary push because element spanned boundary
+              page_seq.push(current_batch_seq);
+              current_batch_seq = [];
+              current_h = 0;
+              continue; 
             } else {
-              raw_element_seq.splice(i ,1);
+              raw_element_seq.splice(i, 1);
+              continue; 
             }
           } else {
             if(current_batch_seq.length === 0){
 
         const h = getElHeight(el);
         const is_RT_page_break = el.tagName && el.tagName.toLowerCase() === 'rt·page-break';
+        const is_RT_page_break_primitive = el.tagName && el.tagName.toLowerCase() === 'rt·page-break-primitive';
 
         // Explicit Page Break Logic - Execute immediately without backward traversal
-        if(is_RT_page_break){
+        if(is_RT_page_break || is_RT_page_break_primitive){
           if(current_batch_seq.length > 0){
             page_seq.push(current_batch_seq);
             current_batch_seq = [];
diff --git a/developer/experiment/RT-Manuscript_locator.js b/developer/experiment/RT-Manuscript_locator.js
new file mode 100644 (file)
index 0000000..4a1b936
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  direct.js
+
+
+  We have four scenarios
+
+  immediate - used in the RT-style distribution itself (authored, consummer, staged)
+  direct - used in the RT-style project itself, but not in the distribution
+  indirect - the version all Harmony projects use
+  URL_only - always pulls style through a URL, a webserver must be present
+  
+*/
+
+window.RT = window.RT || {};
+
+(function() {
+  const project_name = "RT-Style"; 
+  const path = window.location.pathname;
+  const project_root_index = path.indexOf('/' + project_name + '/');
+  
+  if (project_root_index !== -1) {
+    // substring(0, x) excludes the trailing slash. We must prepend it to the payload.
+    const absolute_project_root = path.substring(0, project_root_index + project_name.length + 1);
+    window.RT.dirpr_library = absolute_project_root + "/consumer/Manuscript";
+  } else {
+    // Fallback for when served via local Python HTTP daemon from the project root
+    window.RT.dirpr_library = "../consumer/made/Manuscript";
+  }
+  
+  document.write(
+      '<script src="'
+      + window.RT.dirpr_library
+      + '/Core/RT-Manuscript_make.js"'
+      + '><\/script>'
+  );
+
+})();
diff --git a/tester/authored/Counter/test_3.html b/tester/authored/Counter/test_3.html
new file mode 100644 (file)
index 0000000..2090867
--- /dev/null
@@ -0,0 +1,107 @@
+<!-- 
+counter splits with continuations
+uses manual primitive page breaks and hard coded splits and continuations
+-->
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <title>Counter 3-Page Continuation Test</title>
+    <script src="RT-Manuscript_locator.js"></script>
+    <script>
+      window.RT.theme_preference('inverse_wheat');
+      window.RT.load('Layout/paginate');
+      window.RT.load('Layout/article_tech_ref');
+    </script>
+  </head>
+  <body>
+    <RT·theme-selector></RT·theme-selector>
+    <RT·article>
+
+      <!-- PAGE 1: Initial Scope Generation -->
+      <h1>Page 1: Initial Scope</h1>
+      <p>The state machine initializes. Scopes 1, 3, and 4 breach the page boundary and are suspended (<code>continued="true"</code>).</p>
+
+      <RT·counter·make counter="C" serial="1" style="outline" on-first-step="1"></RT·counter·make>
+
+      <RT·counter·step counter="C" continued="true"> <!-- Node 1: I -->
+        <RT·counter·snapshot counter="C" snapshot="n1"></RT·counter·snapshot>
+        <p>Node 1 execution: <strong><RT·counter·read snapshot="n1"></RT·counter·read></strong> (Expected: <strong>I</strong>)</p>
+
+        <RT·counter·step counter="C"> <!-- Node 2: I.A -->
+          <RT·counter·snapshot counter="C" snapshot="n2"></RT·counter·snapshot>
+          <p style="margin-left: 2rem;">Node 2 execution: <strong><RT·counter·read snapshot="n2"></RT·counter·read></strong> (Expected: <strong>I.A</strong>) - <em>Closes normally</em></p>
+        </RT·counter·step>
+
+        <RT·counter·step counter="C" continued="true"> <!-- Node 3: I.B -->
+          <RT·counter·snapshot counter="C" snapshot="n3"></RT·counter·snapshot>
+          <p style="margin-left: 2rem;">Node 3 execution: <strong><RT·counter·read snapshot="n3"></RT·counter·read></strong> (Expected: <strong>I.B</strong>)</p>
+
+          <RT·counter·step counter="C" continued="true"> <!-- Node 4: I.B.i -->
+            <RT·counter·snapshot counter="C" snapshot="n4"></RT·counter·snapshot>
+            <p style="margin-left: 4rem;">Node 4 execution: <strong><RT·counter·read snapshot="n4"></RT·counter·read></strong> (Expected: <strong>I.B.i</strong>)</p>
+            <p style="margin-left: 4rem; color: #B22222;">--- Page Boundary Reached ---</p>
+          </RT·counter·step>
+        </RT·counter·step>
+      </RT·counter·step>
+
+      <RT·page-break-primitive></RT·page-break-primitive>
+
+      <!-- PAGE 2: First Continuation -->
+      <h1>Page 2: First Continuation</h1>
+      <p>The graph is reassembled. Node 4 closes. Node 5 executes. The page boundary is breached again, forcing a second suspension of the outer scopes 1 and 3.</p>
+
+      <RT·counter·make counter="C" serial="2" continues="1"></RT·counter·make>
+
+      <!-- Node 1 Cont: Suspended again -->
+      <RT·counter·step counter="C" continuation="true" continued="true"> 
+        
+        <!-- Node 3 Cont: Suspended again -->
+        <RT·counter·step counter="C" continuation="true" continued="true"> 
+
+          <!-- Node 4 Cont: Closes -->
+          <RT·counter·step counter="C" continuation="true"> 
+            <RT·counter·snapshot counter="C" snapshot="n4_cont"></RT·counter·snapshot>
+            <p style="margin-left: 4rem;">Node 4 continued payload. Current state: <strong><RT·counter·read snapshot="n4_cont"></RT·counter·read></strong> (Expected: <strong>I.B.i</strong>) - <em>Closes normally</em></p>
+          </RT·counter·step> 
+
+          <RT·counter·step counter="C"> <!-- Node 5: I.B.ii -->
+            <RT·counter·snapshot counter="C" snapshot="n5"></RT·counter·snapshot>
+            <p style="margin-left: 4rem;">Node 5 execution: <strong><RT·counter·read snapshot="n5"></RT·counter·read></strong> (Expected: <strong>I.B.ii</strong>) - <em>Closes normally</em></p>
+            <p style="margin-left: 4rem; color: #B22222;">--- Page Boundary Reached ---</p>
+          </RT·counter·step>
+
+        </RT·counter·step>
+      </RT·counter·step>
+
+      <RT·page-break-primitive></RT·page-break-primitive>
+
+      <!-- PAGE 3: Second Continuation -->
+      <h1>Page 3: Second Continuation</h1>
+      <p>The final graph reassembly. Node 3 closes. Node 6 executes. Node 1 closes.</p>
+
+      <RT·counter·make counter="C" serial="3" continues="2"></RT·counter·make>
+
+      <!-- Node 1 Cont: Closes -->
+      <RT·counter·step counter="C" continuation="true"> 
+
+        <!-- Node 3 Cont: Closes -->
+        <RT·counter·step counter="C" continuation="true"> 
+          <RT·counter·snapshot counter="C" snapshot="n3_cont"></RT·counter·snapshot>
+          <p style="margin-left: 2rem;">Node 3 continued payload. Current state: <strong><RT·counter·read snapshot="n3_cont"></RT·counter·read></strong> (Expected: <strong>I.B</strong>) - <em>Closes normally</em></p>
+        </RT·counter·step> 
+
+        <RT·counter·step counter="C"> <!-- Node 6: I.C -->
+          <RT·counter·snapshot counter="C" snapshot="n6"></RT·counter·snapshot>
+          <p style="margin-left: 2rem;">Node 6 execution: <strong><RT·counter·read snapshot="n6"></RT·counter·read></strong> (Expected: <strong>I.C</strong>) - <em>Closes normally</em></p>
+        </RT·counter·step>
+
+        <RT·counter·snapshot counter="C" snapshot="n1_cont"></RT·counter·snapshot>
+        <p>Node 1 continued payload. Current state: <strong><RT·counter·read snapshot="n1_cont"></RT·counter·read></strong> (Expected: <strong>I</strong>) - <em>Closes normally</em></p>
+
+      </RT·counter·step> 
+
+    </RT·article>
+  </body>
+</html>
diff --git a/tester/authored/Counter/test_4.html b/tester/authored/Counter/test_4.html
new file mode 100644 (file)
index 0000000..ec7bb0d
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <title>Counter Split Continuation Test</title>
+    <script src="RT-Manuscript_locator.js"></script>
+    <script>
+      window.RT.theme_preference('inverse_wheat');
+      window.RT.load('Layout/paginate');
+      window.RT.load('Layout/article_tech_ref');
+    </script>
+  </head>
+  <body>
+    <RT·theme-selector></RT·theme-selector>
+    <RT·article>
+
+      <h1>Page 1: Pre-Split</h1>
+      <p>This counter scope initiates normally and is deliberately severed by an explicit structural split break.</p>
+
+      <RT·counter·make counter="C" style="outline" on-first-step="1"></RT·counter·make>
+
+      <RT·counter·step counter="C" splitable="true"> 
+        <RT·counter·snapshot counter="C" snapshot="n1_pre"></RT·counter·snapshot>
+        <p>Pre-split evaluation: <strong><RT·counter·read snapshot="n1_pre"></RT·counter·read></strong> (Expected: 1)</p>
+
+        <RT·page-break></RT·page-break>
+
+        <h1>Page 2: Post-Split Continuation</h1>
+        <RT·counter·snapshot counter="C" snapshot="n1_post"></RT·counter·snapshot>
+        <p>Post-split evaluation: <strong><RT·counter·read snapshot="n1_post"></RT·counter·read></strong> (Expected: 1)</p>
+        <p>The array extent remains static across the boundary because the continuation flag successfully suppressed the step increment.</p>
+        
+        <RT·counter·step counter="C">
+          <RT·counter·snapshot counter="C" snapshot="n2_nested"></RT·counter·snapshot>
+          <p>Nested step evaluation: <strong><RT·counter·read snapshot="n2_nested"></RT·counter·read></strong> (Expected: 1.A)</p>
+        </RT·counter·step>
+
+      </RT·counter·step>
+
+    </RT·article>
+  </body>
+</html>