Only destover for first draw to screen
diff --git a/sparse_strips/vello_hybrid/src/render/webgl.rs b/sparse_strips/vello_hybrid/src/render/webgl.rs
index f70a358..2ef18c0 100644
--- a/sparse_strips/vello_hybrid/src/render/webgl.rs
+++ b/sparse_strips/vello_hybrid/src/render/webgl.rs
@@ -313,7 +313,7 @@
             image_cache: &self.image_cache,
             filter_context: &self.filter_context,
             filter_pass_state: &mut self.filter_pass_state,
-            depth_cleared: false,
+            first_surface_pass: true,
         };
         self.scheduler.do_scene(
             &mut self.scheduler_state,
@@ -2004,8 +2004,9 @@
     image_cache: &'a ImageCache,
     filter_context: &'a FilterContext,
     filter_pass_state: &'a mut FilterPassState,
-    /// Whether the surface depth buffer has been cleared this frame.
-    depth_cleared: bool,
+    /// `true` until the first surface draw completes. Only the first surface
+    /// draw uses dest-over + depth; subsequent ones use src-over.
+    first_surface_pass: bool,
 }
 
 impl WebGlRendererContext<'_> {
@@ -2019,7 +2020,20 @@
         if strips.is_empty() {
             return;
         }
-        self.programs.upload_strips(self.gl, strips);
+
+        let is_surface = matches!(
+            target,
+            StripPassRenderTarget::Output(OutputTarget::FinalView)
+        );
+        let will_use_dest_over = is_surface && self.first_surface_pass;
+
+        if will_use_dest_over {
+            let mut reversed = strips.to_vec();
+            reversed.reverse();
+            self.programs.upload_strips(self.gl, &reversed);
+        } else {
+            self.programs.upload_strips(self.gl, strips);
+        }
 
         match &target {
             StripPassRenderTarget::Output(OutputTarget::IntermediateTexture(layer_id)) => {
@@ -2132,13 +2146,14 @@
             }
         }
 
-        let is_surface = matches!(
-            target,
-            StripPassRenderTarget::Output(OutputTarget::FinalView)
-        );
-
-        // Surface pass: dest-over blend + depth testing (front-to-back).
+        let use_dest_over = will_use_dest_over;
         if is_surface {
+            self.first_surface_pass = false;
+        }
+
+        // First surface pass: dest-over blend + depth (front-to-back).
+        // Subsequent surface passes: src-over (content goes on top).
+        if use_dest_over {
             self.gl.enable(WebGl2RenderingContext::DEPTH_TEST);
             self.gl.depth_func(WebGl2RenderingContext::LEQUAL);
             self.gl.depth_mask(true);
@@ -2153,9 +2168,7 @@
             self.gl.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT);
         }
 
-        // Clear depth on first surface pass of the frame.
-        if is_surface && !self.depth_cleared {
-            self.depth_cleared = true;
+        if use_dest_over {
             self.gl.clear_depth(1.0);
             self.gl
                 .clear(WebGl2RenderingContext::DEPTH_BUFFER_BIT);
@@ -2230,8 +2243,8 @@
             strips.len() as i32,
         );
 
-        // Restore src-over + no depth for subsequent slot/intermediate passes.
-        if is_surface {
+        // Restore src-over + no depth after dest-over surface pass.
+        if use_dest_over {
             self.gl.disable(WebGl2RenderingContext::DEPTH_TEST);
             self.gl.blend_func(
                 WebGl2RenderingContext::ONE,
diff --git a/sparse_strips/vello_hybrid/src/render/wgpu.rs b/sparse_strips/vello_hybrid/src/render/wgpu.rs
index 8d18983..d3282d6 100644
--- a/sparse_strips/vello_hybrid/src/render/wgpu.rs
+++ b/sparse_strips/vello_hybrid/src/render/wgpu.rs
@@ -371,7 +371,7 @@
             image_cache: &self.image_cache,
             filter_context: &self.filter_context,
             filter_pass_state: &mut self.filter_pass_state,
-            depth_cleared: false,
+            first_surface_pass: true,
         };
         self.scheduler.do_scene(
             &mut self.scheduler_state,
@@ -2336,10 +2336,11 @@
     image_cache: &'a ImageCache,
     filter_context: &'a FilterContext,
     filter_pass_state: &'a mut FilterPassState,
-    /// Whether the depth buffer has been cleared this frame. Reset to `false`
-    /// at the start of each `render_scene`; set to `true` after the first
-    /// surface pass clears depth to 1.0.
-    depth_cleared: bool,
+    /// `true` until the first surface draw completes. The first surface draw
+    /// uses dest-over + depth (front-to-back, reversed strips). Subsequent
+    /// surface draws use src-over so that later-round content composites on
+    /// top of earlier rounds.
+    first_surface_pass: bool,
 }
 
 impl RendererContext<'_> {
@@ -2353,9 +2354,32 @@
         if strips.is_empty() {
             return;
         }
+        let use_dest_over = matches!(target, StripPassRenderTarget::Output(OutputTarget::FinalView))
+            && self.first_surface_pass;
+
+        // For the first surface pass, reverse strips for front-to-back
+        // dest-over rendering. Subsequent surface passes and all slot passes
+        // keep original back-to-front order with src-over.
+        let reversed;
+        let upload_strips = if use_dest_over {
+            reversed = {
+                let mut v = strips.to_vec();
+                v.reverse();
+                v
+            };
+            &reversed[..]
+        } else {
+            strips
+        };
+
+        if matches!(target, StripPassRenderTarget::Output(OutputTarget::FinalView)) {
+            self.first_surface_pass = false;
+        }
+
         // TODO: We currently allocate a new strips buffer for each render pass. A more efficient
         // approach would be to re-use buffers or slices of a larger buffer.
-        self.programs.upload_strips(self.device, self.queue, strips);
+        self.programs
+            .upload_strips(self.device, self.queue, upload_strips);
 
         enum MaybeOwned<'a, T> {
             Borrowed(&'a T),
@@ -2469,13 +2493,11 @@
 
         let (depth_view, depth_load) = match target {
             StripPassRenderTarget::Output(OutputTarget::FinalView) => {
-                let load = if self.depth_cleared {
-                    wgpu::LoadOp::Load
-                } else {
-                    self.depth_cleared = true;
-                    wgpu::LoadOp::Clear(1.0)
-                };
-                (&self.programs.resources.depth_texture_view, load)
+                // Always clear depth for each surface pass. Round boundaries
+                // are determined by clip/blend dependency resolution, not by
+                // scene depth, so preserving depth across rounds would
+                // incorrectly cull content from later rounds.
+                (&self.programs.resources.depth_texture_view, wgpu::LoadOp::Clear(1.0))
             }
             StripPassRenderTarget::SlotTexture(_) => (
                 &self.programs.resources.slot_depth_texture_view,
@@ -2501,14 +2523,15 @@
             stencil_ops: None,
         });
 
-        let pipeline = match target {
-            StripPassRenderTarget::Output(OutputTarget::FinalView) => {
-                &self.programs.strip_pipeline_dest_over
+        let pipeline = if use_dest_over {
+            &self.programs.strip_pipeline_dest_over
+        } else {
+            match target {
+                StripPassRenderTarget::Output(OutputTarget::IntermediateTexture(_)) => {
+                    &self.programs.strip_pipelines_src_over[1]
+                }
+                _ => &self.programs.strip_pipelines_src_over[0],
             }
-            StripPassRenderTarget::Output(OutputTarget::IntermediateTexture(_)) => {
-                &self.programs.strip_pipelines_src_over[1]
-            }
-            StripPassRenderTarget::SlotTexture(_) => &self.programs.strip_pipelines_src_over[0],
         };
 
         let mut render_pass = self.encoder.begin_render_pass(&RenderPassDescriptor {
diff --git a/sparse_strips/vello_hybrid/src/schedule.rs b/sparse_strips/vello_hybrid/src/schedule.rs
index 6b12444..6875b96 100644
--- a/sparse_strips/vello_hybrid/src/schedule.rs
+++ b/sparse_strips/vello_hybrid/src/schedule.rs
@@ -858,8 +858,8 @@
     ///
     /// The rounds queue must not be empty.
     fn flush<R: RendererBackend>(&mut self, renderer: &mut R) {
-        let mut round = self.rounds_queue.pop_front().unwrap();
-        for (i, draw) in round.draws.iter_mut().enumerate() {
+        let round = self.rounds_queue.pop_front().unwrap();
+        for (i, draw) in round.draws.iter().enumerate() {
             #[cfg(debug_assertions)]
             {
                 // This is an expensive O(n²) debug only check that enforces that there are no
@@ -905,16 +905,6 @@
                 continue;
             }
 
-            // Reverse the surface draw (i == 2) for front-to-back ordering.
-            // The scheduler appends strips in scene traversal order
-            // (back-to-front). Reversing gives front-to-back, which is
-            // required for the dest-over blending + depth buffer strategy on
-            // the surface pass. Slot texture draws (i == 0, 1) keep their
-            // original order with src-over blending.
-            if i == 2 {
-                draw.0.reverse();
-            }
-
             renderer.render_strips(&draw.0, target, load);
         }
         for i in 0..2 {