--- tsunami_gui_win32_v46_mercator_scale_fix.c
+++ tsunami_gui_win32_v47_auto_subsidence.c
@@ -50,7 +50,7 @@
       Shift+T         Add hovered observation point to multi-station time-series recording
       Y               Save selected observation point(s) time-series CSV + SVG graph
       E               Advanced source-node tune mode: click node, +/- slip with auto uplift, [/ ] delay, arrows move
-      Stamp mode      S toggle, left click stamp, N/Enter finish fault, Tab cycle, Z/X strike, [/ ] delay, J/K length, < > width+length
+      Stamp mode      S toggle, left click stamp, N/Enter finish fault + auto subsidence, G regen subsidence, Tab cycle, Z/X strike, [/ ] delay, J/K length, < > width+length
       Node tune       Ctrl-click toggle, Shift-click add, Shift-drag box select, A all, C/Esc clear, Tab primary/next
       Node tune       PgUp/PgDn slip with auto uplift, F footprint-only, U copy current brush, Del remove selected
       Japanese zone text uses a CJK font to prevent square-box glyphs
@@ -223,7 +223,10 @@
    from its first stamp so later global setting changes do not rewrite already
    painted patches.  v45 adds per-patch plane-following depth: every stamp center is projected
    onto the first stamp's strike/down-dip plane, so down-dip stamp rows naturally get deeper
-   instead of forming repeated shallow "solar panel" strips. */
+   instead of forming repeated shallow "solar panel" strips.
+   v47 adds automatic down-dip subsidence generation for finite-fault stamps.
+   Loading a v46 preset containing only the stamped uplift/footprint nodes now
+   reconstructs the negative subsidence lobe automatically. */
 #define MAX_STAMP_FAULT_GROUPS 128
 typedef struct {
     int id;
@@ -4490,6 +4493,8 @@
     return g;
 }
 
+static int stamp_regenerate_auto_subsidence(HWND hwnd, int reset_after, int show_status);
+
 static void stamp_finish_current_fault(void) {
     StampFaultGroup *g = stamp_current_group();
     if (!g) {
@@ -4497,9 +4502,12 @@
         return;
     }
     g->completed = 1;
-    set_status("Stamp fault #%d completed: %d patch(es), delay %ds, strike %.0f deg, dip %.0f deg, depth %.1f km. Next click starts a new fault.",
-               g->id, g->stamp_count, g->delay_s, g->strike_deg, g->dip_deg, g->top_depth_km);
     g_current_stamp_fault = -1;
+    {
+        int auto_cells = stamp_regenerate_auto_subsidence(NULL, 1, 0);
+        set_status("Stamp fault #%d completed: %d patch(es), delay %ds, strike %.0f deg, dip %.0f deg, depth %.1f km. Auto subsidence regenerated: %d cell(s). Next click starts a new fault.",
+                   g->id, g->stamp_count, g->delay_s, g->strike_deg, g->dip_deg, g->top_depth_km, auto_cells);
+    }
 }
 
 static void stamp_cycle_fault_group(void) {
@@ -4830,6 +4838,193 @@
     return affected;
 }
 
+
+static StampFaultGroup *stamp_group_by_id(int fault_id) {
+    if (fault_id <= 0) return NULL;
+    for (int i = 0; i < g_stamp_fault_count; ++i) {
+        if (g_stamp_faults[i].id == fault_id) return &g_stamp_faults[i];
+    }
+    return NULL;
+}
+
+static int stamp_source_is_auto_subsidence(const SourceSpec *src) {
+    if (!src) return 0;
+    return (src->fault_id > 0 && src->fault_patch_id < 0 && source_height_is_subsidence(src->height_m));
+}
+
+static int stamp_source_is_direct_rupture_stamp(const SourceSpec *src) {
+    if (!src) return 0;
+    if (src->fault_id <= 0 || src->fault_patch_id <= 0) return 0;
+    return source_node_counts_for_moment_area(src);
+}
+
+static int stamp_remove_auto_subsidence_sources(void) {
+    int removed = 0;
+    for (size_t i = 0; i < g_sources.count; ) {
+        if (stamp_source_is_auto_subsidence(&g_sources.items[i])) {
+            if (i + 1u < g_sources.count) {
+                memmove(&g_sources.items[i], &g_sources.items[i + 1u],
+                        (g_sources.count - i - 1u) * sizeof(SourceSpec));
+            }
+            g_sources.count--;
+            removed++;
+            continue;
+        }
+        i++;
+    }
+    return removed;
+}
+
+static int stamp_regenerate_auto_subsidence(HWND hwnd, int reset_after, int show_status) {
+    (void)hwnd;
+    if (g_grid.width == 0 || g_grid.height == 0) return 0;
+
+    int removed = stamp_remove_auto_subsidence_sources();
+    if (g_stamp_fault_count <= 0) stamp_runtime_sources_max_fault_id();
+
+    const size_t cell_count = (size_t)g_grid.width * (size_t)g_grid.height;
+    float *sub_h = (float *)calloc(cell_count, sizeof(float));
+    uint8_t *occupied = (uint8_t *)calloc(cell_count, 1);
+    int32_t *sub_delay = (int32_t *)malloc(cell_count * sizeof(int32_t));
+    int32_t *sub_fault_id = (int32_t *)calloc(cell_count, sizeof(int32_t));
+    int32_t *sub_patch_id = (int32_t *)calloc(cell_count, sizeof(int32_t));
+    float *sub_strike = (float *)calloc(cell_count, sizeof(float));
+    float *sub_dip = (float *)calloc(cell_count, sizeof(float));
+    float *sub_depth = (float *)calloc(cell_count, sizeof(float));
+    float *sub_width = (float *)calloc(cell_count, sizeof(float));
+    float *sub_length = (float *)calloc(cell_count, sizeof(float));
+
+    if (!sub_h || !occupied || !sub_delay || !sub_fault_id || !sub_patch_id ||
+        !sub_strike || !sub_dip || !sub_depth || !sub_width || !sub_length) {
+        free(sub_h); free(occupied); free(sub_delay); free(sub_fault_id); free(sub_patch_id);
+        free(sub_strike); free(sub_dip); free(sub_depth); free(sub_width); free(sub_length);
+        set_status("Auto subsidence: out of memory; previous generated subsidence removed=%d.", removed);
+        if (reset_after) reset_state_preserve_sources();
+        return 0;
+    }
+    for (size_t i = 0; i < cell_count; ++i) sub_delay[i] = INT_MAX;
+
+    size_t source_count = g_sources.count;
+    int direct_count = 0;
+    for (size_t i = 0; i < source_count; ++i) {
+        const SourceSpec *src = &g_sources.items[i];
+        if (src->grid_x < 0 || src->grid_y < 0 || src->grid_x >= (int)g_grid.width || src->grid_y >= (int)g_grid.height) continue;
+        size_t idx = tsunami_index(&g_grid, (uint32_t)src->grid_x, (uint32_t)src->grid_y);
+        occupied[idx] = 1;
+        if (stamp_source_is_direct_rupture_stamp(src)) direct_count++;
+    }
+
+    for (size_t i = 0; i < source_count; ++i) {
+        const SourceSpec *src = &g_sources.items[i];
+        if (!stamp_source_is_direct_rupture_stamp(src)) continue;
+        if (src->grid_x < 0 || src->grid_y < 0 || src->grid_x >= (int)g_grid.width || src->grid_y >= (int)g_grid.height) continue;
+
+        StampFaultGroup *fg = stamp_group_by_id(src->fault_id);
+        float strike_deg = src->stamp_strike_deg;
+        float dip_deg = source_node_stamp_dip_deg(src);
+        float width_km = (src->stamp_width_km > 0.0f) ? src->stamp_width_km : current_fault_width_km();
+        float length_km = (src->stamp_length_km > 0.0f) ? src->stamp_length_km : g_fault_stamp_length_km;
+        int subsidence_side = (g_subsidence_side < 0) ? -1 : 1;
+        if (fg) {
+            if (fg->strike_deg >= 0.0f && isfinite(fg->strike_deg)) strike_deg = fg->strike_deg;
+            if (fg->dip_deg >= 5.0f && fg->dip_deg <= 60.0f) dip_deg = fg->dip_deg;
+            if (fg->width_km > 0.0f) width_km = fg->width_km;
+            if (fg->length_km > 0.0f) length_km = fg->length_km;
+            subsidence_side = (fg->subsidence_side < 0) ? -1 : 1;
+        }
+
+        float sx, sy, nx, ny;
+        reverse_fault_basis_for(strike_deg, subsidence_side, &sx, &sy, &nx, &ny);
+        (void)sx; (void)sy;
+
+        float km_per_cell = local_ground_km_per_cell_mercator((float)src->grid_y);
+        if (km_per_cell < 0.01f) km_per_cell = 0.01f;
+        float projected_width_km = normalized_fault_width_km(width_km) * fault_dip_cos_deg(dip_deg);
+        float offset_cells = fmaxf(1.5f, 0.65f * projected_width_km / km_per_cell);
+        float half_along = fmaxf(1.5f, 0.22f * normalized_stamp_length_km(length_km) / km_per_cell);
+        float half_across = fmaxf(1.5f, 0.30f * projected_width_km / km_per_cell);
+        int search_r = (int)ceilf(offset_cells + sqrtf(half_along * half_along + half_across * half_across) + 2.0f);
+
+        float base_amp = fabsf(src->height_m);
+        if (base_amp < 0.0005f && src->slip_m > SOURCE_SLIP_HEIGHT_EPS_M) {
+            float dip_rad = dip_deg * TSUNAMI_PI / 180.0f;
+            float reverse_mix = clampf_gui(1.0f - g_strike_slip_mix, 0.0f, 1.0f);
+            base_amp = src->slip_m * sinf(dip_rad) * reverse_mix *
+                       thrust_tsunami_depth_factor_at_km(clampf_gui(src->stamp_depth_km, 0.0f, 700.0f));
+        }
+        if (base_amp < 0.0005f) continue;
+
+        float cx = (float)src->grid_x + nx * offset_cells;
+        float cy = (float)src->grid_y + ny * offset_cells;
+
+        for (int y = (int)floorf(cy - search_r); y <= (int)ceilf(cy + search_r); ++y) {
+            if (y < 0 || y >= (int)g_grid.height) continue;
+            for (int x = (int)floorf(cx - search_r); x <= (int)ceilf(cx + search_r); ++x) {
+                if (x < 0 || x >= (int)g_grid.width) continue;
+                size_t idx = tsunami_index(&g_grid, (uint32_t)x, (uint32_t)y);
+                if (occupied[idx]) continue;
+                if (g_grid.solid[idx]) continue;
+
+                float rx = (float)x - cx;
+                float ry = (float)y - cy;
+                float along = rx * sx + ry * sy;
+                float across = rx * nx + ry * ny;
+                float aa = fabsf(along) / half_along;
+                float ac = fabsf(across) / half_across;
+                if (aa > 1.0f || ac > 1.0f) continue;
+                float w = raised_cosine_weight(aa) * raised_cosine_weight(ac);
+                if (w < 0.02f) continue;
+
+                float candidate = -base_amp * clampf_gui(g_subsidence_ratio, 0.0f, 1.0f) * w;
+                if (candidate < sub_h[idx]) {
+                    sub_h[idx] = candidate;
+                    sub_delay[idx] = normalized_stamp_delay_s(src->delay_s);
+                    sub_fault_id[idx] = src->fault_id;
+                    sub_patch_id[idx] = -abs(src->fault_patch_id > 0 ? src->fault_patch_id : 1);
+                    sub_strike[idx] = normalize_deg_gui(strike_deg);
+                    sub_dip[idx] = dip_deg;
+                    sub_depth[idx] = src->stamp_depth_km;
+                    sub_width[idx] = width_km;
+                    sub_length[idx] = length_km;
+                }
+            }
+        }
+    }
+
+    int added = 0;
+    for (size_t idx = 0; idx < cell_count; ++idx) {
+        if (sub_h[idx] >= -0.0005f) continue;
+        int x = (int)(idx % (size_t)g_grid.width);
+        int y = (int)(idx / (size_t)g_grid.width);
+        int delay = (sub_delay[idx] == INT_MAX) ? g_new_source_delay_s : (int)sub_delay[idx];
+        source_list_append(&g_sources, x, y, sub_h[idx], delay);
+        if (g_sources.count > 0) {
+            SourceSpec *dst = &g_sources.items[g_sources.count - 1];
+            dst->slip_m = 0.0f;
+            dst->fault_id = sub_fault_id[idx];
+            dst->fault_patch_id = sub_patch_id[idx];
+            dst->stamp_strike_deg = sub_strike[idx];
+            dst->stamp_dip_deg = sub_dip[idx];
+            dst->stamp_depth_km = sub_depth[idx];
+            dst->stamp_width_km = sub_width[idx];
+            dst->stamp_length_km = sub_length[idx];
+            dst->moment_area_factor = 0.0f;
+        }
+        added++;
+    }
+
+    free(sub_h); free(occupied); free(sub_delay); free(sub_fault_id); free(sub_patch_id);
+    free(sub_strike); free(sub_dip); free(sub_depth); free(sub_width); free(sub_length);
+
+    sanitize_all_source_node_slips();
+    if (reset_after) reset_state_preserve_sources();
+    if (show_status) {
+        set_status("Auto subsidence regenerated: direct stamp cells=%d, removed old=%d, added=%d. Preset-loaded stamps also use this path.",
+                   direct_count, removed, added);
+    }
+    return added;
+}
+
 static void stamp_adjust_delay(int delta_s) {
     StampFaultGroup *g = stamp_current_group();
     if (g && !g->completed) {
@@ -4930,6 +5125,10 @@
         set_status("Stamp fault mode: next new fault patch length = %.1f km. Open fault groups keep their frozen length.", g_fault_stamp_length_km);
         return 1;
     }
+    case 'G':
+        source_undo_push("regenerate stamp auto subsidence");
+        stamp_regenerate_auto_subsidence(hwnd, 1, 1);
+        return 1;
     }
     return 0;
 }
@@ -8123,6 +8322,7 @@
     else if (strcmp(key, "wave_display_coeff") == 0) g_wave_display_coeff = clampf_gui((float)value, 0.05f, 20.0f);
     else if (strcmp(key, "wave_overlay_alpha") == 0) g_wave_overlay_alpha = clampf_gui((float)value, 0.0f, 1.0f);
     else if (strcmp(key, "fault_stamp_length_km") == 0) g_fault_stamp_length_km = normalized_stamp_length_km((float)value);
+    else if (strcmp(key, "subsidence_side") == 0) g_subsidence_side = ((int)lround(value)) < 0 ? -1 : 1;
     else return 0;
     return 1;
 }
@@ -8153,6 +8353,7 @@
     write_preset_param(fp, "wave_display_coeff", g_wave_display_coeff);
     write_preset_param(fp, "wave_overlay_alpha", g_wave_overlay_alpha);
     write_preset_param(fp, "fault_stamp_length_km", g_fault_stamp_length_km);
+    write_preset_param(fp, "subsidence_side", g_subsidence_side);
 
     fprintf(fp, "SOURCE_HEADER,grid_x,grid_y,height_m,delay_s,slip_m,dip_deg,moment_area_factor,fault_id,patch_id,strike_deg,depth_km,width_km,length_km\n");
     for (size_t i = 0; i < g_sources.count; ++i) {
@@ -8265,6 +8466,7 @@
     source_list_free(&new_sources);
     g_current_stamp_fault = -1;
     stamp_runtime_sources_max_fault_id();
+    stamp_regenerate_auto_subsidence(NULL, 0, 0);
     reset_state_preserve_sources();
     return 1;
 }
@@ -9007,7 +9209,7 @@
         "Y: save selected station graph\n"
         "O: save max-wave PNG\n"
         "S: finite-fault stamp mode on/off, Ctrl+S: save station CSV\n"
-        "Stamp mode: click stamp; N/Enter complete fault; Tab cycle; Z/X strike; [/ ] delay; J/K length; < > width+length\n"
+        "Stamp mode: click stamp; N/Enter complete fault + auto subsidence; G regen subsidence; Tab cycle; Z/X strike; [/ ] delay; J/K length; < > width+length\n"
         "B: selected-station rings\n"
         "Ctrl+D, then B: bathymetry debug map\n"
         "Ctrl+D, then L: land/sea display invert\n"
