/* ==========================================================================
   Algorix review stand configurator
   One stylesheet. No framework, no external font. Tokens match the main site.
   Order: tokens, reset, primitives, poster, stage, panel, lead, success, foot.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */
:root {
  --navy:       #0a193c;
  --navy-deep:  #060f2a;
  --blue:       #0096ff;
  --blue-ink:   #0a6fcc;
  --blue-ink-hi:#0a78d6;
  --ink:        #0b1530;
  --ink-soft:   #41506e;
  --paper:      #ffffff;
  --tint:       #f3f7ff;
  --line:       #dce4f2;
  --warn-bg:    #fff6e2;
  --warn-line:  #e8b93a;
  --warn-ink:   #6a4a05;

  --radius:     12px;
  --radius-sm:  8px;
  --radius-pill:999px;
  --shadow:     0 18px 50px -22px rgba(8, 17, 40, .45);
  --shadow-sm:  0 2px 8px -2px rgba(8, 17, 40, .22);

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --wrap: 1280px;
  --gap:  1rem;
  --tap:  44px;
  --swatch: 44px;
}

/* very narrow phones: keep five swatches on one row */
@media (max-width: 379px) {
  :root { --swatch: 40px; }
}

/* ------------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: var(--blue-ink); }
a:hover { text-decoration: none; }

h1, h2, h3 {
  line-height: 1.12;
  letter-spacing: -.02em;
  font-weight: 800;
  text-wrap: balance;
}
h1 { font-size: clamp(1.85rem, 6.2vw, 3rem); }
h2 { font-size: clamp(1.45rem, 4.4vw, 2.1rem); }
h3 { font-size: 1.05rem; letter-spacing: 0; }
p, li { overflow-wrap: break-word; }

:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* -------------------------------------------------------------- primitives */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2rem);
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip {
  position: absolute;
  left: .5rem; top: -6rem;
  z-index: 20;
  padding: .7rem 1rem;
  background: var(--navy);
  color: #fff;
  border-radius: var(--radius-sm);
  text-decoration: none;
}
.skip:focus { top: .5rem; }

.lede { color: var(--ink-soft); font-size: 1.05rem; }
.hint { color: var(--ink-soft); font-size: .875rem; line-height: 1.45; margin-top: .4rem; }
.micro { color: var(--ink-soft); font-size: .8125rem; line-height: 1.45; }
.brand { font-weight: 800; letter-spacing: -.02em; color: var(--navy); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: var(--tap);
  padding: .7rem 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  transition: background-color .15s ease, border-color .15s ease, transform .12s ease;
}
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--blue-ink); color: #fff; }
.btn--primary:hover { background: var(--blue-ink-hi); }
.btn--ghost { background: var(--paper); color: var(--blue-ink); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--blue-ink); }
.btn--ghost[aria-pressed="true"] { background: var(--navy); border-color: var(--navy); color: #fff; }
.btn--big { width: 100%; padding: .95rem 1.25rem; font-size: 1.0625rem; }
/* small means less padding and smaller type, never a smaller tap target: it keeps
   the 44px floor it inherits from .btn, because a thumb is the same size either way */
.btn--sm { padding: .4rem .8rem; font-size: .875rem; border-radius: var(--radius-sm); }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* ------------------------------------------------------------------ topbar */
.topbar { background: var(--navy); color: #fff; }
.topbar__in {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem .9rem;
  padding-block: .7rem;
}
.topbar .brand { color: #fff; }
.topbar__note { color: rgba(255, 255, 255, .7); font-size: .8125rem; }

/* ====================================================== 1. POSTER, first paint */
.poster { background: linear-gradient(180deg, var(--tint), var(--paper) 70%); }
.poster__in { display: grid; gap: 1.25rem; padding-block: clamp(1.25rem, 5vw, 3.5rem); }

.poster__shot {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--tint);
  box-shadow: var(--shadow);
  /* small phones get a smaller shot, so the headline and the price are in reach */
  width: min(100%, 280px);
  margin-inline: auto;
}
.poster__shot img { width: 100%; }

.poster__copy > * + * { margin-top: .9rem; }

.proof { list-style: none; padding: 0; display: grid; gap: .45rem; }
.proof li { position: relative; padding-left: 1.6rem; }
.proof li::before {
  content: "";
  position: absolute;
  left: 0; top: .55em;
  width: .7rem; height: .7rem;
  border-radius: 50%;
  background: var(--blue);
}

.price {
  border: 1px solid var(--line);
  border-left: 4px solid var(--blue);
  border-radius: var(--radius);
  background: var(--paper);
  padding: 1rem 1.1rem;
}
.price__main { font-size: 1.1rem; font-weight: 600; }
.price__main strong { font-size: 1.5rem; font-weight: 800; color: var(--navy); }
.price__sub { color: var(--ink-soft); font-size: .9rem; margin-top: .3rem; }

/* main.js adds .started to <body> when the start button is pressed.
   The :has() rule is a safety net: if the script only unhides #app, the poster
   still gets out of the way. */
body.started .poster { display: none; }
body:has(#app:not([hidden])) .poster { display: none; }

/* ================================================================ workspace */
.app { background: var(--tint); border-top: 1px solid var(--line); }
.workspace { display: grid; gap: 1.5rem; padding-block: clamp(1.25rem, 4vw, 2.5rem); }

/* ------------------------------------------------------------- 2. 3D stage */
/* The stand is the whole point, so the preview pins to the top of the viewport
   on every screen and the swatch rows scroll underneath it. Without this a
   phone hides the stand the moment the first colour row is reached. */
.stage {
  position: sticky;
  top: 0;
  z-index: 5;
  display: grid;
  gap: .6rem;
  background: var(--tint);
  padding-block: .5rem .9rem;
}

/* Whatever scrolls under the pinned stage has to dissolve, not be sliced. Without
   this the opaque bottom edge cuts a swatch or a font chip clean in half on nearly
   every scroll. 2rem is about the height of one swatch, so a circle fades out over
   its own height. At rest the fade covers the workspace gap, which is the same
   tint, so it cannot be seen. */
.stage::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 100%;
  height: 2rem;
  background: linear-gradient(var(--tint), transparent);
  pointer-events: none;
}

/* 42svh leaves the pinned frame at roughly the top 40 percent of a phone, so a
   swatch row and its label still fit below it. */
.stage__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  max-height: 42vh;
  max-height: 42svh;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, #ffffff 0%, #e9f0fb 55%, #dbe6f6 100%);
}

.stage__frame canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

.stage__status {
  position: absolute;
  inset: auto 0 0 0;
  padding: .5rem .8rem;
  font-size: .8125rem;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, .82);
  text-align: center;
}
.stage__status:empty { display: none; }

.stage__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}
.stage__hint { color: var(--ink-soft); font-size: .8125rem; }

/* The pinned stage sits over the top of a phone screen, so anything the browser
   scrolls to by itself (a field taking focus, a swatch the page jumps to) has to
   clear it. The frame plus the button bar is the 42svh cap plus about 7rem. */
.panel :is(input, select, button) {
  scroll-margin-top: calc(42vh + 7rem);
  scroll-margin-top: calc(42svh + 7rem);
}

/* -------------------------------------------------------- 3. controls panel */
.panel {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem;
  display: grid;
  gap: 1.15rem;
  align-content: start;
}

.group-title {
  padding-top: .35rem;
  border-top: 1px solid var(--line);
  color: var(--navy);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-size: .8125rem;
}

.field { border: 0; padding: 0; min-width: 0; }
.field > label,
.field > legend {
  display: block;
  padding: 0;
  font-weight: 700;
  font-size: .9375rem;
  margin-bottom: .45rem;
}
.field--split { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
.field--split label { display: block; font-weight: 700; font-size: .9375rem; margin-bottom: .45rem; }

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
select,
textarea {
  width: 100%;
  min-height: var(--tap);
  padding: .6rem .75rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 1rem; /* 16px keeps iOS from zooming on focus */
}
textarea { min-height: 5rem; resize: vertical; }
input:hover, select:hover, textarea:hover { border-color: #b9c8e2; }
input::placeholder, textarea::placeholder { color: #8a97b2; }

input[type="file"] {
  width: 100%;
  font-size: .875rem;
  padding: .55rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
  background: var(--tint);
}
input[type="file"]::file-selector-button {
  margin-right: .6rem;
  padding: .45rem .8rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
  color: var(--blue-ink);
  font-weight: 700;
  cursor: pointer;
}

.sub-label { display: block; font-weight: 600; font-size: .875rem; margin: .6rem 0 .35rem; }

.check { display: flex; align-items: center; gap: .55rem; margin-top: .7rem; font-size: .9375rem; }
.check input { width: 1.15rem; height: 1.15rem; accent-color: var(--blue-ink); }

/* font chips. ui.js creates the buttons, so style off the guaranteed hook. */
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip,
[data-test^="font-"] {
  min-height: var(--tap);
  padding: .5rem .9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--paper);
  color: var(--ink);
  font-weight: 600;
  font-size: .9375rem;
  line-height: 1.2;
}
.chip:hover,
[data-test^="font-"]:hover { border-color: var(--blue-ink); }
.chip[aria-pressed="true"], .chip.is-selected, .chip.selected,
[data-test^="font-"][aria-pressed="true"],
[data-test^="font-"][aria-checked="true"],
[data-test^="font-"][data-selected],
[data-test^="font-"].is-selected,
[data-test^="font-"].selected {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}

/* colour swatches. Same idea: ui.js creates them, the data-test hook is the contract.
   An inline background colour set by the JS overrides the fallback below. */
.swatches { display: flex; flex-wrap: wrap; gap: .5rem; }
.swatch,
[data-test^="swatch-"] {
  position: relative;
  width: var(--swatch);
  height: var(--swatch);
  padding: 0;
  border: 1px solid rgba(11, 21, 48, .28);
  border-radius: 50%;
  background: var(--sw, var(--paper));
  box-shadow: inset 0 -6px 12px -8px rgba(0, 0, 0, .55);
}
.swatch:hover,
[data-test^="swatch-"]:hover { border-color: var(--navy); }

.swatch[aria-pressed="true"], .swatch.is-selected, .swatch.selected,
[data-test^="swatch-"][aria-pressed="true"],
[data-test^="swatch-"][aria-checked="true"],
[data-test^="swatch-"][data-selected],
[data-test^="swatch-"].is-selected,
[data-test^="swatch-"].selected {
  box-shadow: 0 0 0 3px var(--paper), 0 0 0 5px var(--blue-ink);
}

.swatch:disabled, .swatch[aria-disabled="true"],
[data-test^="swatch-"]:disabled,
[data-test^="swatch-"][aria-disabled="true"] {
  cursor: not-allowed;
  opacity: .3;
}
/* a bar across any swatch the print rules have ruled out */
.swatch:disabled::after, .swatch[aria-disabled="true"]::after,
[data-test^="swatch-"]:disabled::after,
[data-test^="swatch-"][aria-disabled="true"]::after {
  content: "";
  position: absolute;
  left: 12%; right: 12%; top: 50%;
  height: 2px;
  background: var(--ink);
  transform: rotate(-45deg);
}

.unlock {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  margin-bottom: .55rem;
  padding: .35rem .75rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--tint);
  color: var(--blue-ink);
  font-size: .875rem;
  font-weight: 600;
}
.unlock:hover { border-color: var(--blue-ink); }
.unlock[aria-pressed="true"] { background: var(--paper); color: var(--ink); }

/* warnings */
.warnings:empty { display: none; }
[data-test="warn-contrast"],
.warn {
  display: block;
  padding: .7rem .85rem;
  border: 1px solid var(--warn-line);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  background: var(--warn-bg);
  color: var(--warn-ink);
  font-size: .875rem;
  line-height: 1.45;
}
[data-test="warn-contrast"] + [data-test="warn-contrast"],
.warn + .warn { margin-top: .5rem; }
/* a warning the script drops straight into the page still needs gutters */
body > .warn { max-width: 640px; margin: 1rem auto; }
.lead .warn { margin-top: 1.25rem; }

/* filament budget */
.filament {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .7rem .85rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--tint);
}
.filament__label { font-weight: 700; font-size: .9375rem; }
.filament__count {
  padding: .15rem .6rem;
  border-radius: var(--radius-pill);
  background: var(--navy);
  color: #fff;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.filament.is-full .filament__count { background: #a4460f; }

/* sticky call to action */
.cta-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: grid;
  gap: .35rem;
  justify-items: center;
  margin: 0 -1.1rem -1.1rem;
  padding: .75rem 1.1rem calc(.75rem + env(safe-area-inset-bottom));
  /* Fully opaque, same paper as the panel. Anything translucent here lets the
     swatches scrolling underneath ghost through the button. */
  background: var(--paper);
  border-top: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
}
.cta-bar__price { color: var(--ink-soft); font-size: .8125rem; }

/* ============================================================ 4. lead form */
.lead { background: var(--paper); border-top: 1px solid var(--line); }
.lead__in { padding-block: clamp(1.5rem, 5vw, 3rem); max-width: 640px; margin-inline: auto; }
.lead__in > h2 + .lede { margin-top: .5rem; }
.lead form { display: grid; gap: 1rem; margin-top: 1.5rem; }
.lead__foot { display: grid; gap: .6rem; }

/* honeypot: out of sight, out of the tab order, and it must stay empty */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ============================================================== 5. success */
.success { background: var(--navy); color: #fff; }
.success__in { padding-block: clamp(2rem, 6vw, 3.5rem); max-width: 640px; margin-inline: auto; }
.success__in > * + * { margin-top: .9rem; }
.success h2 { color: #fff; }
.success .lede { color: rgba(255, 255, 255, .8); }
.success .price__main strong { color: var(--blue); }
.success a { color: #9ed3ff; }
/* the download link is an <a> wearing .btn, and the pale link blue above outranks
   .btn--primary, which left it as underlined 3.2:1 text on the blue button. Two
   classes beat one class plus an element, so this wins wherever it sits. */
.success .btn { color: #fff; text-decoration: none; }

/* ================================================================== footer */
.foot { background: var(--navy-deep); color: rgba(255, 255, 255, .78); }
.foot__in { padding-block: 1.75rem; display: grid; gap: .3rem; }
.foot .brand { color: #fff; font-size: 1.1rem; }
.foot a { color: #9ed3ff; }
.foot .micro { color: rgba(255, 255, 255, .55); margin-top: .5rem; }

.noscript {
  padding-block: 1.25rem;
  color: var(--ink);
}

/* ============================================================== wide screens */
@media (min-width: 700px) {
  .poster__in {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    align-items: center;
    gap: clamp(1.5rem, 4vw, 3rem);
  }
  .poster__shot { width: 100%; }
  .btn--big { width: auto; min-width: 15rem; }
  .lead form { grid-template-columns: 1fr 1fr; }
  .lead .field:nth-child(n + 5),
  .lead .lead__foot { grid-column: 1 / -1; }
}

@media (min-width: 980px) {
  .workspace {
    grid-template-columns: minmax(0, 1fr) minmax(340px, 400px);
    align-items: start;
    gap: 1.75rem;
  }
  .stage { top: 1rem; }
  /* Beside the panel now, not above it, so nothing has to be cleared. */
  .panel :is(input, select, button) { scroll-margin-top: 1rem; }
  /* The stand is portrait, so desktop keeps the same 4 / 5 frame as the phone.
     Only the cap changes: the viewport less the topbar, the workspace padding
     and the button bar, which keeps the whole sticky stage on screen. */
  .stage__frame {
    max-height: calc(100vh - 9rem);
    max-height: calc(100svh - 9rem);
  }
  .panel { padding: 1.4rem; }
  .cta-bar { margin: 0 -1.4rem -1.4rem; padding-inline: 1.4rem; }
}

/* ================================================================ contrast */
@media (prefers-contrast: more) {
  :root { --line: #7c8db0; --ink-soft: #2b3550; }
}

/* ================================================================== hidden
   Last in the file on purpose, so it beats every display rule above it without
   needing !important. That leaves the JS free to override with an inline style
   if it ever wants to, though removing the hidden attribute is the way. */
[hidden] { display: none; }
.swatches[hidden], .chips[hidden], .filament[hidden], .cta-bar[hidden] { display: none; }

