#!/usr/bin/env python3
"""molt - round22 variant v2 (medium step).
Reconceives the round21 champion's open turn landing: the inside face's
roll-over lip becomes a bold stepped facet contour (700/800 diamonds
stepped along the field-side edge), and the face's light-to-dim tonal
sweep deepens (300 at the lip -> 700 at the field) so the turn reads as
one rolling volume. The tear, the faceted underside, the fields, and the
rupture are unchanged.
Seeded, deterministic. Writes render.png (1080x1080).
Python + PIL only. Colors are Flexoki swatches, solid fills, no blending."""
import json
import math
import random
from PIL import Image, ImageDraw

SIZE = 1080
SEED = 24
HERE = "/home/hatch/workspace/hillclimb/2026-09-24-molt/round22/v2"


def main():
    pal = json.load(open("/home/hatch/workspace/hillclimb/2026-09-24-molt/flexoki.json"))
    paper = pal["paper"]
    black = pal["black"]
    oranges = [pal["orange"][s] for s in ("400", "500", "600")]

    rng = random.Random(SEED)
    img = Image.new("RGB", (SIZE, SIZE), paper)
    d = ImageDraw.Draw(img)

    # Rupture: a diagonal split from upper-left to lower-right.
    ax, ay, bx, by = -60.0, 330.0, SIZE + 60.0, 760.0
    vx, vy = bx - ax, by - ay
    L = math.hypot(vx, vy)
    nx, ny = -vy / L, vx / L  # unit normal

    N = 26
    spine = [(ax + vx * i / N, ay + vy * i / N) for i in range(N + 1)]
    half = 46.0
    left, right = [], []
    for (x, y) in spine:
        j = rng.uniform(-18, 18)
        w = half + rng.uniform(-12, 12)
        left.append((x + nx * (j + w), y + ny * (j + w)))
        right.append((x + nx * (j - w), y + ny * (j - w)))
    # The dark underneath, revealed where the shell is gone.
    d.polygon(left + right[::-1], fill=black)

    # Thin orange seam: fresh skin lining the split on the +normal side.
    seam = []
    for (x, y) in spine:
        j = rng.uniform(-26, 26)
        w = half + rng.uniform(-18, 18)
        seam.append((x + nx * (j + w - 12), y + ny * (j + w - 12)))
    d.line(seam, fill=oranges[1], width=7)

    def signed_dist(px, py):
        t = (px - ax) * vx + (py - ay) * vy
        t = max(0.0, min(1.0, t / (vx * vx + vy * vy)))
        cx, cy = ax + vx * t, ay + vy * t
        dx, dy = px - cx, py - cy
        return (dx * nx + dy * ny), math.hypot(dx, dy)

    # The two fields differ: -normal side is the intact shell,
    # +normal side (under the orange seam) is the revealed underneath:
    # darker, sparser, and tilted against the shell's grain.
    shell_grays = [pal["base"][s] for s in ("500", "600", "700")]
    under_grays = [pal["base"][s] for s in ("700", "800")]
    UNDER_TILT = math.radians(55)
    UNDER_KEEP = 0.45

    count = 0
    step = 27
    cols = int(SIZE / step) + 1
    for gy in range(cols):
        for gx in range(cols):
            x = gx * step + rng.uniform(-9, 9)
            y = gy * step + rng.uniform(-9, 9)
            sdist, dc = signed_dist(x, y)
            if dc < half + 6:
                continue  # shell gone here; the dark band shows through

            side = 1.0 if sdist >= 0 else -1.0
            underneath = side > 0.0
            if underneath and rng.random() >= UNDER_KEEP:
                continue  # revealed skin carries fewer, scattered scales

            flow = math.radians(
                38
                + 26 * math.sin(x * 0.0042 + y * 0.0017)
                + 14 * math.sin(y * 0.006 - x * 0.001)
            )
            if underneath:
                flow += UNDER_TILT  # the new skin grows along a different grain
            ang = flow + rng.uniform(-0.2, 0.2)

            peel = 0.0
            if dc < half + 48:
                peel = 1.0 - (dc - half) / 48.0
            if peel > 0:
                twist = rng.choice((-1.0, 1.0))
                ang += twist * peel * rng.uniform(0.7, 1.6)
                push = peel * rng.uniform(20, 42)
                x += nx * side * push
                y += ny * side * push
                field = under_grays if underneath else shell_grays
                color = oranges[2] if peel > 0.45 else rng.choice(field)
                color = rng.choice((color, oranges[0])) if peel > 0.8 else color
            elif underneath:
                color = rng.choice(under_grays)
            else:
                color = shell_grays[rng.randrange(len(shell_grays))] if rng.random() < 0.5 else rng.choice(shell_grays)

            ln = rng.uniform(18, 26)
            wd = ln * 0.45
            c, s = math.cos(ang), math.sin(ang)
            pts = [
                (x + c * ln / 2, y + s * ln / 2),
                (x - s * wd / 2, y + c * wd / 2),
                (x - c * ln / 2, y - s * ln / 2),
                (x + s * wd / 2, y - c * wd / 2),
            ]
            d.polygon(pts, fill=color)
            count += 1

    # --- Torn rupture geometry (this variant's single change) ---
    # The rupture is reworked from a clean diagonal band into a torn,
    # peeling break: irregular black jags extend the torn edge on both
    # sides, and shell-side diamonds curl back as lifted flaps.
    # Every draw here comes from position-hashed streams, so the seeded
    # field draws above are untouched and byte-identical to the champion.
    trng = random.Random(f"{SEED}-tear")
    tx, ty = vx / L, vy / L  # unit tangent along the band

    # Irregular torn edge: black jags reaching out from the band edges.
    # right[] is the shell-side edge (-normal), left[] the skin-side edge.
    for i in range(N + 1):
        for sgn, edge, kmax in ((-1.0, right, 58.0), (1.0, left, 40.0)):
            ex, ey = edge[i]
            if trng.random() < 0.62:
                k = trng.uniform(16, kmax)       # jag depth
                wseg = trng.uniform(16, 34)     # jag width along the band
                along = trng.uniform(-14, 14)   # slide along the tangent
                bx, by = ex + tx * along, ey + ty * along
                tipx = bx + nx * sgn * k
                tipy = by + ny * sgn * k
                d.polygon(
                    [
                        (bx - tx * wseg / 2, by - ty * wseg / 2),
                        (bx + tx * wseg / 2, by + ty * wseg / 2),
                        (tipx, tipy),
                    ],
                    fill=black,
                )

    # --- Curled peel ribbon (inherited from the champion, unchanged) ---
    # The flap row reconceived as one continuous lifted strip: the shell
    # peels back from the torn edge as a single gesture, like tape rolling
    # off the skin. Two overlapping rows run the whole break: shell-gray
    # diamonds curling back off the edge, and a back row settling toward
    # the shell's flow. Every draw here comes from a position-hashed
    # stream, so all seeded field draws above are untouched and
    # byte-identical to the champion.
    rrng = random.Random(f"{SEED}-ribbon")
    ribbon_grays = [pal["base"][s] for s in ("500", "600", "700")]
    band_ang = math.atan2(ty, tx)
    curl_dir = band_ang + math.pi / 2  # perpendicular to the band
    shell_flow = math.radians(38)

    def diamond(cx, cy, ln, wd, ang):
        c, s = math.cos(ang), math.sin(ang)
        return [
            (cx + c * ln / 2, cy + s * ln / 2),
            (cx - s * wd / 2, cy + c * wd / 2),
            (cx - c * ln / 2, cy - s * ln / 2),
            (cx + s * wd / 2, cy - c * wd / 2),
        ]

    # Interpolate the shell-side torn edge (right[]) at a band parameter t.
    def shell_edge(t):
        fpos = t * N
        i0 = min(N - 1, int(fpos))
        f = fpos - i0
        ex = right[i0][0] + (right[i0 + 1][0] - right[i0][0]) * f
        ey = right[i0][1] + (right[i0 + 1][1] - right[i0][1]) * f
        return ex, ey

    # Segment geometry first (draw order preserved so the seeded draws of the
    # fields above stay untouched; the underside is rebuilt below this pass).
    segs = []
    nseg = 52
    for q in range(nseg):
        t = min(0.985, max(0.015, (q + rrng.uniform(-0.35, 0.35)) / nseg))
        ex, ey = shell_edge(t)
        # back of the roll: settling toward the shell's flow
        bx = ex - nx * rrng.uniform(28, 42)
        by = ey - ny * rrng.uniform(28, 42)
        bln = rrng.uniform(30, 42)
        bang = curl_dir + (shell_flow - curl_dir) * rrng.uniform(0.4, 0.7)
        bang += rrng.uniform(-0.2, 0.2)
        # lifted curl: shell-gray diamonds rolling back off the edge
        cx = ex - nx * rrng.uniform(12, 22)
        cy = ey - ny * rrng.uniform(12, 22)
        cln = rrng.uniform(32, 44)
        cang = curl_dir + rrng.uniform(-0.55, 0.55)
        segs.append((ex, ey, bx, by, bln, bang, cx, cy, cln, cang))

    # --- Lifted underside face (this variant's single change) ---
    # The segmented shadow crescents and the chunky orange underside band
    # are replaced by one continuous dark lifted face: the inside face of
    # the peeling strip, drawn as a single unbroken strip from the tear
    # edge to the curl backs. Three clean registers along one curl: a dark
    # shadow strip hugging the tear edge, the lifted face itself, and a
    # thin orange fresh-edge line where the strip meets the tear.
    # Every draw here comes from a position-hashed stream, so all seeded
    # field draws above are untouched and byte-identical to the champion.
    frng = random.Random(f"{SEED}-face")
    edge_pts, back_pts = [], []
    for (ex, ey, bx, by, bln, bang, cx, cy, cln, cang) in segs:
        edge_pts.append((ex + nx * frng.uniform(-4, 4), ey + ny * frng.uniform(-4, 4)))
        # well behind the curl diamonds, so a dark crescent of the lifted
        # face shows past the roll - the underside of the peeling strip
        back_pts.append((cx - nx * frng.uniform(30, 42), cy - ny * frng.uniform(30, 42)))
    # the lifted face: one continuous dark inside face from the tear edge
    # to behind the curl - the shell's underside, reading as depth
    d.polygon(edge_pts + back_pts[::-1], fill=pal["base"]["850"])

    # --- True peel-back: the strip's tip folds over the shell field (this
    # variant's single change) ---
    # The strip continues past the curl and lays its tip back onto the dense
    # shell field above the break: the shell's dark underside visibly
    # overlapping the shell's own gray diamonds, like bark peeled back onto
    # itself. The strip stays ONE continuous unbroken band - widest mid-run,
    # tapering toward both ends of the band - so it reads as a single folded
    # flap lying flat on the field: not a second break, not a second peel.
    # Drawn before the ribbon rows so the curled gray diamonds sit on the
    # strip near the tear edge while the dark tip emerges past the curl.
    # Every draw here comes from a position-hashed stream, so all seeded
    # field draws above are untouched and byte-identical to the champion.
    fdrng = random.Random(f"{SEED}-fold")
    n = len(back_pts)
    tip_pts = []
    for i, (px, py) in enumerate(back_pts):
        u = i / max(1, n - 1)
        # one folded flap: it exists only mid-run, tapering to zero toward
        # both ends of the band, and its reach peaks at the flap's center -
        # a single tip folded back onto the field, not the whole strip
        v = max(0.0, min(1.0, (u - 0.22) / 0.56))
        reach = (58.0 + fdrng.uniform(-12, 12)) * math.sin(math.pi * v) ** 1.1
        along = fdrng.uniform(-10, 10)
        tip_pts.append(
            (px - nx * reach + tx * along, py - ny * reach + ty * along)
        )
    d.polygon(back_pts + tip_pts[::-1], fill=pal["base"]["850"])

    # --- Faceted worked inside face (this variant's single change) ---
    # The dark lifted underside is reconceived from "one dark band" into a
    # faceted, worked inside face: the whole strip - tear edge to folded
    # tip - carries large, high-contrast diamonds from the existing gray
    # ramp, at full-frame legibility. Each diamond is drawn in one of
    # three tones - a light facet (base 400), a mid facet (base 600), or a
    # deep facet (base 950) - against the base-850 face, so the strip reads
    # as worked shell material with real light and shadow, not a flat
    # dark band merging into the tear. Grain is point-in-polygon tested
    # to stay strictly inside the strip's two polygons, kept clear of the
    # tear edge (a clean margin from the orange line), and never scattered
    # into the fields. Drawn before the ribbon rows so the curled diamonds
    # sit on the worked underside, naturally. Every draw here comes from
    # a position-hashed stream, so all seeded field draws above are
    # untouched and byte-identical to the champion.
    grng = random.Random(f"{SEED}-facet")
    facet_grays = [pal["base"][s] for s in ("400", "600", "950")]
    face_poly = edge_pts + back_pts[::-1]
    fold_poly = back_pts + tip_pts[::-1]

    def point_in_poly(px, py, poly):
        inside = False
        j = len(poly) - 1
        for i in range(len(poly)):
            xi, yi = poly[i]
            xj, yj = poly[j]
            if ((yi > py) != (yj > py)) and (
                px < (xj - xi) * (py - yi) / (yj - yi) + xi
            ):
                inside = not inside
            j = i
        return inside

    def in_strip(px, py):
        return point_in_poly(px, py, face_poly) or point_in_poly(px, py, fold_poly)

    edge_margin_sq = 20.0 * 20.0
    facet_ang = band_ang + grng.uniform(-0.1, 0.1)
    stepg = 26
    for gy in range(0, SIZE, stepg):
        for gx in range(0, SIZE, stepg):
            cx = gx + stepg / 2 + grng.uniform(-10, 10)
            cy = gy + stepg / 2 + grng.uniform(-10, 10)
            if not in_strip(cx, cy):
                continue
            # keep a clean margin from the tear edge / orange line
            near_edge = False
            for ex, ey in edge_pts:
                dx, dy = cx - ex, cy - ey
                if dx * dx + dy * dy < edge_margin_sq:
                    near_edge = True
                    break
            if near_edge:
                continue
            ln = grng.uniform(26, 38)
            wd = ln * 0.55
            ang = facet_ang + grng.uniform(-0.28, 0.28)
            c, s = math.cos(ang), math.sin(ang)
            verts = [
                (cx + c * ln / 2, cy + s * ln / 2),
                (cx - s * wd / 2, cy + c * wd / 2),
                (cx - c * ln / 2, cy - s * ln / 2),
                (cx + s * wd / 2, cy - c * wd / 2),
            ]
            if all(in_strip(vx, vy) for vx, vy in verts):
                d.polygon(verts, fill=grng.choice(facet_grays))

    # thin fresh edge: orange only where the strip meets the tear
    d.line(edge_pts, fill=oranges[1], width=6)

    # Layered curl roll: the peel's scroll, given real volume (this variant's
    # single change). Each ribbon segment is reconceived from two flat
    # diamonds into a stack of overlapping faceted layers rolling from the
    # back of the roll to the lifted lip - a scroll cross-section of shed
    # shell lifting off. Dark-to-light ramp (800 -> 500) runs with the stack
    # so the roll reads as a curling volume, not a flat fringe. Geometry of
    # the segments themselves is untouched; only this drawing pass changes.
    roll_rng = random.Random(f"{SEED}-roll")
    roll_ramp = [pal["base"][s] for s in ("800", "700", "600", "500")]
    for (ex, ey, bx, by, bln, bang, cx, cy, cln, cang) in segs:
        layers = 4
        for k in range(layers):
            f = k / (layers - 1)  # 0 = back of roll, 1 = lifted lip
            # position runs back-to-lip along the curl, arcing outward so
            # the lip steps clear of the band
            px = bx + (cx - bx) * f + nx * roll_rng.uniform(-6, 6)
            py = by + (cy - by) * f + ny * roll_rng.uniform(-6, 6)
            ln = (bln + (cln - bln) * f) * (1.12 - 0.18 * f)
            ang = bang + (cang - bang) * f + roll_rng.uniform(-0.12, 0.12)
            color = roll_rng.choice(
                (roll_ramp[k], roll_ramp[min(3, k + 1)])
            ) if k < 3 else roll_ramp[3]
            d.polygon(diamond(px, py, ln, ln * 0.5, ang), fill=color)

    # --- Worked shadow step (this variant's single change) ---
    # The separation between the faceted underside and the black tear is
    # reconceived from a flat boundary into a worked lifting step: a pale
    # stepped crescent beneath the lifted face, like a cast-lift edge where
    # the scroll's underside rises off the skin. Pale worked diamonds step
    # from the tear's dark edge up into the faceted face - a clean lift-off
    # gesture along the whole break. Drawn last so it reads continuously,
    # and it sits on the strip side of the orange line, so the tear never
    # grows. Position-hashed stream only - all seeded draws untouched.
    stprng = random.Random(f"{SEED}-step")
    nstep = len(edge_pts)
    step_outer, step_inner = [], []
    for i, (ex, ey) in enumerate(edge_pts):
        u = i / max(1, nstep - 1)
        v = max(0.0, min(1.0, (u - 0.05) / 0.90))
        taper = math.sin(math.pi * v) ** 0.7
        o = 8.0 + stprng.uniform(-2, 2)          # just past the orange line
        depth = 6.0 + 26.0 * taper                # crescent: thins at the ends
        step_outer.append((ex - nx * o + tx * stprng.uniform(-2, 2),
                           ey - ny * o + ty * stprng.uniform(-2, 2)))
        step_inner.append((ex - nx * (o + depth) + tx * stprng.uniform(-2, 2),
                           ey - ny * (o + depth) + ty * stprng.uniform(-2, 2)))
    step_band = step_outer + step_inner[::-1]
    d.polygon(step_band, fill=pal["base"]["600"])

    def pip(px, py, poly):
        inside = False
        j = len(poly) - 1
        for k in range(len(poly)):
            xi, yi = poly[k]
            xj, yj = poly[j]
            if ((yi > py) != (yj > py)) and (
                px < (xj - xi) * (py - yi) / (yj - yi) + xi
            ):
                inside = not inside
            j = k
        return inside

    step_ang = band_ang + stprng.uniform(-0.08, 0.08)
    for i in range(nstep):
        u = i / max(1, nstep - 1)
        v = max(0.0, min(1.0, (u - 0.05) / 0.90))
        taper = math.sin(math.pi * v) ** 0.7
        if taper < 0.15:
            continue
        ox, oy = step_outer[i]
        ix, iy = step_inner[i]
        # two terraces: smaller dimmer diamonds near the tear, larger
        # paler ones stepping up into the faceted face
        for f, ln, tone in ((0.33, 15.0, "500"), (0.66, 21.0, "400")):
            ln *= 0.6 + 0.4 * taper
            cx = ox + (ix - ox) * f + stprng.uniform(-3, 3)
            cy = oy + (iy - oy) * f + stprng.uniform(-3, 3)
            wd = ln * 0.55
            ang = step_ang + stprng.uniform(-0.25, 0.25)
            c, s = math.cos(ang), math.sin(ang)
            verts = [
                (cx + c * ln / 2, cy + s * ln / 2),
                (cx - s * wd / 2, cy + c * wd / 2),
                (cx - c * ln / 2, cy - s * ln / 2),
                (cx + s * wd / 2, cy - c * wd / 2),
            ]
            if all(pip(vx2, vy2, step_band) for vx2, vy2 in verts):
                d.polygon(verts, fill=pal["base"][tone])

    # --- Turn-over crown, enlarged (this variant's single change) ---
    # The fold-back is reconceived from a worked mound into a larger, more
    # open turn: the strip's pale faceted inside face rolls around its own
    # edge in one bold gesture and lands on the shell field above the break.
    # The crown of the turn - where the fold reaches farthest - widens into
    # a big pale worked face with its own tonal structure (light near the
    # roll-over lip on the strip side, dimming toward the field), its own
    # crown edge line where the face rolls over, and a widened cast-shadow
    # crescent hugging the crown's field-side underside. The whole mid-break
    # zone reads as one continuous open turn at full-frame size: step up
    # from the tear, across the faceted underside, around the turn-over
    # crown, down onto the field. Position-hashed stream only - all seeded
    # draws untouched.
    torng = random.Random(f"{SEED}-turn21")
    nfold = len(tip_pts)
    ci0, ci1 = int(0.22 * (nfold - 1)), int(0.78 * (nfold - 1))
    crown_idx = list(range(ci0, ci1 + 1))
    turn_inner, turn_outer = [], []
    for k, i in enumerate(crown_idx):
        px, py = tip_pts[i]
        bx_, by_ = back_pts[i]
        u = i / max(1, nfold - 1)
        v = max(0.0, min(1.0, (u - 0.22) / 0.56))
        t = math.sin(math.pi * v) ** 0.8  # collapse the band at the flap ends
        rx, ry = px - bx_, py - by_
        rl = math.hypot(rx, ry)
        if rl < 1.0:  # degenerate at the flap ends: fall back to strip->field radial
            rx, ry = -nx, -ny
        else:
            rx, ry = rx / rl, ry / rl  # outward: away from the strip
        turn_inner.append((px - rx * 62 * t + torng.uniform(-3, 3),
                           py - ry * 62 * t + torng.uniform(-3, 3)))
        turn_outer.append((px + rx * 24 * t + torng.uniform(-3, 3),
                           py + ry * 24 * t + torng.uniform(-3, 3)))
    turn_ang = band_ang + torng.uniform(-0.08, 0.08)
    # Shadow crescent under the enlarged crown: a base-800 band running
    # from just inside the pale crown's strip edge to well past its field
    # edge. The pale turn band is drawn over it right after, so the shadow
    # peeks only on the field side. Worked with base-700 facets in its
    # visible window - lighter than the tear, so it never reads as a second
    # rupture. Position-hashed stream only - all seeded draws untouched.
    crng = random.Random(f"{SEED}-crease21")
    shad_inner, shad_outer = [], []
    for i in crown_idx:
        px, py = tip_pts[i]
        bx_, by_ = back_pts[i]
        u = i / max(1, nfold - 1)
        v = max(0.0, min(1.0, (u - 0.22) / 0.56))
        t = math.sin(math.pi * v) ** 0.8  # collapse the band at the flap ends
        rx, ry = px - bx_, py - by_
        rl = math.hypot(rx, ry)
        if rl < 1.0:  # degenerate at the flap ends: fall back to strip->field radial
            rx, ry = -nx, -ny
        else:
            rx, ry = rx / rl, ry / rl  # outward: away from the strip
        shad_inner.append((px - rx * 58 * t + crng.uniform(-2, 2),
                           py - ry * 58 * t + crng.uniform(-2, 2)))
        shad_outer.append((px + rx * 60 * t + crng.uniform(-2, 2),
                           py + ry * 60 * t + crng.uniform(-2, 2)))
    shadow_band = shad_inner + shad_outer[::-1]
    d.polygon(shadow_band, fill=pal["base"]["800"])
    for k, (ix, iy) in enumerate(shad_inner):
        if k % 2:
            continue
        ox, oy = shad_outer[k]
        # work the shadow with facets in its visible field-side portion
        for f, ln in ((0.75, 22.0), (0.90, 18.0)):
            cx = ix + (ox - ix) * f + crng.uniform(-3, 3)
            cy = iy + (oy - iy) * f + crng.uniform(-3, 3)
            ang = turn_ang + crng.uniform(-0.25, 0.25)
            verts = diamond(cx, cy, ln, ln * 0.55, ang)
            if all(pip(vx2, vy2, shadow_band) for vx2, vy2 in verts):
                d.polygon(verts, fill=pal["base"]["700"])
    turn_band = turn_inner + turn_outer[::-1]
    d.polygon(turn_band, fill=pal["base"]["500"])

    # The enlarged inside face: large facets with a deepened tonal sweep -
    # light (300) at the roll-over lip on the strip side, settling through
    # 500 to 700 toward the field side - so the open turn reads as real
    # volume, one rolling gesture landing on the field.
    for k, i in enumerate(crown_idx):
        ix, iy = turn_inner[k]
        ox, oy = turn_outer[k]
        for f, ln, tone in ((0.25, 44.0, "300"), (0.50, 40.0, "500"), (0.75, 34.0, "700")):
            cx = ix + (ox - ix) * f + torng.uniform(-4, 4)
            cy = iy + (oy - iy) * f + torng.uniform(-4, 4)
            ang = turn_ang + torng.uniform(-0.25, 0.25)
            verts = diamond(cx, cy, ln, ln * 0.55, ang)
            if all(pip(vx2, vy2, turn_band) for vx2, vy2 in verts):
                d.polygon(verts, fill=pal["base"][tone])
    # Crown edge: the turn's decisive landing contour. The soft 700 line is
    # reconceived as a stepped facet edge - overlapping diamonds laid along
    # the band's field-side edge, stepping 700/800 so the contour reads
    # cleanly against both the pale face and the shell field - so the
    # roll-over lip lands on the field as one bold worked contour.
    erng = random.Random(f"{SEED}-edge22")
    edge_grays = [pal["base"]["700"], pal["base"]["800"]]
    for ox, oy in turn_outer:
        jx, jy = ox + erng.uniform(-6, 6), oy + erng.uniform(-6, 6)
        ln = erng.uniform(18, 26)
        ang = turn_ang + erng.uniform(-0.2, 0.2)
        d.polygon(diamond(jx, jy, ln, ln * 0.5, ang), fill=erng.choice(edge_grays))
    # the terraces flow into the crown: pale bridge diamonds from the
    # step band's inner edge up to the turn band's strip side
    bridge_tones = [pal["base"][s] for s in ("400", "500")]
    for k, i in enumerate(crown_idx):
        if k % 3:
            continue
        sx, sy = step_inner[i]
        ix, iy = turn_inner[k]
        mx, my = (sx + ix) / 2, (sy + iy) / 2
        ang = turn_ang + torng.uniform(-0.2, 0.2)
        d.polygon(
            diamond(mx + torng.uniform(-4, 4), my + torng.uniform(-4, 4),
                    torng.uniform(18, 26), 12.0, ang),
            fill=torng.choice(bridge_tones),
        )
    # the folded-over side settles into the shell field: shell-gray
    # diamonds straddling the band's outer edge
    for k, i in enumerate(crown_idx):
        if k % 2:
            continue
        ox, oy = turn_outer[k]
        ang = turn_ang + torng.uniform(-0.2, 0.2)
        d.polygon(
            diamond(ox + torng.uniform(-3, 3), oy + torng.uniform(-3, 3),
                    torng.uniform(20, 30), 12.0, ang),
            fill=torng.choice(shell_grays),
        )

    img.save(f"{HERE}/render.png")
    print("marks:", count)


if __name__ == "__main__":
    main()
