// Shared bits used by all three homepage directions.
// - Logo: brand wordmark from PNG
// - QuiltGrid: parametric grid of half-square triangles (HSTs)
// - RainbowDivider: 6-stripe band of brand colors
// - StreamDot, ArrowLink, eyebrows — small atoms
// --- Logo ----------------------------------------------------------
function Logo({ variant = "color", height = 44, style }) {
// 'color' is the regular logo. 'mono-paper' overlays a knockout for dark backgrounds.
const src = variant === "color" ? "assets/roco-logo-full.png" : "assets/roco-logo-transparent.png";
return (
);
}
// A simple mono "RoCo / Arts Council" stamp used on dark surfaces in case
// the rasterized logo reads poorly. Wordmark approximation; the real PNG
// stays the canonical mark.
function LogoMono({ height = 44, color = "#FBF7EE", style }) {
return (
RoCo
— Arts Council —
);
}
// --- QuiltGrid -----------------------------------------------------
// Renders an R×C grid of half-square triangles. Each cell is a square split
// diagonally with two colors; orientation alternates pseudo-randomly per seed.
// Used as a hero block in directions A and B.
//
// Palette is the brand 6 + paper. We bias for full saturation in cells and
// occasional empty (paper/navy) tiles to give the grid breathing room.
function QuiltGrid({
cols = 5, rows = 4, cellSize = 140, seed = 7,
palette = ["#45217A", "#F3CF03", "#C81344", "#78BE4D", "#4195D3", "#01234B", "#FBF7EE"],
emptyChance = 0.08,
style,
}) {
// simple deterministic RNG so every artboard render is identical
let s = seed;
const rnd = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
const cells = [];
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const x = c * cellSize;
const y = r * cellSize;
const orientation = Math.floor(rnd() * 4); // 0..3
// pick two distinct colors
const ai = Math.floor(rnd() * palette.length);
let bi = Math.floor(rnd() * palette.length);
if (bi === ai) bi = (bi + 1) % palette.length;
const a = palette[ai];
const b = palette[bi];
// small chance of an empty paper square for rhythm
const empty = rnd() < emptyChance;
const baseFill = empty ? "#FBF7EE" : a;
// Triangle paths per orientation (the "top" triangle):
// 0 = top-left triangle (cuts ↘), 1 = top-right (cuts ↙),
// 2 = bottom-right, 3 = bottom-left
const tri = (() => {
switch (orientation) {
case 0: return `M${x},${y} L${x + cellSize},${y} L${x},${y + cellSize} Z`;
case 1: return `M${x},${y} L${x + cellSize},${y} L${x + cellSize},${y + cellSize} Z`;
case 2: return `M${x + cellSize},${y} L${x + cellSize},${y + cellSize} L${x},${y + cellSize} Z`;
case 3: default: return `M${x},${y} L${x + cellSize},${y + cellSize} L${x},${y + cellSize} Z`;
}
})();
cells.push(
{!empty && }
);
}
}
return (
);
}
// --- HST corner stamp (small) -------------------------------------
function HstStamp({ size = 48, top = "#45217A", bottom = "#F3CF03", style }) {
return (
);
}
// --- Pinwheel block -----------------------------------------------
function Pinwheel({ size = 320, colors = ["#45217A", "#F3CF03", "#C81344", "#78BE4D"], style }) {
return (
);
}
// --- Rainbow divider ----------------------------------------------
function RainbowDivider({ height = 8, style }) {
const colors = ["#45217A", "#F3CF03", "#C81344", "#78BE4D", "#4195D3", "#01234B"];
return (