You are seat S3 (medieval + modern code paths). Seats S1 (spec.mjs/check.mjs for Breton) and S2 (layout.mjs/render.mjs,
Breton gable roofs and rubble walls) are working in parallel; you do NOT edit their files. The root will dispatch to
your modules by `spec.style`. Read kits-src/medieval/style.json and kits-src/modern/style.json (written by seat H1, with
`notes` on what code must generate), jobs/medieval-atom-kit-v1/STYLE.md and jobs/modern-atom-kit-v1/STYLE.md (the atom
names, sizes and origins Astra is building right now; kits land later in browse/kits/<style>/kit.json), and the
reference sheets jobs/medieval-atom-kit-v1/sheet.png and jobs/modern-atom-kit-v1/sheet.png (LOOK at them).
Build (pure JS, no THREE, same conventions as TYPES.md; tiny local mat4 helpers):
1. omg/kit/building/styles/medieval.mjs:
   `makeSpec(style, type, seed, overrides)` -> BuildingSpec (types house, tavern, smithy, shop): stone ground storey
   (wall.kind 'rubble' on storey 0), timber-framed upper storeys (storey wall kind 'timber_frame', put per-storey kinds in
   an optional `volume.storeys[i].wall` field), jetty 0.4 m on the street facade (optional `volume.jetty`), posts on the
   bay axes and at the window jambs, ONE casement size on every timber storey, pitch 55, plain-tile roof, no gutters,
   tavern: door_arched_double + tavern_sign + ridge chimney + 3 storeys. Same law ideas as BLUEPRINT section 4 (bay grid,
   stacked axes, head line per storey, garden facade mirrored with a back door).
   `layoutStyle(spec, kitInfo)` -> { instances, panels }: the GENERATED timber frame members as panels of kind 'beam'
   (a box: origin, u, v, n, size [len, h, depth]; Oak_frame material; posts, sill beams, rails at floor and head lines,
   studs at window jambs), infill panels (kind 'infill', plaster material from spec.look, set back 25 mm, holes for
   windows), braces as atoms (brace_storey / brace_straight) only in end bays and never across a window, jetty
   (bressummer_1m pieces, joist_end every 0.5 m, jetty_bracket at the corners), tile roof from the eaves with tile strips
   (tile_strip_a/b, 8 tiles = 1.32 m) and singles at the ends (tile 0.165 x 0.265, headlap 0.065, gauge 0.10, lift
   0.015 + 0.010 x (course % 2), never cumulative), ridge_tile_round, verge_board_1m, rafter_end every 0.5 m at the eaves,
   windows (window_leaded on timber storeys, window_leaded_stone on the stone storey), doors, chimney_stone, tavern_sign,
   lantern_iron, corner_stone at the stone storey corners.
2. omg/kit/building/styles/modern.mjs: same two functions for villa, terrace, block3, shop: flat roof (roof.form 'flat')
   with a parapet 0.5 m (generated panels kind 'render'/'concrete' + parapet_coping_1m pieces n = round(L) each L/n,
   parapet_corner at corners), roof slab panel kind 'roof_flat' (Roof_gravel), one head line per storey, window_tall or
   window_std per storey (all the same on a storey), glazing_slider on the garden ground floor, door_pivot + canopy_concrete
   at the entrance, balcony_steel stacked on the axes above a slider for block3, materials: ground in render, upper in
   cladding (Larch_cladding or charred) for villas (material change at a storey line only, max 3 materials per facade),
   rainwater_head + downpipe_square_1m at the back corners, roof_skylight / roof_vent on the slab.
3. omg/kit/building/styles/registry.mjs: `STYLE_MODULES = { medieval, modern }` so the root can dispatch.
4. omg/kit/building/test/styles.test.mjs: 100 seeds x every type x both styles: specs are deterministic; posts at every
   window jamb; no brace crosses a window; one window size per storey; parapet coping covers the full perimeter; tile
   courses never pass the ridge; balconies stack on axes. Print instances and generated panels per building.
Atom node names: exactly those in the two STYLE.md files (roles may map 1:1). Where a kit does not exist yet, code
against those names; the root wires the real kit.json in later.
Files you own: omg/kit/building/styles/*.mjs, omg/kit/building/test/styles.test.mjs.
