/* Demo Locker brochure.
   Palette, font stack and TUI idiom are copied from packages/web/src/index.css
   so the page and the app read as the same object. Deliberately a copy, not a
   shared build — this page is one static file with no pipeline. If the app's
   accent or font changes, update it here too. */

/* --accent has to be a registered property to be animatable: an unregistered
   custom property has no type, so the browser can only flip it between
   keyframes rather than interpolate through them. With a <color> syntax the
   whole page cross-fades. */
@property --accent {
  syntax: "<color>";
  inherits: true;
  initial-value: #3f6;
}

:root {
  --bg: #0a0a0a;
  --fg: #ffffff;
  --fg-dim: #ccc;
  --accent: #3f6;
  /* derived rather than animated alongside --accent, so the tint can never
     drift out of step with the colour it is a tint of. */
  --accent-dim: color-mix(in srgb, var(--accent) 8%, transparent);
  --border: #282828;
  --font: "Berkeley Mono", "JetBrains Mono", "Fira Code", "SF Mono", monospace;

  /* Every accented thing on the page reads var(--accent) — logo, links, the
     [copy] buttons, the list markers, the prompt-box tint, ::selection — so
     animating the one variable moves all of them in step. 6s per colour across
     the seven accents the app ships, plus a wrap back to the first so the loop
     has no visible seam. */
  animation: accent-cycle 42s linear infinite;
}

/* Ordered around the hue wheel, NOT in the app's ACCENTS order. Registered
   custom properties interpolate in sRGB, and a straight line in sRGB between
   two near-opposite hues runs through grey — the app's order puts amber (32deg)
   next to blue (207deg), and the logo spent a second of every loop a muddy
   khaki. Sorted by hue the largest gap is 87deg (gold to green, through
   yellow-green), so the cycle stays saturated the whole way round. Keep any new
   accent in hue order for the same reason.

   The wheel is entered at green (DL's pick, 2026-07-30) rather than at the
   lowest hue: the list is rotated, not re-sorted, so every adjacent pair — and
   therefore every interpolation — is the one hue order already vetted. The
   brochure resting on green while the app still defaults to gold is deliberate;
   don't "resync" them. */
@keyframes accent-cycle {
  0%      { --accent: #3f6; } /* 135deg green  */
  14.286% { --accent: #6cf; } /* 200deg cyan   */
  28.571% { --accent: #4af; } /* 207deg blue   */
  42.857% { --accent: #a6f; } /* 267deg purple */
  57.143% { --accent: #f6a; } /* 333deg pink   */
  71.429% { --accent: #f80; } /*  32deg amber  */
  85.714% { --accent: #fc0; } /*  48deg gold   */
  100%    { --accent: #3f6; }
}

/* A page-wide colour cycle with no off switch is exactly what this query is
   for. Holding the initial green leaves every accent rule working untouched. */
@media (prefers-reduced-motion: reduce) {
  :root {
    animation: none;
  }
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  background: var(--bg);
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 13px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--accent);
  color: var(--bg);
}

a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

a:hover,
a:focus-visible {
  border-bottom-color: var(--accent);
}

.wrap {
  max-width: 880px;
  margin: 0 auto;
  padding: 2.5rem 1.625rem 4rem;
}

/* ascii logo — sized from its own column count against the container, so it
   fits a phone instead of clipping. Same approach as the app: 100cqw is the
   exact width available, where deriving it from the viewport minus an assumed
   padding is not. Measured glyph width for the font stack is 0.602em. */
/* NB `container-type: inline-size` makes this element's width independent of
   its contents, so it must never sit in a content-sized box — as a flex item it
   would collapse to zero and take the art with it. That shipped in the app once.
   Safe here because it's in a plain block context, but the guard is cheap. */
.ascii-fit {
  container-type: inline-size;
  width: 100%;
  min-width: 0;
}

/* --fit is the fraction of the container the art is allowed to occupy. At 1 it
   spans edge to edge, which on a phone squeezes the glyph cells and lets the
   logo dominate the page — the mobile query below pulls it in. The pre is
   width:fit-content so the art centres inside the leftover space rather than
   hugging the left edge — and that is also what keeps the 4px floor safe. The
   floor binds at and below a 320px viewport, but a fit-content pre shrinks to
   the art instead of the box, so the art stays inside .ascii-fit and nothing
   clips: measured 265px of art in a 268px box at 300px, the narrowest width
   worth supporting. */
.ascii-fit > .ascii-logo {
  --cols: 110;
  --fit: 1;
  font-size: clamp(
    4px,
    calc(100cqw / (var(--cols) * 0.61) * var(--fit)),
    11px
  );
  width: fit-content;
  margin-inline: auto;
}

.ascii-logo {
  color: var(--accent);
  font-family: var(--font);
  line-height: 1.2;
  white-space: pre;
  overflow: hidden;
  user-select: none;
}

.tagline {
  margin-top: 1.75rem;
  font-size: 15px;
  line-height: 1.7;
}

.tagline em {
  color: var(--accent);
  font-style: normal;
}

section {
  margin-top: 3rem;
}

.label {
  color: var(--fg-dim);
  font-size: 11px;
  font-weight: normal;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.25rem;
}

ul.plain {
  list-style: none;
}

ul.plain > li {
  padding: 0.35rem 0;
}

/* the either/or under the recommendation — indented, dimmed, dashes in the
   accent so it reads as a nested aside. */
ul.sub {
  list-style: none;
  margin-top: 0.35rem;
  color: var(--fg-dim);
}

ul.sub li {
  padding-left: 1.5rem;
  text-indent: -1.5rem;
}

ul.sub li::before {
  content: "- ";
  color: var(--accent);
}

ul.plain strong {
  color: var(--accent);
  font-weight: normal;
}

.cta-lead {
  color: var(--fg-dim);
  margin-bottom: 0.9rem;
}

/* the hinge between the two ways in — reads as a second lead-in to the box
   below it, so it matches .cta-lead rather than sitting centred between them. */
.or {
  color: var(--fg-dim);
  margin: 1.75rem 0 0.9rem;
}

/* One screenshot, centred. This was a swipable three-shot strip; the extra
   two were showing the same UI a second and third time, so they earned their
   removal rather than a carousel to hide them in. */
.shot {
  display: block;
  margin: 3rem auto 0;
  width: 100%;
  max-width: 620px;
  height: auto;
  border: 1px solid var(--border);
}

/* the copyable prompt — the main event on this page */
.prompt-box {
  border: 1px solid var(--border);
  background: var(--accent-dim);
  padding: 1rem;
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
}

.prompt {
  font-family: var(--font);
  color: var(--fg);
  font-size: 13px;
  line-height: 1.7;
  white-space: pre-wrap;
  word-break: break-word;
  flex: 1 1 22ch;
  min-width: 0;
}

.btn {
  font-family: var(--font);
  font-size: 13px;
  color: var(--accent);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  white-space: nowrap;
  flex: 0 0 auto;
}

.btn:hover,
.btn:focus-visible {
  color: var(--fg);
}

.btn[data-copied="true"] {
  color: var(--fg);
}

footer {
  margin-top: 4rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

.colophon {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* the icon is the whole link, so it gets no underline rule — the hover cue is
   the color flip instead. line-height:0 keeps the svg from riding above the
   text baseline it sits next to. */
.icon-link {
  border-bottom: none;
  line-height: 0;
  flex: 0 0 auto;
}

.icon-link:hover,
.icon-link:focus-visible {
  color: var(--fg);
  border-bottom: none;
}

@media (max-width: 640px) {
  .wrap {
    padding: 1.75rem 1rem 3rem;
  }
  .tagline {
    font-size: 14px;
  }
  .prompt-box {
    gap: 0.75rem;
  }
  .ascii-fit > .ascii-logo {
    --fit: 0.85;
  }
}
