/*
 * Ohio PC Solutions — brand tokens, in two themes.
 *
 * Mirrored from the Claude Design system project
 * "Ohio PC Solutions Design System" (tokens/colors.css, typography.css,
 * spacing.css). **That project is the source of truth.** When it changes, change
 * this file to match rather than editing values here and hoping.
 *
 * Copied rather than imported because the design system lives in Claude Design,
 * not in this repository, and a plugin on shared hosting cannot fetch it at
 * runtime. The cost is that the two can drift; the note above is the mitigation.
 *
 * Loaded as a dependency of both app stylesheets, so the palette is defined once
 * for the staff app and the public lookup alike.
 *
 * ---------------------------------------------------------------------------
 * How to read this file
 * ---------------------------------------------------------------------------
 *
 * **Three kinds of token live here, and the difference is what happens to them
 * in dark.**
 *
 *   1. **Brand colours** - `--opcs-navy`, `--opcs-orange`, `--opcs-white`.
 *      Literal. They are the same value in both themes and they never move,
 *      because they are what the brand *is*. Reach for one only where the
 *      literal colour is the point: the orange accent button carrying navy
 *      text, the always-light public lookup.
 *
 *   2. **Role tokens** - `--opcs-surface`, `--opcs-ink`, `--opcs-line` and the
 *      rest. Named for the job rather than the colour, because the colour is
 *      exactly what changes between the two themes. **Almost everything in
 *      staff-app.css uses these.**
 *
 *   3. **Semantic colours** - the orange steps, green, red. Named for what they
 *      mean, which does not change; their *values* change so the meaning still
 *      reads on a dark ground.
 *
 * **Every contrast figure below was measured against the ground the colour
 * actually sits on, in both themes.** Not against white, and not by eye. Re-run
 * the audit after any change here: it walks every rendered element, takes its
 * computed colour and its nearest non-transparent ancestor background, and
 * applies the 4.5:1 and large-text 3:1 thresholds.
 */

:root {
	/*
	 * Light is what an unchosen reader gets - see DEFAULT_THEME - and saying so
	 * here is what makes the form controls, the scrollbars and the canvas agree
	 * with the palette instead of following the operating system on their own.
	 */
	color-scheme: light;

	/* ---- Brand base. Literal, and the same in both themes ---- */
	--opcs-navy: #1a3263;    /* Primary. The brand's own blue */
	--opcs-orange: #ff8600;  /* Accent only. Top rule, emphasis, links on navy */
	--opcs-white: #ffffff;

	/*
	 * ---- Grounds ----
	 *
	 * --opcs-surface        the ordinary ground: the page, cards, tables
	 * --opcs-tint           one step from it: table headers, hovered rows
	 * --opcs-surface-invert a panel deliberately different from the page
	 *
	 * **--opcs-surface-invert is the one ground that does not change with the
	 * theme.** It is the brand's reversed navy field in both, because the dark
	 * grounds are grey: a navy panel on a grey page is the only navy on the
	 * screen and reads as more of a brand moment than it does on white. The
	 * token is still named for the relationship rather than for navy, because
	 * the relationship is what it is for - but here the relationship happens to
	 * survive intact.
	 *
	 * The step from surface to tint is 1.20:1 in light and 1.33:1 in dark. Dark
	 * gets slightly more, because a dark ground carries less separation per unit
	 * of luminance than a light one does.
	 */
	--opcs-surface: #ffffff;
	--opcs-tint: #e8ebef;
	--opcs-surface-invert: #1a3263;

	/*
	 * ---- Ink ----
	 *
	 * --opcs-ink             body, headings, strong edges, and the filled
	 *                        "this one is selected" surfaces
	 * --opcs-ink-strong      one step further, for the hover under those fills
	 * --opcs-ink-quiet       the quiet tier on --opcs-surface and --opcs-tint
	 * --opcs-ink-quieter     one below it, and at the floor - see the note
	 * --opcs-ink-on-tint     quiet text on a board column's coloured ground
	 * --opcs-ink-invert      text on --opcs-surface-invert
	 * --opcs-ink-invert-quiet the quiet tier on that panel
	 *
	 * **--opcs-ink is a fill as well as a colour**, and that is worth knowing
	 * before designing with it. The primary button, the active filter pill, the
	 * checked switch and a chart bar are all "the most ink-like thing on the
	 * screen" - so in dark they become a *light* fill carrying
	 * --opcs-surface as text. A navy fill on a navy-dark page would be a
	 * button nobody can see.
	 */
	--opcs-ink: #1a3263;
	--opcs-ink-strong: #172d59;
	--opcs-ink-invert: #ffffff;

	/*
	 * Two quiet tiers on light grounds, and which ground they sit on is the
	 * whole distinction. Measured, because the two were being used
	 * interchangeably and one of them was unreadable wherever it landed.
	 *
	 *   --opcs-ink-quiet    on --opcs-surface 5.83:1, on --opcs-tint 4.87:1
	 *   --opcs-ink-quieter  on --opcs-surface 5.50:1, on --opcs-tint 4.60:1
	 *
	 * ink-quiet was #696b72, which is 4.45:1 on the tint - and that tint is the
	 * ground under every table header and every hovered row, so the column
	 * headings themselves were just under AA. Six units darker clears it with
	 * room to spare and is indistinguishable by eye.
	 *
	 * **--opcs-ink-quieter is the floor, not a step on a scale.** The board
	 * card's device line asked to sit back from the request above it; the ground
	 * that binds is not the card but the tint it takes when hovered, where this
	 * measures 4.60:1 against the 4.5 it has to clear. The next step down,
	 * #686b72, is 4.46:1 and fails. So most of that line's separation is carried
	 * by its size rather than by its colour. Anything genuinely quieter needs
	 * the hover tint to move with it, which is a change to how a card answers
	 * the pointer and not a colour decision.
	 */
	--opcs-ink-quiet: #63656b;
	--opcs-ink-quieter: #666970;

	/*
	 * **The board column is the one ground that is neither surface nor tint**,
	 * so the quiet text on it gets a token of its own. A column wears its
	 * status colour full height, and --opcs-ink-quiet measures 4.00:1 there and
	 * fails; this is 4.66:1 in light and 4.59:1 against the palest column in
	 * dark. The board's "Empty" and "+2 more" are its only users.
	 *
	 * Measure anything new against the column, not against the page, if it goes
	 * there.
	 */
	--opcs-ink-on-tint: #485b82;

	/*
	 * The quiet tier on a reversed panel. 6.28:1, and the same in both themes:
	 * the panel does not move, so neither does anything on it.
	 *
	 * **Never on a light ground**: this is the answer to "what is their phone
	 * number", and on --opcs-surface it measures 1.99:1.
	 */
	--opcs-ink-invert-quiet: #aeb8ce;

	/*
	 * ---- Lines ----
	 *
	 * --opcs-line         hairline dividers and component borders
	 * --opcs-line-strong  a 3px rule that has to be seen against --opcs-tint
	 *
	 * line is deliberately faint - 1.15:1 against the surface in light, 1.47:1
	 * in dark. The larger figure is not a change of intent: a border on a dark
	 * ground needs more luminance distance to read as the same hairline.
	 *
	 * line-strong has exactly one user, the rule down the left of a history
	 * entry, and its whole job is to be visible on the tint that entry sits on:
	 * 3.15:1 in light, 2.72:1 in dark.
	 */
	--opcs-line: #e5e8ee;
	--opcs-line-strong: #7684a1;

	/*
	 * ---- The navy scale that is left ----
	 *
	 * Most of it moved into the role tokens above - tint-90 became
	 * --opcs-tint, tint-40 --opcs-line-strong, tint-20 --opcs-ink-on-tint,
	 * navy-10 --opcs-ink-strong - because a name that describes a light value
	 * becomes a lie the moment there is a dark one.
	 *
	 * **navy-40 stays under its own name because it is a mix target rather than
	 * a colour anything is drawn in**: the status chips push their ink 62%
	 * toward it in light. **navy-tint-80 has no users at all.** It was the
	 * board's column ground until the columns began wearing their own status
	 * colour full height; it is kept because this file mirrors the design
	 * system rather than pruning it.
	 */
	--opcs-navy-40: #101e3b;
	--opcs-navy-tint-80: #d1d6e0;

	/*
	 * **--opcs-muted-slate fails AA on every ground this plugin puts text on**,
	 * navy included, so it is never a text colour here and nothing uses it.
	 * Kept declared because it is the design system's "quiet on navy" and this
	 * file mirrors that system. Anything that reads goes to --opcs-ink-quiet or
	 * --opcs-ink-quieter on light, --opcs-ink-invert-quiet on a reversed panel.
	 */
	--opcs-muted-slate: #8693ad;

	/*
	 * ---- Orange ----
	 *
	 * **Orange is not a text colour on --opcs-surface.** --opcs-orange-10
	 * measures 2.96:1 there and it cannot be darkened into contrast and still be
	 * the brand orange. Where an accent has to read, the accent goes on the
	 * ground and the text goes to --opcs-ink: 11.44:1 in light, 11.24:1 in dark.
	 *
	 *   --opcs-orange-10  the link and accent-button hover
	 *   --opcs-orange-20  the step that clears 3:1 for a graphic carrying
	 *                     meaning, and 4.5:1 for anything larger. The priority
	 *                     flame's silhouette, the aging figure, the wordmark
	 *                     hover. 3.83:1 on surface and 3.21:1 on tint in light;
	 *                     8.29:1 and 6.50:1 in dark.
	 *   --opcs-orange-tint-90  the ground under --opcs-ink where an accent must
	 *                     read. Warnings, the public-message flag, a chip.
	 *
	 * --opcs-orange-tint-80 has no users and is kept for the same reason
	 * --opcs-navy-tint-80 is.
	 */
	--opcs-orange-10: #e67900;
	--opcs-orange-20: #c86900;
	--opcs-orange-tint-80: #ffe7cc;
	--opcs-orange-tint-90: #fff3e6;

	/*
	 * ---- Green ----
	 *
	 * Success, and only success. Not a brand colour and not a third accent -
	 * the brand is navy and orange, and green earns its place here by already
	 * being in the shop's vocabulary: these are the exact two values the Ready
	 * for Pickup status carries, seeded in includes/install.php. Reusing them
	 * rather than picking a nicer green means a technician learns one green.
	 *
	 * Mirrored in the Claude Design system project as `--green` and
	 * `--green-tint-90`, bare-prefixed like everything around them, so the
	 * mirror holds in both directions. The status palette they were taken from
	 * is in that project as tokens/app.css.
	 *
	 * The pair measures 4.57:1 in light and 6.38:1 in dark, so the green is
	 * readable on its own tint where a chip needs it to be.
	 */
	--opcs-green: #15803d;
	--opcs-green-tint-90: #dcfce7;

	/*
	 * ---- Red ----
	 *
	 * Added the same way the green was, and for the same reason: these are the
	 * exact two values the Cancelled status carries, seeded in
	 * includes/install.php. Reusing them rather than picking a nicer red means a
	 * technician learns one red, and the shop already reads this one as "this
	 * job is not going the normal way".
	 *
	 * The pair measures 6.80:1 in light and 5.87:1 in dark - which the priority
	 * chip needs, being 10px uppercase and therefore held to the 4.5:1 that
	 * small text is.
	 *
	 * **Note that the app's own error blocks are orange, not red.**
	 * .opcs_list_warning is an orange rule on an orange tint. So this red says
	 * "cancelled, or urgent" rather than "something went wrong", and a new
	 * failure message should still reach for the orange one.
	 *
	 * Mirrored in the Claude Design system project, in tokens/colors.css and
	 * beside the green, so the mirror holds in both directions.
	 *
	 * **There is no prefix to straighten.** A note here used to say these two
	 * carried the plugin's `opcs-` prefix in that file while navy, orange and
	 * the neutrals were bare, and flagged the mismatch as work owed. They were
	 * not in that file at all - the note recorded an intention rather than what
	 * was there - and when they did land they landed bare, like everything
	 * around them. Nothing to rename, and a reminder that a claim about the
	 * other side of a mirror is worth checking before it is written down.
	 */
	--opcs-red: #991b1b;
	--opcs-red-tint-90: #fee2e2;

	/*
	 * **The same red, at the lightness it takes to still read as red.**
	 *
	 * --opcs-red above is a *text* colour and its darkness is the whole reason
	 * it works there. Put that same value down as an eight-pixel bar and the
	 * shop reads it as **brown** - which is not a quibble, it is what happened
	 * on the board's unheld rail. Dark red over a small area loses its hue
	 * before it loses its contrast.
	 *
	 * This is the mark tier, and it has to clear the 3:1 a meaningful graphic
	 * needs on every ground the board has. Light: 4.83:1 on a card, 4.43:1 on a
	 * column, 4.04:1 on a hovered card. Dark: 6.08:1, 3.22:1 against the palest
	 * column, 4.76:1 hovered.
	 *
	 * **Not --opcs-red-10 or -20**, because in this file those numbers go
	 * *darker* - see the orange scale - and darker is the failure being fixed.
	 * It is named for its job instead, the way --opcs-ink-quiet is.
	 */
	--opcs-red-mark: #dc2626;      /* Red as a graphic, not as text */

	/*
	 * **Red as a solid ground, which is a third job again.** The "do not serve"
	 * flag on a reversed customer card is the only user: the tint would vanish
	 * against that panel, so the chip inverts and the red becomes the field.
	 * It carries --opcs-ink-invert, at 8.31:1 - and the same in both themes,
	 * because it sits on the panel that does not change.
	 *
	 * It is a safety notice, so it is the one red that is deliberately loud in
	 * both themes rather than quietening down in either.
	 */
	--opcs-alarm-solid: #991b1b;

	/*
	 * Type. Outfit is the display voice, Montserrat carries body and UI.
	 *
	 * Avada already loads both, so the staff app gets them at no cost. The
	 * public lookup strips Avada's assets and therefore falls back to the system
	 * stack; see the note in public-status.css.
	 */
	--opcs-font-display: "Outfit", system-ui, -apple-system, "Segoe UI", sans-serif;
	--opcs-font-body: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;

	/*
	 * Spacing, 8px base, leaning large.
	 *
	 * In rem, so the scale grows with the reader's own font size rather than
	 * staying put while the text around it gets bigger. The design system's
	 * numbers are the px in the comments; 1rem is 16px, so these are exactly
	 * those values and nothing has moved.
	 */
	--opcs-space-1: 0.25rem;   /* 4px */
	--opcs-space-2: 0.5rem;    /* 8px */
	--opcs-space-3: 0.75rem;   /* 12px */
	--opcs-space-4: 1rem;      /* 16px */
	--opcs-space-5: 1.5rem;    /* 24px */
	--opcs-space-6: 2rem;      /* 32px */
	--opcs-space-7: 3rem;      /* 48px */

	/*
	 * Radii. The brand is squared and confident: 4-6px on cards, buttons and
	 * inputs. 999px is for pills only - status badges and filter chips - and
	 * never for a panel.
	 *
	 * The pill stays in px, and it is the one radius that should. It is not a
	 * measurement, it is "round this off completely" written as a number larger
	 * than anything it will meet, and in rem it would be a number that grows for
	 * no reason and still means the same thing.
	 */
	--opcs-radius-sm: 0.25rem;   /* 4px */
	--opcs-radius-md: 0.375rem;  /* 6px */
	--opcs-radius-pill: 999px;

	/*
	 * Rules. The 6px orange top rule is the brand's "on" signal.
	 *
	 * **These stay in px, deliberately.** A border is a line on a screen rather
	 * than a length in the text, and the hairline in particular has to land on
	 * one device pixel: 0.0625rem rounds to whatever the browser decides and a
	 * divider that renders at 0 on one machine and 1 on another is worse than
	 * one that never scales. The brand's 6px rule is the same argument - it is a
	 * fixed mark, not a piece of the type.
	 */
	--opcs-rule-top: 6px;
	--opcs-rule-accent: 3px;
	--opcs-border: 1.5px;      /* Component borders */
	--opcs-card-rail: 8px;     /* The board card's ownership rail */
	--opcs-hairline: 1px;      /* Dividers */

	/*
	 * Motion. Short functional transitions only: colour and border on hover and
	 * focus. No bounces, no decorative looping, no scale on press.
	 */
	--opcs-transition: 120ms ease;
}

/*
 * No shadows, no gradients, no blur, no transparency. Those are brand rules
 * rather than preferences, so there is deliberately no token for them: there is
 * no correct value to reach for.
 */

@media (prefers-reduced-motion: reduce) {

	:root {
		--opcs-transition: 0ms;
	}
}

/*
 * ---------------------------------------------------------------------------
 * Dark
 * ---------------------------------------------------------------------------
 *
 * A technician chooses light or dark on their own settings screen, the choice
 * is stored per user, and the server writes it onto the html element as
 * `data-opcs-theme` - so the right palette is in the first paint rather than
 * swapped in by script. Everything below is that palette.
 *
 * **It is a second value for each job, not a second set of tokens.** Every name
 * below already exists above; nothing in staff-app.css knows which theme it is
 * in. That is what the role tokens bought, and it is why there is no
 * `.is_dark` anywhere in the stylesheet.
 *
 * **The /status/ page never gets the attribute and is always light.** It is one
 * page for one stranger and the shop does not control the client for it; see
 * the note at the top of public-status.css. It uses the brand tokens directly
 * rather than the roles, which is why nothing here reaches it.
 *
 * ---- What the palette is made of ----
 *
 * **The grounds are grey, not navy, and that is the shop's call.** The first
 * dark palette ran the navy scale all the way down - the page, the cards, the
 * board columns, every ground a step of #1a3263. It was coherent and it was
 * too much: a whole screen of the brand blue stops reading as the brand and
 * starts reading as a tint somebody forgot to turn off. Navy is the workhorse
 * on white because white is around it.
 *
 * So the grounds are a cool dark grey - enough blue in it to sit beside the
 * brand without arguing, not enough to be navy - and **navy is kept for the one
 * surface that is supposed to be navy.** See below.
 *
 * **--opcs-surface-invert does not appear in this block, and that is the whole
 * idea.** The reversed customer card is the brand's own dark field and it stays
 * exactly what it is in light: #1a3263, white text, muted-read labels, orange
 * links. Against a grey page it reads as *more* of a brand moment than it did
 * against white, because it is now the only navy on the screen.
 *
 * That also deletes a problem the navy version had. When the page was navy the
 * panel had to be *lighter* than it to read as a panel at all, and the brand
 * orange on that lighter navy measured 4.25:1 - a fail on a phone number
 * somebody has to read - so links there needed a lighter orange of their own.
 * With the page grey, the panel keeps the brand navy, the brand orange keeps
 * its 5.14:1, and that token is gone. **A palette that needs fewer exceptions
 * is usually the better palette.**
 *
 * **The ink is not pure white.** #ffffff on a dark ground haloes; a very light
 * grey reads as the same "black text" the light theme has without the glare,
 * and it is still 14.01:1 on the page.
 *
 * ---- What was measured, and what it cost ----
 *
 * Both quiet tiers are pinned by the same ground they are pinned by in light -
 * --opcs-tint, which is the hovered row and the hovered card. ink-quiet clears
 * it at 4.92:1 and ink-quieter at 4.56:1, so the gap between the two is as
 * narrow here as it is in light and for the same reason: **ink-quieter is at
 * the floor in dark too.** Anything quieter needs a different ground.
 *
 * --opcs-ink-on-tint is the one token that had to get brighter than its light
 * counterpart looks comfortable. It sits on a board column, the palest of which
 * in dark is On Deck, and 4.59:1 there is simply what it costs.
 *
 * ---- What does not change ----
 *
 * **The reversed panel, entire.** --opcs-surface-invert, --opcs-ink-invert,
 * --opcs-ink-invert-quiet and --opcs-alarm-solid are all absent below, so the
 * customer card and the "do not serve" flag on it are the same object in both
 * themes.
 *
 * **The technician colours.** They are the shop's own Miro swatches, chosen by
 * the people they belong to, and they arrive inline from technician_swatch()
 * and card_edge_style() where no stylesheet can reach them. They are pale, so
 * on a dark ground they read *better* than they do now - the card rail's 1.52:1
 * to 2.03:1 on white was the worst contrast in the app and it improves. The
 * darker ring drawn around every dot and swatch stops being necessary and stops
 * being harmful at the same time; it is left alone.
 *
 * **The status colours**, which are data the shop can edit, and the orange
 * accent, which is the brand. What changes for a status is how its one stored
 * colour is turned into a ground and an ink - see the block at the foot of
 * staff-app.css, which mixes toward --opcs-tint and white in dark rather than
 * toward white and --opcs-navy-40. Mixed into grey rather than into navy the
 * tints come out more clearly *themselves*, because the ground is no longer
 * pulling every one of them toward blue.
 */
:root[data-opcs-theme="dark"] {
	color-scheme: dark;

	/*
	 * Grounds. 1.28:1 from surface to tint, against light's 1.20:1 - a dark
	 * ground carries less separation per unit of luminance, so it needs a
	 * slightly wider step to read as the same step.
	 *
	 * Cool rather than neutral. A pure grey beside the brand navy reads as a
	 * different material; a few degrees of blue in it reads as the same family
	 * without becoming the brand colour, which is the thing being avoided.
	 */
	--opcs-surface: #1b1d22;
	--opcs-tint: #2d3037;

	/* Ink. 14.01:1 on surface, 10.98:1 on tint. */
	--opcs-ink: #e8eaef;

	/* The hover under a filled control. --opcs-surface on it is 11.47:1. */
	--opcs-ink-strong: #d2d5dc;

	/* On surface 6.28:1 / on tint 4.92:1, and 5.82:1 / 4.56:1. */
	--opcs-ink-quiet: #9a9ea6;
	--opcs-ink-quieter: #94989f;

	/* 4.59:1 against the palest board column, 6.84:1 against the deepest. */
	--opcs-ink-on-tint: #b6bac2;

	/* 1.43:1 against surface; 2.74:1 on tint for the strong rule. */
	--opcs-line: #34383f;
	--opcs-line-strong: #6d727c;

	/*
	 * Orange. The brand orange itself already clears everything on a dark
	 * ground, so these two steps go *lighter* rather than darker - which is the
	 * opposite direction from light, and the reason they are not shared.
	 *
	 * orange-20 stays a step below orange-10 so the priority flame keeps its two
	 * tones: the silhouette is orange-20 at 8.10:1 on a card, the enclosed core
	 * is the brand orange.
	 */
	--opcs-orange-10: #ffb259;
	--opcs-orange-20: #ffa033;
	--opcs-orange-tint-80: #513c1e;
	--opcs-orange-tint-90: #3a2c17;   /* --opcs-ink on it: 11.24:1 */

	/* Green. 8.17:1 on surface, 6.38:1 on its own tint. */
	--opcs-green: #5cc98a;
	--opcs-green-tint-90: #14371f;    /* --opcs-ink on it: 10.93:1 */

	/* Red. 7.10:1 on surface, 5.87:1 on its own tint. */
	--opcs-red: #f28b8b;
	--opcs-red-tint-90: #4a1f1f;      /* --opcs-ink on it: 11.58:1 */

	/*
	 * The mark tier, brightened so it still clears 3:1 on a pale column:
	 * 6.08:1 on a card, 3.22:1 on the palest column, 4.76:1 on a hovered card.
	 */
	--opcs-red-mark: #ff6b6b;
}
