(version 1)

# SP1 edge-connector (J3): the gold fingers must reach the board edge to make
# contact in the GameCube slot, so copper-to-edge clearance is intentionally
# relaxed for this footprint only. This is by design, not a defect.
# Test BOTH items because the violated pair is (Edge.Cuts segment of J3) vs (pad
# of J3) - the edge segment is item A, the pad is item B.
(rule "SP1 gold fingers - allow copper to board edge"
	(condition "A.memberOfFootprint('J3') || B.memberOfFootprint('J3')")
	(constraint edge_clearance (min -0.5mm)))

# Power-integrity: flag any power-rail track narrower than its netclass width.
# A netclass "track width" is only the DEFAULT for new routing - KiCad does NOT
# enforce it - so without these rules an under-width power trace passes DRC
# silently. These make DRC surface every thin power segment so they don't have to
# be found by eye. Severity is "warning" (not error) so an unavoidable neck into a
# fine-pitch pin is flagged for review but never blocks fab export.
(rule "Power rail minimum width (0.3mm)"
	(severity warning)
	(condition "A.NetClass == 'Power'")
	(constraint track_width (min 0.3mm)))

(rule "Low-current power rail minimum width (0.25mm)"
	(severity warning)
	(condition "A.NetClass == 'PowerLV'")
	(constraint track_width (min 0.25mm)))

# ---------------------------------------------------------------------------
# JLCPCB manufacturing capability floor (standard multi-layer tier), pulled
# from jlcpcb.com/capabilities/pcb-capabilities. These are "the board cannot
# physically be made this way" limits, not house-style margins - severity is
# "error" because violating one means a rejected/reworked fab order, not just
# a style nit. They sit BELOW the netclass defaults above (0.2-0.3mm), so on
# a board routed to house style they should never fire; they exist as a
# backstop for hand-tweaked geometry (e.g. necking into a fine-pitch pin)
# that dips below what JLCPCB can actually etch/drill.
#
# NOT covered here (no DRC constraint type exists for these - check manually
# before ordering):
#   - Board thickness: JLCPCB stocks 0.6/0.8/1.0/1.2/1.6/2.0mm. This board's
#     stackup sums to 1.1412mm, which is NOT one of those - confirm with
#     JLCPCB's stackup tool (their impedance-controlled 4-layer config can
#     produce non-stock totals like this deliberately) before ordering.
#   - Solder mask minimum bridge/dam width (0.10mm standard, 0.13mm black/
#     white): no matching KiCad custom-rule constraint type as of this
#     version.
#   - NPTH minimum hole size (0.50mm): skipped - no confirmed condition
#     syntax to select NPTH-only pads without risking a rule that silently
#     never matches; the general hole_size floor below still catches any
#     NPTH hole below the PTH/via floor, just not the tighter 0.50mm NPTH-
#     specific one.

(rule "JLCPCB min copper trace width (0.09mm)"
	(severity error)
	(constraint track_width (min 0.09mm)))

(rule "JLCPCB min copper clearance (0.09mm)"
	(severity error)
	(constraint clearance (min 0.09mm)))

(rule "JLCPCB min via/PTH drill (0.15mm)"
	(severity error)
	(constraint hole_size (min 0.15mm)))

(rule "JLCPCB min via pad diameter (0.25mm)"
	(severity error)
	(constraint via_diameter (min 0.25mm)))

(rule "JLCPCB min hole-to-hole spacing (0.2mm)"
	(severity error)
	(constraint hole_to_hole (min 0.2mm)))

(rule "JLCPCB min hole-to-copper clearance (0.2mm)"
	(severity error)
	(constraint hole_clearance (min 0.2mm)))

(rule "JLCPCB min silkscreen line/text thickness (0.15mm, front)"
	(severity warning)
	(layer "F.SilkS")
	(constraint text_thickness (min 0.15mm)))

(rule "JLCPCB min silkscreen line/text thickness (0.15mm, back)"
	(severity warning)
	(layer "B.SilkS")
	(constraint text_thickness (min 0.15mm)))

(rule "JLCPCB min silkscreen text height (1.0mm, front)"
	(severity warning)
	(layer "F.SilkS")
	(constraint text_height (min 1.0mm)))

(rule "JLCPCB min silkscreen text height (1.0mm, back)"
	(severity warning)
	(layer "B.SilkS")
	(constraint text_height (min 1.0mm)))

(rule "JLCPCB min silkscreen-to-pad clearance (0.15mm, front)"
	(severity warning)
	(layer "F.SilkS")
	(constraint silk_clearance (min 0.15mm)))

(rule "JLCPCB min silkscreen-to-pad clearance (0.15mm, back)"
	(severity warning)
	(layer "B.SilkS")
	(constraint silk_clearance (min 0.15mm)))

# ---------------------------------------------------------------------------
# Differential pair geometry vs calculated target impedance. The USB_DP/ETH_DP
# netclasses (0.25/0.15mm, 0.2/0.14mm) only set the DEFAULT for new routing -
# same caveat as the power-rail rules above, KiCad does not enforce a
# netclass's width/gap on already-routed copper. These rules close that gap:
# they check the geometry actually laid down, not just what a fresh route
# would use, so re-routing to the wrong default (the original bug that had
# USB sitting at ~113ohm on the Default netclass's 0.2/0.25mm) gets caught by
# DRC instead of requiring another hand calculation to notice.
#
# Target values and their impedance were derived by hand (IPC-2141-style
# edge-coupled microstrip formula) from this board's actual stackup - F.Cu/
# B.Cu are symmetric microstrip over In1.Cu/In2.Cu respectively (both 0.2104mm
# FR4 dielectrics, same εr), so one target pair covers a net whether it's
# routed on F.Cu or briefly detours to B.Cu for a crossover. Severity is
# "error": these two nets only exist to hit a controlled-impedance target, so
# missing it isn't a style nit like the power-rail/silkscreen rules above -
# it's the one thing the routing was actually for.
#   USB_DP:  0.25mm width / 0.15mm gap -> ~91ohm  (target 90ohm +/-15%)
#   ETH_DP:  0.20mm width / 0.14mm gap -> ~100ohm (target 100ohm +/-15%)
# track_width keeps a +/-0.02mm max band (routing precision). diff_pair_gap
# has NO max: a max bound sounds right but false-flags normal pad fanout,
# where P/N necessarily diverge for a few mm right at the pad before
# converging into the coupled run - DRC can't tell that apart from a
# genuinely uncoupled long run, and real routing hit gaps of 0.65-1.65mm on
# fanout stubs vs a ~0.16mm max here. min still catches the case that matters
# (traces routed too close, i.e. below the fab clearance floor); max on gap
# only matters over a long uncoupled run, which is a length-matching/loss
# question, not something this board-wide rule can safely judge per-segment.
#
# Covers both halves of the D1/D4/D5 split-net TVS pattern: USB_DP now
# matches FT_DP/FT_DN (D1's chip-side pins) alongside USB_D+/USB_D-, and
# ETH_DP matches PHY_TX_P/PHY_TX_N/PHY_RX_P/PHY_RX_N (D4/D5's chip-side pins)
# alongside ETH_TX_P/N and ETH_RX_P/N - see netclass_patterns in
# re-bba-rb.kicad_pro. Without that, the chip-side half of each pair falls
# back to Default and silently skips the impedance target.

(rule "USB differential pair width/gap (target ~90ohm)"
	(severity error)
	(condition "A.NetClass == 'USB_DP'")
	(constraint track_width (min 0.23mm) (opt 0.25mm) (max 0.27mm))
	(constraint diff_pair_gap (min 0.13mm) (opt 0.15mm)))

(rule "Ethernet differential pair width/gap (target ~100ohm)"
	(severity error)
	(condition "A.NetClass == 'ETH_DP'")
	(constraint track_width (min 0.18mm) (opt 0.20mm) (max 0.22mm))
	(constraint diff_pair_gap (min 0.12mm) (opt 0.14mm)))
