/*
 * Palette for www.openpower.tools.
 *
 * Dark (the default) is derived from the Worcester colours: Pear Black
 * #020202, Diglis Deep Blue #334D70, Hive Gold #D7BD44, Cathedral Stone
 * #DCCAA4 and Saucy Orange #EB6424 (Elgar Bronze #5C2119 only works on light
 * backgrounds and is left out). Light is derived
 * from the six Nottingham colours: Sherwood Forest #30544A, Tramway Teal
 * #1E8477, Minted Pea Green #8CB531, Lace White #E9F0F8, Cave Sandstone
 * #C6B49E and Chopper Orange #E75019. Where a pair fails WCAG AA, a tint or
 * shade of the same hue is used instead. crates/op-site/src/palette.rs checks
 * every text/background pair in `cargo test`; keep the two light blocks
 * identical (the same test enforces that).
 *
 * Token roles:
 *   --op-text, --op-muted, --op-link, --op-link-hover  text: 4.5:1 on bg/surface
 *   --op-accent, --op-focus, --op-border-strong        UI: 3:1 on bg/surface
 *     (dark: orange is the interaction colour, gold the link colour)
 *   --op-raised                                        lifted background (callout fills);
 *     text, links and status labels keep 4.5:1 on it
 *   --op-pole-base                                     decoration only (barberpole mix
 *     target: black in dark, white in light)
 *   --op-status-{info,ok,warning,danger}               text: 4.5:1 on bg/raised; UI: 3:1 on surface
 *     (one hue per meaning in both themes: callout labels and stripes,
 *     badge and timeline dots; neutral is UI-only at 3:1)
 *   --op-highlight                                     decoration only (title rule)
 *   --op-border                                        decoration only
 *
 * With no stored choice the theme follows the system preference; the toggle
 * flips dark and light and stores the choice, mirrored as
 * <html data-theme="dark"> or "light". The .opt-theme-dark and .opt-theme-light
 * classes scope a token set to a subtree, which the specimen uses to show
 * both themes side by side.
 */

:root,
.opt-theme-dark {
  color-scheme: dark;

  --op-bg: #020202;
  --op-surface: #2B415F;
  --op-text: #DCCAA4;
  --op-muted: #ADB8C6;
  --op-link: #E6D27A;
  --op-link-hover: #D7BD44;
  --op-accent: #EB6424;
  --op-highlight: #EB6424;
  --op-focus: #EB6424;
  --op-border: #334D70;
  --op-border-strong: #8F9DB0;
  --op-code-bg: #1A2738;

  --op-status-neutral: #8F9DB0;
  --op-status-info: #7FB0DE;
  --op-status-ok: #97C264;
  --op-status-warning: #E0A458;
  --op-status-danger: #E4756A;

  --op-raised: #131A26;
  --op-pole-base: #000000;

  /* Chart series: Okabe-Ito hues fitted in two OKLCH lightness bands, tested in palette.rs. */
  /* orange */
  --op-series-1: #E7A000;
  /* bluish green */
  --op-series-2: #49F3BA;
  /* blue */
  --op-series-3: #ABD9FF;
  /* reddish purple */
  --op-series-4: #F682C5;
  /* sky blue */
  --op-series-5: #37BCFF;
  /* olive */
  --op-series-6: #E3D846;
  --op-band: #3A445A;
  --op-playhead: #EB6424;
  --op-peek: #ADB8C6;
}

/* No explicit choice: follow the system. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --op-bg: #E9F0F8;
    --op-surface: #FFFFFF;
    --op-text: #30544A;
    --op-muted: #635A4F;
    --op-link: #145A51;
    --op-link-hover: #1A7065;
    --op-accent: #E75019;
    --op-highlight: #8CB531;
    --op-focus: #1E8477;
    --op-border: #C6B49E;
    --op-border-strong: #8B7E6F;
    --op-code-bg: #DDE4EC;

  --op-status-neutral: #8B7E6F;
  --op-status-info: #2F6DA8;
  --op-status-ok: #447114;
  --op-status-warning: #8A6207;
  --op-status-danger: #B03A30;

  --op-raised: #FFFFFF;
  --op-pole-base: #FFFFFF;

  /* Chart series: Okabe-Ito hues fitted in two OKLCH lightness bands, tested in palette.rs. */
  /* orange */
  --op-series-1: #8F6200;
  /* bluish green */
  --op-series-2: #009C73;
  /* blue */
  --op-series-3: #008BD8;
  /* reddish purple */
  --op-series-4: #A93C7F;
  /* sky blue */
  --op-series-5: #0074A4;
  /* olive */
  --op-series-6: #918800;
  --op-band: #FDF1ED;
  --op-playhead: #E75019;
  --op-peek: #635A4F;
  }
}

:root[data-theme="light"],
.opt-theme-light {
  color-scheme: light;

  --op-bg: #E9F0F8;
  --op-surface: #FFFFFF;
  --op-text: #30544A;
  --op-muted: #635A4F;
  --op-link: #145A51;
  --op-link-hover: #1A7065;
  --op-accent: #E75019;
  --op-highlight: #8CB531;
  --op-focus: #1E8477;
  --op-border: #C6B49E;
  --op-border-strong: #8B7E6F;
  --op-code-bg: #DDE4EC;

  --op-status-neutral: #8B7E6F;
  --op-status-info: #2F6DA8;
  --op-status-ok: #447114;
  --op-status-warning: #8A6207;
  --op-status-danger: #B03A30;

  --op-raised: #FFFFFF;
  --op-pole-base: #FFFFFF;

  /* Chart series: Okabe-Ito hues fitted in two OKLCH lightness bands, tested in palette.rs. */
  /* orange */
  --op-series-1: #8F6200;
  /* bluish green */
  --op-series-2: #009C73;
  /* blue */
  --op-series-3: #008BD8;
  /* reddish purple */
  --op-series-4: #A93C7F;
  /* sky blue */
  --op-series-5: #0074A4;
  /* olive */
  --op-series-6: #918800;
  --op-band: #FDF1ED;
  --op-playhead: #E75019;
  --op-peek: #635A4F;
}

/*
 * Theme easing. The toggle arms <html data-op-theme-easing> for the
 * duration of a click's palette blend. The colour tokens are registered
 * as typed <color> properties (which is what lets them interpolate at
 * all); while the attribute is present they transition on an
 * exponential curve - barely moving at first, committing at the end -
 * so a second click inside the window aborts: the reversal replays from
 * wherever the blend was, shortened in proportion (CSS transition
 * reversing). Browsers lacking property registration ignore these
 * rules and flip instantly, which keeps the abort semantics true. Each
 * initial-value carries the dark palette (the :root default); a test in
 * op-site keeps the registrations, the :root declarations and the
 * transition-property list identical, and the duration in step with the
 * toggle's timer.
 */
@property --op-bg { syntax: "<color>"; inherits: true; initial-value: #020202; }
@property --op-surface { syntax: "<color>"; inherits: true; initial-value: #2B415F; }
@property --op-text { syntax: "<color>"; inherits: true; initial-value: #DCCAA4; }
@property --op-muted { syntax: "<color>"; inherits: true; initial-value: #ADB8C6; }
@property --op-link { syntax: "<color>"; inherits: true; initial-value: #E6D27A; }
@property --op-link-hover { syntax: "<color>"; inherits: true; initial-value: #D7BD44; }
@property --op-accent { syntax: "<color>"; inherits: true; initial-value: #EB6424; }
@property --op-highlight { syntax: "<color>"; inherits: true; initial-value: #EB6424; }
@property --op-focus { syntax: "<color>"; inherits: true; initial-value: #EB6424; }
@property --op-border { syntax: "<color>"; inherits: true; initial-value: #334D70; }
@property --op-border-strong { syntax: "<color>"; inherits: true; initial-value: #8F9DB0; }
@property --op-code-bg { syntax: "<color>"; inherits: true; initial-value: #1A2738; }
@property --op-status-neutral { syntax: "<color>"; inherits: true; initial-value: #8F9DB0; }
@property --op-status-info { syntax: "<color>"; inherits: true; initial-value: #7FB0DE; }
@property --op-status-ok { syntax: "<color>"; inherits: true; initial-value: #97C264; }
@property --op-status-warning { syntax: "<color>"; inherits: true; initial-value: #E0A458; }
@property --op-status-danger { syntax: "<color>"; inherits: true; initial-value: #E4756A; }
@property --op-raised { syntax: "<color>"; inherits: true; initial-value: #131A26; }
@property --op-pole-base { syntax: "<color>"; inherits: true; initial-value: #000000; }
@property --op-series-1 { syntax: "<color>"; inherits: true; initial-value: #E7A000; }
@property --op-series-2 { syntax: "<color>"; inherits: true; initial-value: #49F3BA; }
@property --op-series-3 { syntax: "<color>"; inherits: true; initial-value: #ABD9FF; }
@property --op-series-4 { syntax: "<color>"; inherits: true; initial-value: #F682C5; }
@property --op-series-5 { syntax: "<color>"; inherits: true; initial-value: #37BCFF; }
@property --op-series-6 { syntax: "<color>"; inherits: true; initial-value: #E3D846; }
@property --op-band { syntax: "<color>"; inherits: true; initial-value: #3A445A; }
@property --op-playhead { syntax: "<color>"; inherits: true; initial-value: #EB6424; }
@property --op-peek { syntax: "<color>"; inherits: true; initial-value: #ADB8C6; }

:root[data-op-theme-easing] {
  transition-property: --op-bg, --op-surface, --op-text, --op-muted,
    --op-link, --op-link-hover, --op-accent, --op-highlight, --op-focus,
    --op-border, --op-border-strong, --op-code-bg, --op-status-neutral,
    --op-status-info, --op-status-ok, --op-status-warning,
    --op-status-danger, --op-raised, --op-pole-base, --op-series-1,
    --op-series-2, --op-series-3, --op-series-4, --op-series-5, --op-series-6,
    --op-band, --op-playhead, --op-peek;
  transition-duration: var(--op-motion-blend);
  transition-timing-function: var(--op-motion-blend-curve);
}

/*
 * Motion tokens. Every timed effect on the site reads its clock from
 * here. Custom properties inherit through shadow roots, so a
 * component's shadow stylesheet and the palette blend above share one
 * duration and one curve without any value being copied (op-site's
 * motion module pins these values by test). The blend's curve is a
 * true exponential, (2^(6t)-1)/63, where linear() exists, and a
 * shape-preserving bezier elsewhere. The blend is a colour fade, not
 * motion, so reduced motion leaves it alone; snaps collapse to nothing
 * there, and preview loops are replaced by a static preview in the
 * parts that play them.
 */
:root {
  --op-motion-snap: 160ms;
  --op-motion-fade: 250ms;
  --op-motion-preview: 1.6s;
  --op-motion-blend: 3s;
  --op-motion-blend-curve: cubic-bezier(0.9, 0.05, 0.85, 0.3);
}

@supports (animation-timing-function: linear(0, 1)) {
  :root {
    --op-motion-blend-curve: linear(0, 0.008 10%, 0.021 20%, 0.039 30%, 0.068 40%, 0.111 50%, 0.177 60%, 0.276 70%, 0.426 80%, 0.654 90%, 0.809 95%, 1);
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --op-motion-snap: 0s;
  }
}

/* Font tokens: candidates are compared on /specimen/; the site default is
   chosen there. Every webfont is embedded in the wasm binary and registered
   through the CSS Font Loading API (crates/op-site/src/fonts.rs); the
   stylesheet declares no font sources at all. Stacks always end in a system
   fallback for the no-wasm case. */
:root {
  /* Option E from /specimen/: Sys (Space Grotesk for the public) headings,
     IBM Plex Sans body, PragmataPro Liga (Iosevka for the public) code. */
  /* Order: the embedded faces (registered from the font pack), then the
     metric-fitted local() fallbacks, then a generic tail. Locally installed
     fonts are deliberately absent: everyone gets the same rendering. */
  --op-font-sans: "IBM Plex Sans", "opt-body-fallback", system-ui, sans-serif;
  --op-font-heading: "Barlow Semi Condensed", "opt-heading-fallback", system-ui, sans-serif;
  --op-font-mono: "Iosevka SS08", "opt-mono-fallback", ui-monospace, monospace;
}

/* The metric-fitted local() fallback faces (opt-heading-fallback,
   opt-body-fallback, opt-mono-fallback) live in a stylesheet generated at build
   time by crates/op-assets, which computes every size-adjust and box override
   from the actual font tables so the numbers can never go stale. */

/* Base styles for the light DOM; shadow roots carry their own. */

html {
  background: var(--op-bg);
  color: var(--op-text);
  font-family: var(--op-font-sans);
  line-height: 1.5;
}

body {
  max-width: 40rem;
  margin: 0 auto;
  padding: 2rem 1rem;
}

a {
  color: var(--op-link);
}

a:hover {
  color: var(--op-link-hover);
}

:focus-visible {
  outline: 2px solid var(--op-focus);
  outline-offset: 2px;
}

h1,
h2,
h3 {
  font-family: var(--op-font-heading);
  letter-spacing: var(--op-heading-fallback-tracking, 0em);
}

main p {
  margin: 0.5rem 0;
}

main ul {
  margin: 0;
  padding-left: 1.25rem;
}

main li {
  margin: 0.25rem 0;
}

code,
pre {
  font-variant-ligatures: contextual;
}

/* Pre-rendered elements ship their shadow root as a declarative template.
   An engine that parses it attaches the tree and this rule never applies; an
   engine that does not leaves an inert template, whose children are inert by
   construction, so the rule only helps engines that expose them at all. It is
   not the fallback: declarative shadow roots are Baseline 2024, and the real
   fallback is the light DOM the element keeps beside the template. */

:not(:defined) > template[shadowrootmode] {
  display: block;
}

/* Innards of the light-DOM content components. Shadow CSS reaches only the
   directly slotted element (::slotted), so what sits inside a slotted list or
   table is styled here, with the same tokens. */

opt-key-value dt {
  color: var(--op-muted);
}

opt-key-value dd {
  margin: 0;
}

opt-table th,
opt-table td {
  padding: 0.4rem 0.75rem;
  text-align: left;
}

opt-table th {
  color: var(--op-muted);
  font-weight: 600;
  border-bottom: 1px solid var(--op-border-strong);
}

/* Row rules are opt-in: alignment and spacing carry an airy table on their
   own; lined earns its ink on long or dense reference tables. */
opt-table[lined] td {
  border-bottom: 1px solid var(--op-border);
}

opt-table caption {
  text-align: left;
  color: var(--op-muted);
  font-size: 0.85rem;
  padding-bottom: 0.5rem;
}

opt-table[dense] th,
opt-table[dense] td {
  padding: 0.15rem 0.5rem;
}

/* The dots sit on the line drawn by opt-timeline's shadow at 1.25rem inset. */
opt-timeline li {
  position: relative;
  margin: 0.75rem 0;
}

opt-timeline li::before {
  content: "";
  position: absolute;
  left: -1.25rem;
  top: 0.45em;
  transform: translateX(-50%);
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  background: var(--op-status-neutral);
}

opt-timeline li[data-status="info"]::before {
  background: var(--op-status-info);
}

opt-timeline li[data-status="ok"]::before {
  background: var(--op-status-ok);
}

opt-timeline li[data-status="warning"]::before {
  background: var(--op-status-warning);
}

opt-timeline li[data-status="danger"]::before {
  background: var(--op-status-danger);
}

opt-timeline time {
  display: block;
  font-size: 0.8rem;
  font-family: var(--op-font-mono);
  color: var(--op-muted);
}

/* Form controls: light-DOM labels wrap their native controls (no ids needed),
   the elements provide the box and the selector scope. */

opt-input label,
opt-select label {
  display: block;
  color: var(--op-muted);
  font-size: 0.9rem;
}

opt-input input,
opt-input textarea,
opt-select select {
  display: block;
  box-sizing: border-box;
  width: 100%;
  margin-top: 0.25rem;
  font: inherit;
  color: var(--op-text);
  background: var(--op-bg);
  border: 1px solid var(--op-border-strong);
  border-radius: 0.25rem;
  padding: 0.3rem 0.6rem;
}

opt-input ::placeholder {
  color: var(--op-muted);
  opacity: 1;
}

opt-checkbox label,
opt-switch label {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
}

opt-checkbox input {
  accent-color: var(--op-accent);
  width: 1em;
  height: 1em;
  margin: 0;
}

/* opt-switch: its representation is generated from op-parts by the
   component itself (crates/op-site/src/components/switch.rs). */
/* Breadcrumb and pagination trails are light-DOM lists of links. */

opt-breadcrumb ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  font-size: 0.9rem;
}

/* Separators drawn here stay out of the accessible name. */
opt-breadcrumb li + li::before {
  content: "/";
  color: var(--op-muted);
  margin-right: 0.35rem;
}

opt-breadcrumb [aria-current="page"] {
  color: var(--op-muted);
}

opt-pagination ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
}

opt-pagination a,
opt-pagination .gap {
  display: inline-block;
  min-width: 1.4rem;
  text-align: center;
  padding: 0.2rem 0.5rem;
  border: 1px solid transparent;
  border-radius: 0.25rem;
  text-decoration: none;
}

opt-pagination a:hover {
  border-color: var(--op-accent);
}

opt-pagination [aria-current="page"] {
  border-color: var(--op-border-strong);
}

/* Numbered procedure steps (opt-steps): CSS counters draw the bubbles,
   data-state colours them with the status tokens; the text carries the
   meaning in words. */

opt-steps ol {
  counter-reset: opt-step;
}

opt-steps li {
  counter-increment: opt-step;
  position: relative;
  margin: 0.9rem 0;
  padding-left: 2.5rem;
}

opt-steps li::before {
  content: counter(opt-step);
  position: absolute;
  left: 0;
  top: -0.1rem;
  width: 1.6rem;
  height: 1.6rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--op-border-strong);
  border-radius: 50%;
  font-family: var(--op-font-mono);
  font-size: 0.85rem;
  color: var(--op-muted);
}

opt-steps li:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 0.8rem;
  top: 1.7rem;
  bottom: -1.05rem;
  width: 1px;
  background: var(--op-border);
}

opt-steps li[data-state="done"]::before {
  border-color: var(--op-status-ok);
  color: var(--op-status-ok);
}

opt-steps li[data-state="current"]::before {
  border-color: var(--op-status-info);
  color: var(--op-status-info);
  background: var(--op-raised);
}

opt-steps li[data-state="error"]::before {
  border-color: var(--op-status-danger);
  color: var(--op-status-danger);
}

/* Collapsible hierarchies (opt-tree): native details/summary branches with
   guide lines; the marker turns with the open state. */

opt-tree ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

opt-tree ul ul {
  margin-left: 0.4rem;
  padding-left: 1rem;
  border-left: 1px solid var(--op-border);
}

opt-tree li {
  margin: 0.2rem 0;
}

opt-tree summary {
  cursor: pointer;
  list-style-type: "\25B8  ";
}

opt-tree summary:hover {
  color: var(--op-link-hover);
  background: color-mix(in srgb, var(--op-link-hover) 14%, transparent);
}

opt-tree details[open] > summary {
  list-style-type: "\25BE  ";
}

opt-tree summary::marker {
  color: var(--op-muted);
}

/* The component gallery on /components/: cards of live examples, two-up
   where the column allows. */

.op-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 0 1rem;
  align-items: start;
}

/* The A-Frame scene owns its light-DOM subtree (see op-site scene.rs). */
opt-scene {
  display: block;
  margin: 1rem 0;
  border: 1px solid var(--op-border);
}

opt-scene .loading {
  color: var(--op-muted);
  margin: 1rem;
}

/* Leave room for the fixed theme toggle on narrow screens. */
@media (max-width: 30rem) {
  body {
    padding-top: 3.5rem;
  }
}
