* { box-sizing: border-box; }

/* The `hidden` attribute is nothing but a UA `display: none`, so any author
   rule carrying its own `display` silently defeats it — `img` just below,
   and every `.thing { display: flex }` in this file. The elements toggled
   with `el.hidden = true` are exactly those. Say it once, here. */
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--sans);
  background: var(--bg);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.mono { font-family: var(--mono); }
button {
  font-family: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}
button:focus-visible, .ribbon:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---- top bar ---- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  height: 46px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  flex: none;
}
.brand { display: flex; align-items: baseline; gap: 14px; min-width: 0; }
/* The wordmark is the way back to the landing page — the viewer otherwise
   has no exit, which is the convention everywhere else and so the first
   place someone looks. */
.brand-mark {
  font-family: var(--mono);
  font-size: 18px;
  letter-spacing: -0.5px;
  color: inherit;
  text-decoration: none;
}
.brand-mark:hover b { color: var(--accent-hi); }
.brand-mark b { color: var(--accent); font-weight: 500; }
.brand-short { display: none; }
.model-name {
  font-size: 14px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* ---- top nav (skewt-look, nav unification) ----
   Sits between .brand and .runinfo, both of which keep their own natural
   width; flex:1 lets .topnav absorb whatever room those two leave rather
   than fighting .topbar's space-between for it, and overflow:hidden clips
   instead of wrapping. That matters here more than on the other pages:
   .topbar's 46px height is baked into #mapImage's own
   `calc(100dvh - 262px)` further down, so a header that grows even one
   line would leave the map too tall for the space actually left for it. */
.topnav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
}
.topnav a {
  font-size: 13.5px;
  text-decoration: none;
  color: var(--muted);
  white-space: nowrap;
  flex: none;
}
.topnav a:hover { color: var(--ink); }
.topnav a[aria-current="page"] { color: var(--ink); font-weight: 600; }
.runinfo { display: flex; align-items: center; gap: 10px; }

/* ---- mobile hamburger nav (skewt-look) ------------------------------------
   `.topnav` (above) vanishes below 820px same as `.sidebar` does, and this
   replaces it -- an `.icon-btn` sized exactly like the settings gear right
   beside it, so the 46px `.topbar` this feeds `#mapImage`'s own
   `calc(100dvh - 262px)` never grows a pixel. `.nav-menu` reuses
   `.run-menu`'s own box (position:absolute, so it overlays rather than
   pushing the stage down) and only adds its own link styling -- the run
   selector's menu holds buttons, this one real `<a>` links. Hidden above
   820px: `.topnav` already carries the nav there. */
.nav-select { position: relative; display: none; }
@media (max-width: 820px) { .nav-select { display: inline-flex; } }
/* No min-width override here: .run-menu's own 300px (below, "run selector")
   already fits five short links comfortably and wins the cascade anyway --
   it is declared later in this file, so a smaller number here would be
   dead weight, not a real narrower panel. */
.nav-menu a {
  display: block; padding: 8px 10px; font-size: 13.5px;
  text-decoration: none; color: var(--ink); border-radius: 4px;
}
.nav-menu a:hover { background: var(--panel-hover); }
.nav-menu a[aria-current="page"] { color: var(--accent-hi); font-weight: 500; }
.runinfo .mono { font-size: 13.5px; color: var(--muted); }
/* Run age is worn by the init text itself (Ivan, 2026-08-02: the dot
   cost topbar space the mobile nav needs). Same three colours the dot
   carried; the classes land on #runLabel (app.js). */
.runinfo .mono.run-fresh { color: var(--fresh); }
.runinfo .mono.run-aging { color: var(--aging); }
.runinfo .mono.run-stale { color: var(--stale); }
.auth-btn {
  font-size: 13.5px;
  font-weight: 500;
  padding: 5px 12px;
  border-radius: 4px;
  background: var(--accent);
  color: var(--on-accent);
}
.auth-btn:hover { background: var(--accent-hi); }
.auth-btn.signed { background: none; border: 1px solid var(--line); color: var(--muted); font-weight: 400; }
.auth-btn.signed:hover { border-color: var(--stale); color: var(--stale); }
.premium-badge {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 1px;
  padding: 3px 7px;
  border-radius: 3px;
  color: var(--badge-ink);
  background: var(--badge-bg);
  border: 1px solid var(--badge-line);
}

/* ---- layout ---- */
.layout { display: flex; flex: 1; min-height: 0; }

/* ---- sidebar ---- */
.sidebar {
  /* Fluid, sized around the map rather than around the viewport. The map's
     natural width is 1180px and the stage adds 24px of padding plus this
     border, so 1205px is reserved and the sidebar takes whatever is left,
     between 280 and 470.

     Consequence: the map reaches 1:1 at a 1485px window and never shrinks
     again as the window grows, while the buttons widen smoothly from 120px
     of text to 215px. The old fixed 340px with a 3-column breakpoint at
     1560px did the opposite — crossing it widened the sidebar by 130px and
     made a 1600px monitor show a *smaller* map than a 1536px one, with
     narrower buttons into the bargain. */
  width: clamp(280px, calc(100vw - 1205px), 470px);
  flex: none;
  background: var(--panel);
  border-right: 1px solid var(--line);
  overflow-y: auto;
  padding: 10px 0 30px;
}
.group-title {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--muted);
  padding: 14px 16px 5px;
}
/* A row, not a block: the name truncates on its own while the padlock stays
   put. Ellipsis on the button itself ate the padlock first, since it sits
   last — and a premium product that does not look premium is the one thing
   this button has to get right. */
.product-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  text-align: left;
  font-size: 13.5px;
  padding: 5px 16px;
  border-left: 3px solid transparent;
}
.product-name {
  min-width: 0;                 /* without this a flex item refuses to shrink */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.product-btn:hover { background: var(--panel-hover); }
.product-btn.active {
  border-left-color: var(--accent);
  background: var(--panel-active);
  font-weight: 500;
  color: var(--active-ink);
}
.sidebar-search {
  display: block;
  width: calc(100% - 24px);
  margin: 10px 12px 0;
  font: inherit;
  font-size: 13.5px;
  padding: 6px 9px;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 5px;
}
.sidebar-search:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.no-matches { font-size: 13.5px; color: var(--muted); padding: 12px 16px; grid-column: 1 / -1; }

/* two-column product grid (desktop sidebar); group titles span both columns */
#productNav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 2px;
}
#productNav .group-title { grid-column: 1 / -1; }
#productNav .product-btn {
  white-space: nowrap;
  overflow: hidden;
  font-size: 12.5px;
  padding: 5px 8px;             /* trimmed to buy back text width */
}

/* ---- stage column ---- */
.stage-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.sectorbar {
  display: flex;
  gap: 4px;
  padding: 8px 12px 4px;
  overflow-x: auto;
  flex: none;
  scrollbar-width: none;
}
.sector-btn {
  font-size: 13.5px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--muted);
  white-space: nowrap;
}
.sector-btn:hover { border-color: var(--accent); color: var(--accent); }
.sector-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.sector-gap { width: 10px; flex: none; }

/* ---- stage ---- */
.stage {
  position: relative;
  overflow: hidden;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 12px;
}
#mapImage {
  max-width: 100%;
  will-change: transform;
  max-height: 100%;
  box-shadow: 0 1px 4px var(--shadow-1);
  background: var(--map-bg);
  user-select: none;
  /* The map owns its gestures (js/mapzoom.js), so the browser gets none.
     Every touch-action value that let the browser pan a zoomed map also made
     it claim horizontal drags at fit-to-screen, which killed swipe-to-step;
     there is no value that expresses "pan only when zoomed". */
  touch-action: none;
  transform-origin: center center;
}
.stage-msg {
  position: absolute;
  font-size: 15px;
  color: var(--muted);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 14px 22px;
}

[data-theme="dark"] #mapImage {
  filter: brightness(0.88) saturate(0.97);
}
@media (hover: hover) and (pointer: fine) {
  [data-theme="dark"] #mapImage:hover { filter: none; }
}

/* ---- controls ---- */
.controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 12px;
  flex: none;
}
.transport { display: flex; gap: 2px; }
.transport button {
  min-width: 34px;
  height: 30px;
  font-size: 15px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--ink);
}
.transport button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.transport button:disabled { opacity: 0.35; cursor: default; }
.transport button.playing { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.transport .speed { font-size: 13px; }
.readout {
  font-size: 14px;
  color: var(--ink);
  white-space: nowrap;
}
.readout b { color: var(--accent); font-weight: 500; }

/* ---- time ribbon (signature) ---- */
.ribbon {
  position: relative;
  height: 56px;
  margin: 2px 12px 10px;
  flex: none;
  cursor: crosshair;
  touch-action: none;
}
#ribbonCanvas {
  width: 100%;
  height: 100%;
  display: block;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 5px;
}
.ribbon-cursor {
  /* The same grip handle as /skewt/'s ribbon (Ivan: deploy it here too):
     full-height hairline (::before) plus a 14x28 slitted pill (::after),
     centred by transform on the exact x the JS sets so the wide body
     never lies about the instant it marks. Surface stays the drag
     target; the handle only advertises it. */
  position: absolute;
  top: 0;
  width: 18px;
  height: 100%;
  transform: translateX(-50%);
  pointer-events: none;
  transition: left 60ms linear;
}
.ribbon-cursor::before {
  content: ""; position: absolute; top: 0; bottom: 0;
  left: 50%; width: 2px; margin-left: -1px;
  background: var(--accent);
}
.ribbon-cursor::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 14px; height: 28px; border-radius: 7px;
  background: linear-gradient(90deg,
    var(--accent) 0 4px,  var(--panel) 4px 5px,
    var(--accent) 5px 9px, var(--panel) 9px 10px,
    var(--accent) 10px 14px);
  box-shadow: 0 1px 4px var(--shadow-2);
}
@media (prefers-reduced-motion: reduce) {
  .ribbon-cursor { transition: none; }
}

/* ---- paywall panel ---- */
.paywall {
  position: absolute;
  max-width: 340px;
  text-align: center;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 26px 30px;
  box-shadow: 0 4px 24px var(--shadow-2);
}
.paywall-lock { font-size: 26px; margin-bottom: 6px; }
.paywall h3 { margin: 0 0 6px; font-size: 17px; }
.paywall p { margin: 0 0 16px; font-size: 14.5px; color: var(--muted); line-height: 1.45; }
.paywall-cta {
  font-size: 14.5px;
  font-weight: 500;
  padding: 8px 20px;
  border-radius: 5px;
  background: var(--accent);
  color: var(--on-accent);
}
.paywall-cta:hover { background: var(--accent-hi); }
.paywall-cta:disabled { opacity: 0.6; cursor: default; }
.paywall-alt {
  display: block;
  margin-top: 12px;
  font-size: 13px;
  color: var(--muted);
  text-decoration: none;
}
.paywall-alt:hover { color: var(--accent); text-decoration: underline; }
.premium-badge.manage { cursor: pointer; }
.premium-badge.manage:hover { background: var(--badge-hover); }

/* ---- run selector ---- */
.run-select { position: relative; }
.run-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  border: 1px solid transparent;
  border-radius: 4px;
}
.run-btn:hover { border-color: var(--line); }
.run-btn .mono { font-size: 13.5px; color: var(--muted); }
.run-caret { font-size: 10px; color: var(--muted); }
.run-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 40;
  /* The menu is absolutely positioned inside the small run button, so
     shrink-to-fit caps its width at the containing block and long tags wrap
     instead of the box growing. max-content sizes it to its longest row and
     lets it extend leftward from right:0; the max-width keeps it on screen. */
  width: max-content;
  min-width: 300px;
  max-width: min(92vw, 440px);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 4px 24px var(--shadow-2);
  padding: 4px;
}
.run-item {
  display: flex;
  align-items: center;
  white-space: nowrap;
  gap: 8px;
  width: 100%;
  text-align: left;
  font-size: 13.5px;
  padding: 7px 10px;
  border-radius: 4px;
}
.run-item:hover { background: var(--panel-hover); }
.run-item.active { background: var(--panel-active); color: var(--accent-hi); font-weight: 500; }
/* Condensed rather than mono: a run label is read, not compared column by
   column, and the narrower face buys back the width the tag needs. */
.run-item .run-label {
  font-family: var(--cond);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.run-item .tag {
  white-space: nowrap;           /* "arhiva · besplatno" must stay on one line */
  flex: none;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.8px;
  padding: 2px 5px;
  border-radius: 3px;
  margin-left: auto;
  color: var(--chip-ink);
  background: var(--chip-bg);
  border: 1px solid var(--chip-line);
}
.run-item.locked { color: var(--muted); }
.run-item.locked::after { content: "🔒"; font-size: 10px; opacity: 0.55; }
.settings-select { position: relative; }
.icon-btn {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 4px;
}
.icon-btn:hover { border-color: var(--accent); color: var(--accent); }
.settings-menu { min-width: 190px; }
.menu-section {
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.8px;
  color: var(--muted);
  padding: 8px 10px 3px;
}
.settings-menu .run-item.active::after { content: "✓"; margin-left: auto; }
.archive-chip {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 1px;
  padding: 3px 7px;
  border-radius: 3px;
  color: var(--chip-ink);
  background: var(--chip-bg);
  border: 1px solid var(--chip-line);
}

/* premium lock badge in sidebar (only when enforcement is on) */
.product-btn.locked::after {
  content: "🔒";
  font-size: 10px;
  opacity: 0.55;
  flex: none;                   /* never shrinks, never clipped */
  margin-left: auto;            /* pinned to the end, away from the ellipsis */
}

/* ---- sign-in dialog ---- */
.signin {
  width: min(92vw, 340px);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 26px 28px 20px;
  background: var(--panel);
  color: var(--ink);
  font-family: var(--sans);
}
.signin::backdrop { background: var(--backdrop); }
.dialog-close {
  position: absolute;
  top: 8px; right: 12px;
  font-size: 20px;
  color: var(--muted);
}
.signin-brand {
  font-family: var(--mono);
  font-size: 19px;
  text-align: center;
  margin-bottom: 18px;
}
.signin-brand b { color: var(--accent); font-weight: 500; }
.providers { display: flex; flex-direction: column; gap: 8px; }
.provider-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  font-size: 14.5px;
  font-weight: 500;
  padding: 9px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--panel);
}
.provider-btn:hover { border-color: var(--accent); }
.divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  font-size: 12.5px;
  margin: 14px 0;
}
.divider::before, .divider::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
#emailForm { display: flex; flex-direction: column; gap: 8px; }
#emailForm input {
  font: inherit;
  font-size: 14.5px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg);
  color: var(--ink);
}
#emailForm input:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; border-color: transparent; }
/* Sits between the form and .signin-links now, not inside the form's own
   flex gap, so it carries its own top margin to keep the same breathing
   room a provider error and an email-field error get alike. */
.form-err { font-size: 13.5px; color: var(--stale); margin: 8px 0 0; }
.submit-btn {
  font-size: 14.5px;
  font-weight: 500;
  padding: 9px;
  border-radius: 5px;
  background: var(--accent);
  color: var(--on-accent);
}
.submit-btn:hover { background: var(--accent-hi); }
.signin-links {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 14px;
  font-size: 13px;
}
.signin-links a { color: var(--accent); text-decoration: none; }
.signin-links a:hover { text-decoration: underline; }

.product-btn-mobile {
  display: none;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 500;
  padding: 0 12px;
  height: 30px;
  border: 1px solid var(--accent);
  border-radius: 4px;
  color: var(--accent);
  background: var(--panel);
  max-width: 40vw;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ---- mobile ---- */
/* ---- large windows: shrink-wrap the stage column to the map ----
   --stage-w is set from the map's natural width (viewer.js), so the sector
   pills, transport, and ribbon hug the map instead of the window edges;
   the sidebar+map group centers horizontally and top-aligns vertically. */
@media (min-width: 821px) {
  .layout { justify-content: center; }
  .stage-col {
    flex: 0 1 auto;
    width: min(100%, calc(var(--stage-w, 1100px) + 24px));
  }
  .stage { flex: 0 1 auto; min-height: 320px; padding: 10px 12px; }
  #mapImage { max-height: calc(100dvh - 262px); }
  /* vertical breathing room between the stage column's elements */
  .sectorbar { padding: 14px 12px 10px; }
  .controls { padding: 8px 12px; }
  .ribbon { margin: 8px 12px 14px; }
}

/* very wide windows: room for a wider sidebar with three product columns */
@media (max-width: 820px) {
  .sidebar { display: none; }
  .product-btn-mobile { display: inline-flex; }
  .model-name { display: none; }
  /* Same idiom as .lnav-links (landing.css) hiding below 700px: the tool
     links vanish, the brand mark stays as the way home, and nothing here
     is asked to wrap or grow the topbar's fixed height. */
  .topnav { display: none; }
  .controls { flex-direction: column; gap: 4px; }
  .readout { font-size: 13px; }
  .topbar { padding-top: env(safe-area-inset-top); height: calc(46px + env(safe-area-inset-top)); }
  /* narrow phones: compact topbar so brand + run + ⚙ + auth fit one line */
  .topbar { padding-left: 8px; padding-right: 8px; }
  .brand-mark { font-size: 17px; }
  .brand-long { display: none; }
  .brand-short { display: inline; }
  .runinfo { gap: 6px; }
  .run-btn { padding: 4px 4px; gap: 5px; }
  .runinfo .mono, .run-btn .mono {
    font-family: "IBM Plex Sans Condensed", var(--sans);
    font-size: 12.5px;
    max-width: 48vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .auth-btn { font-size: 12.5px; padding: 4px 9px; }
  .icon-btn { width: 26px; height: 26px; font-size: 14px; }
  .premium-badge, .archive-chip { font-size: 10px; padding: 2px 5px; }
  /* transport keys fit the width; the product button wraps to its own row */
  .transport { flex-wrap: wrap; justify-content: center; row-gap: 6px; }
  .transport button { min-width: 36px; height: 38px; font-size: 15px; }
  .product-btn-mobile { flex: 1 1 100%; max-width: none; justify-content: center; height: 38px; }
  .ribbon { height: 62px; }
  .sectorbar {
    padding-top: 10px;
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent);
  }
  .sector-btn { padding: 8px 13px; font-size: 14px; }
  .controls { padding-bottom: env(safe-area-inset-bottom); }
}

.sheet-backdrop {
  position: fixed; inset: 0;
  z-index: 40;
  background: var(--backdrop);
}
.sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 41;
  max-height: 72vh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-top: 1px solid var(--line);
  border-radius: 12px 12px 0 0;
  padding: 6px 14px calc(12px + env(safe-area-inset-bottom));
  box-shadow: 0 -8px 30px var(--shadow-3);
}
.sheet[hidden] { display: none; }
.sheet-grab {
  width: 34px; height: 4px;
  border-radius: 2px;
  background: var(--line);
  margin: 4px auto 8px;
  flex: none;
}
.sheet-search { margin: 0 0 8px; flex: none; }
.sheet-grid { overflow-y: auto; }
.sheet-grid .group-title { padding: 12px 2px 4px; }
.sheet-grid .grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}
.sheet-grid .product-btn {
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 10px;
  min-height: 40px;
  border-left-width: 1px;
}
.sheet-grid .product-btn.active {
  border-color: var(--accent);
  background: var(--panel-active);
}
@media (prefers-reduced-motion: no-preference) {
  .sheet { animation: sheet-up 200ms ease; }
  @keyframes sheet-up { from { transform: translateY(30%); opacity: 0.6; } }
}

/* Theme transitions */
@media (prefers-reduced-motion: no-preference) {
  body, .topbar, .sidebar, .sector-btn, .transport button, #ribbonCanvas,
  .paywall, .signin, .run-menu, .sheet {
    transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;
  }
}

/* Loading spinner */
.stage-msg[data-loading]::before {
  content: "";
  display: inline-block;
  width: 13px; height: 13px;
  margin-right: 9px;
  vertical-align: -2px;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .stage-msg[data-loading]::before { animation: none; } }

/* ---- terms consent before checkout ---- */
.consent { max-width: 460px; }
.consent h3 {
  font-size: 17px; font-weight: 600; margin: 0 0 16px;
}
.consent-check {
  display: flex; gap: 11px; align-items: flex-start;
  font-size: 14px; line-height: 1.55; color: var(--muted);
  margin-bottom: 20px; cursor: pointer;
}
.consent-check input {
  margin: 2px 0 0; width: 17px; height: 17px; flex: none;
  accent-color: var(--accent); cursor: pointer;
}
.consent-check a { color: var(--accent); }
.consent .submit-btn:disabled { opacity: .5; cursor: not-allowed; }
.consent-price {
  font-family: var(--mono); font-size: 14px; color: var(--ink);
  background: var(--panel-active); border: 1px solid var(--line);
  border-radius: 2px; padding: 8px 11px; margin: 0 0 16px;
}

/* Same control as the landing page's. The two stylesheets share no component
   layer -- only tokens.css -- so a ten-line rule lives in both rather than a
   third file existing to hold it. */
.seg {
  display: inline-flex; border: 1px solid var(--line); border-radius: 2px;
  overflow: hidden; margin: 0 0 14px; font-family: var(--mono);
  font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
}
.seg button {
  font: inherit; letter-spacing: inherit; text-transform: inherit;
  padding: 7px 14px; border: 0; background: none; color: var(--muted); cursor: pointer;
}
.seg button.on { background: var(--accent); color: var(--on-accent); }
/* Inset because .seg clips its overflow — an outer ring would be cut off. That
   puts the ring on top of the selected button's accent fill, where an accent
   ring is invisible, so the selected one draws its ring in the other colour. */
.seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.seg button.on:focus-visible { outline-color: var(--on-accent); }

/* Heads the archived block in the run menu: every archived run is served
   from separate, rate-limited infrastructure, whether it is free or not. */
.run-note {
  border-top: 1px solid var(--line);
  margin-top: 4px;
  padding: 8px 12px 4px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--muted);
}
