ci: update cibuildwheel to v4.1 and pyodide to 314 (#6095)

* ci: update cibuildwheel to v4.1 and pyodide to 314

Bump pypa/cibuildwheel from v3.4 to v4.1 across the Pyodide, iOS, and
Android jobs. Move the Pyodide build to cp314-pyodide_wasm32
(pyodide 314.0.0).

Drop the iOS CIBW_SKIP: cp314-* workaround now that pypa/cibuildwheel#2494
is resolved.

Assisted-by: ClaudeCode:claude-opus-4.8

* test: xfail array resize on numpy<2.4 + Python 3.14

Removing the cp314 iOS skip surfaced a pre-existing numpy bug, not a
cibuildwheel regression: numpy<2.4 has a resize(refcheck=True) regression
on Python 3.14 where the reference held by the bound function isn't
detected, so a resize that should raise instead succeeds and the later
reshape rejects the non-square size. Fixed in numpy>=2.4, but the iOS test
environment has no numpy wheel newer than 2.3.5.post1, so xfail the test
for that specific combination.

Assisted-by: ClaudeCode:claude-opus-4.8

* test: link numpy resize aliasing issue and trim comment

iOS numpy wheels updated to 2.5.0, so the xfail is a general numpy<2.4 +
Python 3.14 guard rather than iOS-specific. Reference numpy/numpy#30265.

Assisted-by: ClaudeCode:claude-opus-4.8
diff --git a/.github/workflows/tests-cibw.yml b/.github/workflows/tests-cibw.yml
index 1fa4c8a..83107b2 100644
--- a/.github/workflows/tests-cibw.yml
+++ b/.github/workflows/tests-cibw.yml
@@ -30,7 +30,7 @@
         PYODIDE_BUILD_EXPORTS: whole_archive
       with:
         package-dir: tests
-        only: cp312-pyodide_wasm32
+        only: cp314-pyodide_wasm32
 
   build-ios:
     name: iOS wheel ${{ matrix.runs-on }}
@@ -51,7 +51,6 @@
     - uses: pypa/cibuildwheel@v4.1
       env:
         CIBW_PLATFORM: ios
-        CIBW_SKIP: cp314-*  # https://github.com/pypa/cibuildwheel/issues/2494
       with:
         package-dir: tests
 
diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py
index 93477aa..e3f29e9 100644
--- a/tests/test_numpy_array.py
+++ b/tests/test_numpy_array.py
@@ -1,5 +1,7 @@
 from __future__ import annotations
 
+import sys
+
 import pytest
 
 import env  # noqa: F401
@@ -7,6 +9,12 @@
 
 np = pytest.importorskip("numpy")
 
+# numpy < 2.4 fails to detect aliasing in ndarray.resize on Python 3.14, so a
+# resize that should raise instead succeeds: numpy/numpy#30265 (fixed in 2.4.0).
+NUMPY_RESIZE_REFCHECK_BROKEN = sys.version_info >= (3, 14) and tuple(
+    int(x) for x in np.__version__.split(".")[:2]
+) < (2, 4)
+
 
 def test_dtypes():
     # See issue #1328.
@@ -485,6 +493,10 @@
     assert m.array_initializer_list4().shape == (1, 2, 3, 4)
 
 
+@pytest.mark.xfail(
+    NUMPY_RESIZE_REFCHECK_BROKEN,
+    reason="numpy<2.4 resize(refcheck) regression on Python 3.14",
+)
 def test_array_resize():
     a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64")
     m.array_reshape2(a)