function $ColorBox(vertical) {
	const $cb = $(E("div")).addClass("color-box");

	const $current_colors = $Swatch(selected_colors.ternary).addClass("current-colors");
	const $palette = $(E("div")).addClass("palette");

	$cb.append($current_colors, $palette);

	const $foreground_color = $Swatch(selected_colors.foreground).addClass("color-selection foreground-color");
	const $background_color = $Swatch(selected_colors.background).addClass("color-selection background-color");
	$current_colors.append($background_color, $foreground_color);

	$G.on("option-changed", () => {
		update_$swatch($foreground_color, selected_colors.foreground);
		update_$swatch($background_color, selected_colors.background);
		update_$swatch($current_colors, selected_colors.ternary);
	});

	$current_colors.on("pointerdown", () => {
		const new_bg = selected_colors.foreground;
		selected_colors.foreground = selected_colors.background;
		selected_colors.background = new_bg;
		$G.triggerHandler("option-changed");
	});

	const make_color_button = (color) => {

		const $b = $Swatch(color).addClass("color-button");
		$b.appendTo($palette);

		const double_click_period_ms = 400;
		let within_double_click_period = false;
		let double_click_button = null;
		let double_click_tid;
		// @TODO: handle left+right click at same time
		// can do this with mousedown instead of pointerdown, but may need to improve Dwell Clicker click simulation
		$b.on("pointerdown", (e) => {
			// @TODO: allow metaKey for ternary color, and selection cropping, on macOS?

			if (button === 0) {
				$c.data("$last_fg_color_button", $b);
			}

			const color_selection_slot = e.ctrlKey ? "ternary" : e.button === 0 ? "foreground" : e.button === 2 ? "background" : null;
			if (color_selection_slot) {
				if (within_double_click_period && e.button === double_click_button) {
					show_edit_colors_window($b, color_selection_slot);
				} else {
					selected_colors[color_selection_slot] = $b.data("swatch");
					$G.trigger("option-changed");
				}

				clearTimeout(double_click_tid);
				double_click_tid = setTimeout(() => {
					within_double_click_period = false;
					double_click_button = null;
				}, double_click_period_ms);
				within_double_click_period = true;
				double_click_button = e.button;
			}
		});
	};

	const build_palette = () => {
		$palette.empty();

		palette.forEach(make_color_button);

		// Note: this doesn't work until the colors box is in the DOM
		const $some_button = $palette.find(".color-button");
		if (vertical) {
			const height_per_button =
				$some_button.outerHeight() +
				parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-top")) +
				parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-bottom"));
			$palette.height(Math.ceil(palette.length / 2) * height_per_button);
		} else {
			const width_per_button =
				$some_button.outerWidth() +
				parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-left")) +
				parseFloat(getComputedStyle($some_button[0]).getPropertyValue("margin-right"));
			$palette.width(Math.ceil(palette.length / 2) * width_per_button);
		}

		// the "last foreground color button" starts out as the first in the palette
		$c.data("$last_fg_color_button", $palette.find(".color-button:first-child"));
	};

	let $c;
	if (vertical) {
		$c = $Component(localize("Colors"), "colors-component", "tall", $cb);
		$c.appendTo(get_direction() === "rtl" ? $left : $right); // opposite ToolBox by default
	} else {
		$c = $Component(localize("Colors"), "colors-component", "wide", $cb);
		$c.appendTo($bottom);
	}

	build_palette();
	$(window).on("theme-change", build_palette);

	// I'm gonna do things messy, got a long road to go!
	// eslint-disable-next-line no-self-assign
	$c = /** @type {JQuery<HTMLDivElement> & I$Component & I$ColorBox} */ ($c);

	$c.rebuild_palette = build_palette;

	return $c;
}
@param {boolean} vertical
@returns {JQuery<HTMLDivElement> & I$Component & I$ColorBox}