/*
  Veyra marketing site.
  --------------------------------------------------------------------------
  Two grounds, nothing in between: deep navy for the moments that carry the
  product, warm paper for the moments that carry the words. Hairline rules and
  monospaced labels do the structural work so the page needs very few boxes.

  app.css themes the actual inventory application; this file only ever styles
  index.html. Product surfaces here deliberately borrow app.css's palette so
  the screenshots read as the same software.
*/

:root {
  /* --- navy ground (shared with the app) --- */
  --ink: var(--v-ink-950);
  --ink-2: var(--v-ink-850);
  --ink-3: var(--v-ink-800);
  --ink-deep: #060b16;
  /* Crisp neutral hairlines. Every consumer of these is a dark surface, so a
     white alpha reads cleaner against navy than the blue-tinted core token. */
  --hair: rgba(255, 255, 255, 0.1);
  --hair-strong: rgba(255, 255, 255, 0.18);
  --on-ink: #eaf0fa;
  --on-ink-muted: var(--v-ink-300);

  /* --- paper ground --- */
  --paper: var(--v-paper-1);
  --paper-2: var(--v-paper-2);
  --rule: var(--v-paper-line);

  /* --- brand ---
     The mark stays cyan; the interface accent is emerald. One accent, spent
     deliberately: the primary action, live figures, healthy status, focus.
     Everything else is type and hairlines, so the green always means
     something. --cyan-deep survives for the 404 page's links, where a green
     of that weight would read as a status rather than as a link. */
  --emerald: #4ade80;
  --emerald-bright: #86efac;
  --emerald-deep: #15803d;
  --emerald-quiet: rgba(74, 222, 128, 0.1);
  --emerald-line: rgba(74, 222, 128, 0.32);

  --cyan-deep: var(--v-brand-600);

  /* Status: green healthy, amber watch, red critical. */
  --ok: var(--emerald);
  --low: var(--v-amber-ink);
  --out: var(--v-red-ink);

  /* --- legacy tokens: the assessment component is built on these --- */
  --bg: var(--paper);
  --surface: #ffffff;
  --surface-strong: #eef3ff;
  --surface-soft: #f8f7f4;
  --primary: #163a6c;
  --primary-deep: #0d2348;
  --accent: var(--v-brand-500);
  --accent-strong: var(--v-brand-600);
  --accent-soft: var(--v-brand-50);
  --text: #141b2b;
  --muted: #4e5a6e;
  --line: var(--v-paper-line);
  --success: #1c8c6d;
  --warning: #f3b93f;
  --shadow: 0 24px 60px rgba(17, 31, 62, 0.08);

  --display: var(--font-sans);
  --mono: var(--font-mono);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* the sticky header must not sit on top of an anchor target */
  scroll-padding-top: var(--space-24);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
  display: block;
}

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

h1,
h2,
h3 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1.06;
}

.shell {
  width: min(1180px, calc(100% - 48px));
  margin: 0 auto;
}

/* kept so any older markup or bookmarklet using .container still lines up */
.container {
  width: min(1180px, calc(100% - 48px));
  margin: 0 auto;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--emerald);
  color: var(--v-ink-950);
  font-weight: 600;
}

.skip-link:focus {
  left: 12px;
  top: 12px;
}

/* Monospaced micro-label. Used for every field name, unit and section marker
   on the page - it is the one typographic move that ties the marketing page
   to the data-dense app. */
.mono-label {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-muted);
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 50px;
  padding: 0 var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font-family: inherit;
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

/*
  The two hero actions must not read as a pair. The primary is a solid accent
  fill that lifts on hover; the secondary is a ghost - no fill, a hairline,
  muted type - so it is available without competing.
*/
.button-accent {
  background: var(--emerald);
  color: var(--v-ink-950);
  box-shadow: 0 1px 2px rgba(3, 8, 20, 0.4);
  transition: background var(--duration-base) var(--ease),
    box-shadow var(--duration-base) var(--ease),
    transform var(--duration-base) var(--ease);
}

.button-accent:hover,
.button-accent:focus-visible {
  background: var(--emerald-bright);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px -6px rgba(74, 222, 128, 0.55), 0 2px 4px rgba(3, 8, 20, 0.4);
}

.button-outline {
  border-color: var(--hair);
  color: var(--on-ink-muted);
}

.button-outline:hover,
.button-outline:focus-visible {
  border-color: var(--hair-strong);
  color: var(--on-ink);
}

/* Paper-ground buttons, used by the assessment component. */
.button-primary {
  background: var(--ink);
  color: #fff;
}

.button-primary:hover,
.button-primary:focus-visible {
  background: var(--ink-3);
}

.button-secondary {
  background: transparent;
  border-color: var(--rule);
  color: var(--text);
}

.button-secondary:hover,
.button-secondary:focus-visible {
  border-color: var(--ink);
}

.button-ghost {
  background: transparent;
  color: var(--muted);
}

.button-ghost:hover,
.button-ghost:focus-visible {
  color: var(--ink);
}

/* ==========================================================================
   1. Navigation
   ========================================================================== */

.site-header {
  position: sticky;
  /* containing block for the mobile menu panel */
  isolation: isolate;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--ink) 92%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hair);
  color: var(--on-ink);
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--space-10);
  min-height: 80px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.brand-mark {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-control);
  object-fit: cover;
}

.brand-word {
  font-family: var(--display);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -0.04em;
}

/*
  The masthead carries the brand at full presence; the footer keeps the small
  mark, where it is a signature rather than a title. Only the header grows, so
  the two never compete.
*/
.site-header .brand {
  gap: var(--space-3);
}

.site-header .brand-mark {
  width: 40px;
  height: 40px;
  border-radius: 9px;
}

.site-header .brand-word {
  font-size: 1.625rem;
  letter-spacing: -0.045em;
}

.site-nav {
  display: flex;
  gap: var(--space-8);
  font-size: var(--text-base);
  color: var(--on-ink-muted);
}

.site-nav a {
  transition: color 0.18s ease;
}

.site-nav a:hover,
.site-nav a:focus-visible {
  color: var(--on-ink);
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-left: auto;
}

.nav-login {
  font-size: var(--text-base);
  color: var(--on-ink-muted);
  transition: color 0.18s ease;
}

.nav-login:hover,
.nav-login:focus-visible {
  color: var(--on-ink);
}

.nav-cta.button {
  min-height: 40px;
  padding: 0 var(--space-4);
  font-size: var(--text-base);
}

/* ==========================================================================
   2. Display type
   --------------------------------------------------------------------------
   What is left of the old marketing hero after the cinematic opening replaced
   it: the full stop and the hand-set line break, both still used by the
   closing headline and by the two auth pages.
   ========================================================================== */

/* A single accent full stop. The only decorative colour in a headline. */
.stop {
  color: var(--emerald);
}

/* Headline breaks are set by hand for the wide layout. Below the phone
   breakpoint they leave orphan lines, so the text is left to wrap itself. */
.type-break {
  display: initial;
}

/* ==========================================================================
   The Veyra bar, inside a product surface
   --------------------------------------------------------------------------
   The mark and the wordmark as they sit in the title bar of a screenshot.
   Used by the loop section; the rest of that panel went with the hero.
   ========================================================================== */

.app-shot-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--display);
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: -0.03em;
}

.app-shot-brand img {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  object-fit: cover;
}

/* --- what Veyra caught --------------------------------------------------- */

/* Grid and flex children default to min-content width, which lets a long
   product name push a column wider than its track. This pins it back. */
.story-visual {
  min-width: 0;
}

.rec-action,
.rec-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-control);
  font-size: var(--text-sm);
  font-weight: 600;
}

.rec-action {
  width: 100%;
  background: var(--emerald);
  color: var(--v-ink-950);
}

.rec-secondary {
  border: 1px solid var(--hair-strong);
  color: var(--on-ink-muted);
}

/* ==========================================================================
   3-5. The story sections, on paper
   ========================================================================== */

.story-step {
  padding: var(--space-32) 0;
  border-top: 1px solid var(--rule);
}

.story-step:first-child {
  border-top: 0;
  padding-top: var(--space-32);
}

.story-grid {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  gap: var(--space-16);
  align-items: start;
}

/* Flipped step: the visual takes the wide track on the left, the copy the
   narrow one on the right. Both the track widths and the source order swap. */
.story-step-flip .story-grid {
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
}

.story-step-flip .story-copy {
  order: 2;
}

.story-copy {
  position: sticky;
  top: 128px;
}

.step-index {
  margin: 0 0 var(--space-5);
  padding-top: var(--space-3);
  border-top: 2px solid var(--ink);
  display: inline-block;
  font-family: var(--mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
}

.story-copy h2 {
  font-size: clamp(2.4rem, 4.6vw, 3.7rem);
  margin-bottom: var(--space-5);
}

.story-copy p {
  max-width: 40ch;
  margin: 0;
  color: var(--muted);
  font-size: var(--text-md);
}

/* --- dark product panes sitting on paper -------------------------------- */

.pane {
  background: var(--ink-2);
  border: 1px solid rgba(10, 16, 32, 0.14);
  border-radius: var(--radius-panel);
  box-shadow: 0 30px 70px rgba(10, 20, 40, 0.16);
  color: var(--on-ink);
  overflow: hidden;
}

.pane-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--hair);
  background: rgba(10, 16, 32, 0.45);
}

.pane-title {
  font-family: var(--display);
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: -0.025em;
}

.filter-chip {
  padding: var(--space-1) var(--space-3);
  border-radius: 6px;
  border: 1px solid var(--emerald-line);
  background: var(--emerald-quiet);
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  color: var(--emerald);
}

/* --- 01 full inventory table -------------------------------------------- */

.pane-table {
  width: 100%;
  border-collapse: collapse;
}

.pane-table caption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.pane-table th,
.pane-table td {
  padding: var(--space-3) var(--space-6);
  text-align: left;
  border-bottom: 1px solid var(--hair);
  font-size: var(--text-base);
  vertical-align: middle;
}

.pane-table thead th {
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
  font-family: var(--mono);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-muted);
}

.pane-table .num {
  text-align: right;
  font-family: var(--mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.cell-name {
  display: block;
  font-weight: 500;
}

.cell-muted {
  color: var(--on-ink-muted);
  font-size: var(--text-sm);
}

.pane-table tfoot td {
  border-bottom: 0;
  border-top: 1px solid var(--hair-strong);
  font-weight: 600;
  color: var(--on-ink);
}

/* --- 02 needs attention -------------------------------------------------- */

.attn-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.attn-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-5) var(--space-6) var(--space-5) var(--space-5);
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--hair);
}

.attn-out {
  border-left-color: var(--out);
  background: rgba(255, 122, 122, 0.05);
}

.attn-low {
  border-left-color: var(--low);
}

.attn-name {
  margin: 0 0 var(--space-1);
  font-size: var(--text-base);
  font-weight: 500;
}

.attn-why {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--on-ink-muted);
}

.attn-side {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex: none;
}

.attn-metric {
  margin: 0;
  font-family: var(--display);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.attn-metric em {
  font-style: normal;
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--on-ink-muted);
}

.attn-rest {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-4) var(--space-6);
  font-size: var(--text-sm);
  color: var(--on-ink-muted);
}

/* --- 03 recommended order ------------------------------------------------ */

.rec-hero {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-6) var(--space-6);
  border-bottom: 1px solid var(--hair);
}

.rec-hero-name {
  margin: 0 0 var(--space-1);
  font-family: var(--display);
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: -0.04em;
}

.rec-hero-sku {
  margin: 0;
}

.rec-hero-qty {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(2.6rem, 5vw, 3.6rem);
  font-weight: 600;
  letter-spacing: -0.055em;
  line-height: 1;
  color: var(--emerald);
  font-variant-numeric: tabular-nums;
}

.rec-hero-qty em {
  font-style: normal;
  font-size: var(--text-base);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--on-ink-muted);
}

.rec-why {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rec-why li {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: var(--space-5);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--hair);
  font-size: var(--text-base);
}

.rec-why span {
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-muted);
  padding-top: 3px;
}

.rec-why b {
  font-weight: 500;
}

.rec-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
}

.rec-bar .rec-action {
  width: auto;
}

/* --- status pills (dark surfaces) --------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: 6px;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.pill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.pill-in,
.pill-ok {
  color: var(--ok);
  background: var(--emerald-quiet);
}

.pill-low {
  color: var(--low);
  background: rgba(245, 196, 81, 0.15);
}

.pill-out {
  color: var(--out);
  background: rgba(255, 122, 122, 0.15);
}

/* ==========================================================================
   Free assessment - intro block (the component itself is styled further down)
   ========================================================================== */

.assessment-section {
  padding: var(--space-32) 0;
  border-top: 1px solid var(--rule);
  background: var(--paper-2);
}

.assessment-intro {
  max-width: 640px;
  margin-bottom: var(--space-10);
}

.assessment-intro h2 {
  font-size: clamp(2rem, 3.6vw, 2.9rem);
  margin-bottom: var(--space-4);
}

.assessment-intro p {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-md);
}

/* ==========================================================================
   6. Closing call to action
   ========================================================================== */

.closer {
  padding: var(--space-32) 0;
  background: var(--ink);
  color: var(--on-ink);
}

.closer-inner {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-12);
  flex-wrap: wrap;
}

.closer-title {
  font-size: clamp(2.6rem, 6.4vw, 5rem);
  letter-spacing: -0.05em;
  line-height: 0.98;
}

.closer-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
  padding-bottom: var(--space-2);
}

.closer-alt {
  font-size: var(--text-base);
  color: var(--on-ink-muted);
  transition: color 0.18s ease;
}

.closer-alt:hover,
.closer-alt:focus-visible {
  color: var(--emerald);
}

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  padding: var(--space-16) 0 var(--space-8);
  background: var(--ink-deep);
  color: var(--on-ink);
  border-top: 1px solid var(--hair);
}

.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-12);
}

.footer-copy {
  max-width: 38ch;
  margin: var(--space-4) 0 0;
  color: var(--on-ink-muted);
  font-size: var(--text-base);
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  font-size: var(--text-base);
  color: var(--on-ink-muted);
}

.footer-col .mono-label {
  margin-bottom: var(--space-1);
  color: var(--on-ink-muted);
}

.footer-col a {
  transition: color 0.18s ease;
}

.footer-col a:hover,
.footer-col a:focus-visible {
  color: var(--emerald);
}

.bottom-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-16);
  padding-top: var(--space-5);
  border-top: 1px solid var(--hair);
  font-size: var(--text-sm);
  color: var(--on-ink-muted);
}

/* ==========================================================================
   Motion
   ==========================================================================
   There is no entrance animation. A hero that starts at opacity 0 means the
   first painted frame - which is what a screenshot, a shared link preview and
   anyone on a slow connection actually sees - shows faded text. Motion here
   is reserved for state changes: menus opening, hover, focus.
   ========================================================================== */

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 1080px) {
  .story-grid,
  .story-step-flip .story-grid {
    grid-template-columns: 1fr;
    gap: var(--space-10);
  }

  .story-copy {
    position: static;
  }

  .story-step-flip .story-copy {
    order: 0;
  }

  .story-copy p {
    max-width: 56ch;
  }

}

@media (max-width: 900px) {
  .shell,
  .container {
    width: calc(100% - 32px);
  }

  .nav {
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-6);
    padding: var(--space-3) 0;
    min-height: 0;
  }

  .site-nav {
    order: 3;
    width: 100%;
    gap: var(--space-5);
    overflow-x: auto;
    padding-bottom: 2px;
  }

  .story-step,
  .story-step:first-child {
    padding: var(--space-20) 0;
  }

  .assessment-section,
  .closer {
    padding: var(--space-20) 0;
  }

  .footer-grid {
    grid-template-columns: 1fr 1fr;
  }

  .footer-brand-col {
    grid-column: 1 / -1;
  }
}

@media (max-width: 620px) {
  .type-break {
    display: none;
  }

  .nav-login {
    display: none;
  }

  /* Still larger than it was, but the wordmark stops crowding the menu
     button on a phone. */
  .site-header .brand-mark {
    width: 34px;
    height: 34px;
  }

  .site-header .brand-word {
    font-size: 1.375rem;
  }

  .pane-head {
    flex-wrap: wrap;
    padding: var(--space-4);
  }

  .pane-table {
    display: block;
    overflow-x: auto;
  }

  .pane-table thead th,
  .pane-table td {
    padding: var(--space-3) var(--space-4);
    white-space: nowrap;
  }

  .attn-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-4) var(--space-4) var(--space-3);
  }

  .rec-hero {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-4);
  }

  .rec-why li {
    grid-template-columns: 1fr;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-4);
  }

  .rec-bar {
    flex-direction: column;
    align-items: stretch;
    padding: var(--space-4) var(--space-4);
  }

  .rec-bar .rec-action,
  .rec-secondary {
    width: 100%;
  }

  .closer-inner {
    gap: var(--space-8);
  }

  .closer-actions {
    width: 100%;
  }

  .closer-actions .button {
    width: 100%;
  }

  .bottom-bar {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
  }
}

/* ==========================================================================
   Missed Revenue Assessment
   ========================================================================== */

.assessment-app {
  max-width: 760px;
}

.assessment-privacy {
  max-width: 760px;
  margin: var(--space-4) 0 0;
  color: var(--muted);
  font-size: var(--text-base);
}

/* --- question card ------------------------------------------------------ */

.q-card,
.r-card {
  padding: var(--space-8);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow);
}

.q-progress {
  margin-bottom: var(--space-6);
}

.q-progress-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-2);
}

.q-count {
  color: var(--primary);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.q-time {
  color: var(--muted);
  font-size: var(--text-sm);
}

.q-fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}

.q-legend {
  padding: 0;
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1.2;
}

.q-legend:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 4px;
  border-radius: 4px;
}

.q-help {
  margin: var(--space-2) 0 0;
  color: var(--muted);
  font-size: var(--text-base);
}

/* --- inputs ------------------------------------------------------------- */

.q-number {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.q-input,
.q-select {
  width: 100%;
  min-height: 56px;
  padding: 0 var(--space-4);
  font-family: inherit;
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text);
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.q-number .q-input {
  max-width: 200px;
}

.q-input:focus,
.q-select:focus {
  outline: none;
  border-color: var(--accent-strong);
  box-shadow: 0 0 0 3px rgba(27, 135, 189, 0.18);
}

.q-affix {
  color: var(--muted);
  font-size: var(--text-md);
  font-weight: 600;
}

.q-affix-end {
  font-size: var(--text-base);
  font-weight: 500;
}

.q-select-wrap {
  margin-top: var(--space-5);
}

.q-select {
  appearance: none;
  cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 21px) 25px, calc(100% - 15px) 25px;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: var(--space-10);
}

.q-options {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.q-option {
  position: relative; /* anchors the visually hidden input */
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4);
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease;
}

.q-option:hover {
  border-color: var(--accent);
}

.q-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.q-option-mark {
  flex: none;
  width: 22px;
  height: 22px;
  border: 2px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.q-option input[type='checkbox'] + .q-option-mark {
  border-radius: 7px;
}

.q-option.is-selected {
  background: var(--accent-soft);
  border-color: var(--accent-strong);
}

.q-option.is-selected .q-option-mark {
  border-color: var(--accent-strong);
  box-shadow: inset 0 0 0 4px var(--accent-strong);
}

.q-option:focus-within {
  border-color: var(--accent-strong);
  box-shadow: 0 0 0 3px rgba(27, 135, 189, 0.18);
}

.q-option-label {
  font-weight: 500;
}

.q-error {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  color: #8c2f2f;
  background: rgba(255, 122, 122, 0.1);
  border: 1px solid rgba(255, 122, 122, 0.28);
  border-radius: var(--radius-control);
  font-size: var(--text-base);
}

.q-actions {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

.q-actions .button {
  min-width: 130px;
}

.q-back[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

.q-back[disabled]:hover {
  transform: none;
}

/* --- results ------------------------------------------------------------ */

.r-eyebrow {
  margin: 0 0 var(--space-3);
  color: var(--primary);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.r-eyebrow:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 4px;
  border-radius: 4px;
}

.r-title {
  font-size: var(--text-2xl);
  margin-bottom: var(--space-6);
}

.r-clean {
  margin: 0;
  color: var(--muted);
}

.r-hero {
  padding: var(--space-6) var(--space-6);
  background: linear-gradient(135deg, var(--primary) 0%, var(--primary-deep) 100%);
  border-radius: 12px;
  color: #fff;
}

.r-hero-label {
  display: block;
  margin-bottom: var(--space-1);
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.r-hero-value {
  display: block;
  font-size: clamp(3rem, 7vw, 3.75rem);
  font-weight: 700;
  letter-spacing: -0.055em;
  line-height: 1.05;
}

.r-hero-note {
  max-width: 46ch;
  margin: var(--space-3) 0 0;
  color: rgba(255, 255, 255, 0.82);
  font-size: var(--text-base);
}

.r-hero-note strong {
  color: #fff;
}

.r-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.r-tile {
  padding: var(--space-5);
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
}

.r-tile-label {
  display: block;
  margin-bottom: var(--space-2);
  color: var(--muted);
  font-size: var(--text-sm);
  font-weight: 500;
}

.r-tile-value {
  display: block;
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 1.1;
}

.r-tile-note {
  display: block;
  margin-top: var(--space-1);
  color: var(--muted);
  font-size: var(--text-sm);
}

/* meter: one hue, filled portion on a lighter step of the same ramp */
.r-meter {
  margin-top: var(--space-6);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line);
}

.r-meter-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-2);
}

.r-meter-label {
  color: var(--muted);
  font-size: var(--text-base);
}

.r-meter-value {
  font-size: var(--text-lg);
  font-weight: 700;
  letter-spacing: -0.03em;
}

.r-meter-track {
  height: 14px;
  background: var(--accent-soft);
  border-radius: 4px;
  overflow: hidden;
}

.r-meter-fill {
  height: 100%;
  background: var(--accent-strong);
  border-radius: 0 4px 4px 0;
}

.r-meter-note {
  max-width: 62ch;
  margin: var(--space-3) 0 0;
  color: var(--muted);
  font-size: var(--text-base);
}

.r-gaps {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line);
}

.r-gaps-title {
  margin-bottom: var(--space-4);
  font-size: var(--text-lg);
}

.r-gap {
  padding: var(--space-5) var(--space-5);
  background: var(--surface-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
}

.r-gap + .r-gap {
  margin-top: var(--space-3);
}

.r-gap-level {
  display: inline-block;
  margin-bottom: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.r-gap-high {
  color: #8c2f2f;
  background: rgba(255, 122, 122, 0.14);
}

.r-gap-medium {
  color: #7a5306;
  background: rgba(243, 185, 63, 0.18);
}

.r-gap-title {
  margin-bottom: var(--space-2);
  font-size: var(--text-md);
}

.r-gap-detail {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-base);
}

.r-gap-action {
  margin: var(--space-3) 0 0;
  font-size: var(--text-base);
}

.r-gap-action strong {
  color: var(--primary);
}

.r-math {
  margin-top: var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--surface-soft);
}

.r-math summary {
  padding: var(--space-4) var(--space-5);
  color: var(--primary);
  font-weight: 600;
  cursor: pointer;
}

.r-math summary:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: -2px;
  border-radius: var(--radius-control);
}

.r-math-body {
  padding: 0 var(--space-5) var(--space-5);
  color: var(--muted);
  font-size: var(--text-base);
}

.r-math-body p {
  margin-top: 0;
}

.r-math-body ol {
  margin: 0;
  padding-left: var(--space-5);
}

.r-math-body li {
  margin-bottom: var(--space-2);
}

.r-math-body strong {
  color: var(--text);
}

.r-math-caveat {
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
}

.r-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

.button-ghost {
  background: transparent;
  color: var(--muted);
}

.button-ghost:hover {
  color: var(--primary);
}

.r-actions-note {
  margin: var(--space-3) 0 0;
  color: var(--muted);
  font-size: var(--text-sm);
}

@media (max-width: 620px) {
  .q-card,
  .r-card {
    padding: var(--space-6) var(--space-5);
  }

  .q-legend {
    font-size: var(--text-xl);
  }

  .r-tiles {
    grid-template-columns: 1fr;
  }

  .q-actions {
    flex-direction: column-reverse;
  }

  .q-actions .button {
    width: 100%;
  }

  .r-meter-head {
    flex-direction: column;
    gap: var(--space-1);
  }
}

/* --- print: the assessment results become the report -------------------- */

@media print {
  .site-header,
.story,
.closer,
.site-footer,
.assessment-intro,
.assessment-privacy,
.r-actions,
.r-actions-note,
.skip-link {
    display: none !important;
  }

  body {
    background: #fff;
  }

  .assessment-section {
    padding: 0;
    border-top: 0;
    background: #fff;
  }

  .r-card {
    box-shadow: none;
    border: 0;
    padding: 0;
  }

  .r-hero {
    color: #000;
    background: none;
    border: 1px solid #999;
  }

  .r-hero-label,
  .r-hero-note {
    color: #333;
  }

  .r-hero-note strong {
    color: #000;
  }

  .r-math {
    background: none;
  }

  .r-math[open] summary {
    display: none;
  }
}

/* ==========================================================================
   404
   ========================================================================== */

.notfound {
  display: flex;
  align-items: center;
  min-height: calc(100vh - 72px - 120px);
  padding: var(--space-24) 0;
}

.notfound-inner {
  max-width: 62ch;
}

/* The code is metadata, not a headline, so it is set as a label, not as
   the giant decorative numeral every 404 template uses. */
.notfound-code {
  margin: 0 0 var(--space-4);
  font-family: var(--mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: var(--tracking-label);
  color: var(--cyan-deep);
}

.notfound-title {
  font-size: clamp(2rem, 4.5vw, 3rem);
  margin-bottom: var(--space-4);
}

.notfound-body {
  margin: 0 0 var(--space-8);
  color: var(--muted);
  font-size: var(--text-lg);
}

.notfound-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-12);
}

.notfound-links {
  padding-top: var(--space-6);
  border-top: 1px solid var(--rule);
}

.notfound-links .mono-label {
  color: var(--muted);
  margin-bottom: var(--space-3);
}

.notfound-links ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: 0;
  padding: 0;
  list-style: none;
}

.notfound-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--cyan-deep);
  font-weight: 500;
}

.notfound-links a:hover {
  text-decoration: underline;
}

.notfound-help {
  margin: var(--space-8) 0 0;
  color: var(--muted);
  font-size: var(--text-sm);
}

.notfound-help a {
  color: var(--cyan-deep);
}

@media (max-width: 620px) {
  .notfound-actions .button {
    width: 100%;
  }
}

/* ==========================================================================
   SECOND PASS: composition
   ==========================================================================
   Three problems this fixes, all visible in a screenshot of the first pass:

   1. The hero's right half was empty. The product panel sat underneath the
      text, so the most important asset on the page read as an afterthought.
   2. Sections 01, 02 and 03 shared one structure (narrow copy beside a wide
      panel) which reads as a template repeating itself.
   3. The closing CTA had a void between the headline and the button.
   ========================================================================== */

/*
  A degree and a half of perspective, only where there is room for it. Enough
  to sit the panel in space; small enough that the figures stay crisp.
*/

/* ------------------------------------------------- section rhythm ------- */

/*
  01 and 03 are full-width: a copy band above, the product across the whole
  measure below. 02 stays a split. Three sections, two structures, so the
  page has a rhythm instead of a pattern.
*/
.story-step-wide .story-band {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: end;
  gap: var(--space-16);
  margin-bottom: var(--space-12);
}

.story-band-lead h2 {
  font-size: clamp(2rem, 3.4vw, 2.75rem);
  margin: 0;
}

.story-band-body {
  max-width: 58ch;
  margin: 0;
  padding-bottom: var(--space-1);
  color: var(--muted);
  font-size: var(--text-lg);
  line-height: 1.6;
}

.story-visual-wide {
  width: 100%;
}

/* Section 02 keeps the split but the copy gets room to be read. */
.story-step-flip .story-grid {
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--space-16);
}

.story-copy h2 {
  font-size: clamp(2rem, 3.4vw, 2.75rem);
  margin-bottom: var(--space-5);
}

.story-copy p {
  max-width: 46ch;
  font-size: var(--text-md);
  line-height: 1.65;
}

.story-aside {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--rule);
  font-size: var(--text-base) !important;
  color: var(--muted);
}

.step-index {
  margin-bottom: var(--space-4);
  padding-top: var(--space-3);
  font-size: var(--text-2xs);
}

/* ---------------------------------------------------------- closing CTA */

/*
  Was a headline on the left and a button on the right with nothing between
  them. Now the left column carries the claim and its explanation, and the
  actions sit against it rather than across a gap.
*/
.closer-inner {
  align-items: end;
  gap: var(--space-16);
}

.closer-lead {
  max-width: 20ch;
}

.closer-title {
  font-size: clamp(2.5rem, 5vw, 4rem);
  line-height: 0.98;
  margin-bottom: var(--space-5);
}

.closer-body {
  max-width: 38ch;
  margin: 0;
  color: var(--on-ink-muted);
  font-size: var(--text-md);
  line-height: 1.6;
}

.closer-actions {
  padding-bottom: var(--space-2);
}

/* -------------------------------------------------------- responsive ---- */

@media (max-width: 1080px) {

  .story-step-wide .story-band,
  .story-step-flip .story-grid {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }

  .story-band-body {
    font-size: var(--text-md);
  }
}

@media (max-width: 720px) {

  .closer-inner {
    gap: var(--space-10);
  }

  .closer-lead {
    max-width: none;
  }
}

/* ---------------------------------------------------- hero: one ground */

/*
  The first pass ran a navy-to-paper gradient inside the hero so the product
  panel could hang across the boundary. With the hero now a side-by-side
  composition the copy column is taller, and the seam cut straight through
  the automation list: cyan labels and muted text landing on cream, where
  they are unreadable. The hero is one ground again.
*/

/* The first section already carries its own top space; the hero does not
   need to add another 96px on top of it. */
.story-step:first-child,
.story-step-wide:first-child {
  padding-top: var(--space-24);
}

/* ==========================================================================
   SECOND PASS: assessment
   ==========================================================================
   It read as a generic form on a card: small legend, a hairline progress bar
   that was easy to miss, and two buttons of near-equal weight. The questions
   are the product experience here, so they get product-grade hierarchy.
   ========================================================================== */

.assessment-intro p {
  max-width: 56ch;
  font-size: var(--text-lg);
  line-height: 1.6;
}

.assessment-app {
  max-width: 40rem;
}

.q-card,
.r-card {
  padding: var(--space-10);
  border-radius: var(--radius-panel);
  box-shadow: 0 1px 2px rgba(20, 27, 43, 0.04), 0 12px 32px rgba(20, 27, 43, 0.06);
}

/* --- progress ----------------------------------------------------------- */

.q-progress {
  margin-bottom: var(--space-10);
}

.q-progress-row {
  margin-bottom: var(--space-3);
}

.q-count {
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  color: var(--text);
}

.q-time {
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* --- question ----------------------------------------------------------- */

.q-legend {
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.q-help {
  margin-top: var(--space-3);
  max-width: 52ch;
  font-size: var(--text-base);
  color: var(--muted);
}

/* --- controls ----------------------------------------------------------- */

.q-options {
  gap: var(--space-2);
  margin-top: var(--space-6);
}

.q-option {
  min-height: 56px;
  padding: var(--space-4);
  border-radius: var(--radius-control);
}

.q-option:hover {
  border-color: var(--accent-strong);
  background: var(--paper-2);
}

.q-option.is-selected {
  background: var(--accent-soft);
  border-color: var(--accent-strong);
  box-shadow: inset 0 0 0 1px var(--accent-strong);
}

.q-option-label {
  font-size: var(--text-md);
  font-weight: 500;
}

.q-input,
.q-select {
  min-height: 56px;
  border-radius: var(--radius-control);
  font-size: var(--text-md);
}

.q-select-wrap,
.q-number {
  margin-top: var(--space-6);
}

/* --- actions ------------------------------------------------------------ */

/*
  One primary action. Back was a bordered button of the same visual weight as
  Continue, which made every step a choice between two equal options.
*/
.q-actions {
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-10);
  padding-top: var(--space-6);
  border-top: 1px solid var(--line);
}

.q-actions .button {
  min-width: 0;
}

.q-actions .q-next {
  min-width: 9rem;
  margin-left: auto;
}

.q-back.button-secondary {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
  padding-inline: var(--space-3);
}

.q-back.button-secondary:hover:not([disabled]) {
  color: var(--text);
  background: var(--paper-2);
}

/* --- error -------------------------------------------------------------- */

.q-error {
  margin-top: var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--out);
  border-radius: var(--radius-control);
  font-size: var(--text-base);
}

/* --- results ------------------------------------------------------------ */

.r-title {
  font-size: var(--text-2xl);
  margin-bottom: var(--space-8);
}

.r-hero {
  padding: var(--space-8);
  border-radius: var(--radius-panel);
}

.r-tiles {
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.r-tile {
  padding: var(--space-5);
  border-radius: var(--radius-control);
}

@media (max-width: 620px) {
  .q-card,
  .r-card {
    padding: var(--space-6);
  }

  .q-legend {
    font-size: var(--text-lg);
  }

  .q-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }

  .q-actions .q-next {
    margin-left: 0;
  }
}

/* ==========================================================================
   The data box
   ==========================================================================
   A kraft shoebox after "See everything". Closed it
   is an object sitting on the page; opened, the three statistics that
   justify the product are standing inside it.

   Four decisions make this read as a physical thing rather than a card.

   1. ONE PERSPECTIVE, ONE PRESERVE-3D. `.vbox` owns `perspective`,
      `.vbox-tilt` owns `transform-style`, and every face is a descendant of
      that one element, so the lid, the walls and the contents share a single
      projection. Giving each piece its own perspective is what makes CSS 3D
      look like flat pieces pretending to be solid.

   2. ONLY THE FACES THAT EXIST. The camera is fixed, so the base needs five
      faces rather than six plus liners: the back wall and floor are modelled
      facing IN, the front and right walls facing OUT, and the left wall
      facing in, because the scene is turned to show the right. Two thin
      strips expose the corrugation on the cut edges, which is the detail
      that actually says cardboard.

   3. ONE TRANSFORM PER ELEMENT. A shake, a hover lift, an open tilt and a
      lid knock are four transforms that would overwrite each other on one
      node. Each gets its own layer, so a click mid-shake can cancel the
      animation without the lid jumping.

   4. THE SEQUENCE IS DELAYS, NOT TIMERS. Every layer carries an open delay
      and the reverse delay when closed, so closing genuinely plays backwards
      with no JavaScript timeline to fall out of step with the CSS.

   On the dark ground because the light inside the box is the reveal, and it
   has nothing to read against on cream.
*/

.boxlab {
  padding: var(--space-24) 0 var(--space-20);
  background:
    radial-gradient(900px 500px at 50% 18%, rgba(74, 222, 128, 0.06), transparent 70%),
    var(--ink);
  color: var(--on-ink);
  border-top: 1px solid var(--hair);
  overflow: hidden;
}

.boxlab-head {
  max-width: 44ch;
  margin-bottom: var(--space-8);
}

.boxlab-head h2 {
  font-size: clamp(2rem, 3.4vw, 2.75rem);
  margin: 0;
}

/* --- the stage ----------------------------------------------------------
   The box sits low in the frame. The air above it is not decoration: it is
   where the lid goes. */

.vbox-stage {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: 540px;
  padding-bottom: 110px;
}

/* --- geometry -----------------------------------------------------------
   Every measurement in this component derives from these few numbers, so a
   breakpoint only has to restate them. */

.vbox {
  --bw: 640px;   /* base width  */
  --bd: 260px;   /* base depth  */
  --bh: 215px;   /* base height */
  --lh: 34px;    /* lid rim height */
  --lo: 10px;    /* lid overhang, each side */
  --seam: 5px;   /* the gap the lid rests above the rim */
  --card: 6px;   /* board thickness */

  --lw: calc(var(--bw) + var(--lo) * 2);
  --ld: calc(var(--bd) + var(--lo) * 2);

  /* Kraft: four steps of one warm brown - lit front, turned side, interior,
     and the dark inside the flutes. */
  --kraft-1: #d9b083;
  --kraft-2: #c2955f;
  --kraft-3: #a97c48;
  --kraft-4: #825c33;
  --kraft-in: #8d6740;
  --kraft-in-2: #3f2d1a;
  --kraft-ink: rgba(58, 42, 25, 0.78);

  position: relative;
  width: var(--bw);
  height: var(--bh);
  perspective: 2400px;
  perspective-origin: 50% 44%;
}

.vbox-tilt {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  /* A negative rotateX looks DOWN into the box; -16deg turns it to show the
     right-hand wall, as in the reference photograph. */
  transform: rotateX(-26deg) rotateY(-16deg);
  transition: transform 820ms cubic-bezier(0.22, 0.61, 0.24, 1);
  will-change: transform;
}

/* Hover is a hint, never a reveal: the box lifts and turns a degree or two. */
.vbox.is-closed:hover .vbox-tilt,
.vbox.is-closed:focus-within .vbox-tilt {
  transform: translateY(-12px) translateZ(34px) rotateX(-24deg) rotateY(-14deg);
  transition-duration: 420ms;
}

/* Open: a touch more from above and a touch less turned, so the interior
   shows and the statistics face the reader. */
.vbox.is-opening .vbox-tilt,
.vbox.is-open .vbox-tilt {
  transform: rotateX(-29deg) rotateY(-9deg);
}

/* --- the click target ---------------------------------------------------
   The scene is flattened by the time it paints, so this is an ordinary 2D
   overlay: no translateZ, no stacking surprises. It covers the object in
   both states and grows upward when open, so the raised statistics are part
   of the target too. */

.vbox-toggle {
  position: absolute;
  inset: -34px -44px -70px;
  z-index: 3;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 18px;
  cursor: pointer;
  transition: top 500ms var(--ease);
}

.vbox.is-opening .vbox-toggle,
.vbox.is-open .vbox-toggle {
  top: -300px;
}

.vbox-toggle:focus-visible {
  outline: 2px solid var(--emerald);
  outline-offset: 4px;
}

/* --- faces --------------------------------------------------------------
   Each face is centred on the object's origin with a negative margin and
   then pushed out to its own plane, so the geometry reads as a handful of
   translations rather than five positioning schemes. */

.vbox-base {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.vbox-face {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
}

/* Exterior, catching the light. */
.vbox-wall-front {
  width: var(--bw);
  height: var(--bh);
  margin: calc(var(--bh) / -2) 0 0 calc(var(--bw) / -2);
  transform: translateZ(calc(var(--bd) / 2));
  background-color: var(--kraft-1);
  /* the last layer is the paper tooth: a 3px grain, far too faint to read
     as stripes but enough that the face is not flat colour */
  background-image:
    linear-gradient(180deg, rgba(255, 255, 255, 0.17), rgba(255, 255, 255, 0) 62%),
    linear-gradient(0deg, rgba(50, 32, 14, 0.44), rgba(50, 32, 14, 0) 72%),
    repeating-linear-gradient(92deg, rgba(255, 255, 255, 0.04) 0 1px, rgba(0, 0, 0, 0.04) 1px 3px);
}

/* Exterior, turned away from the light. */
.vbox-wall-right {
  width: var(--bd);
  height: var(--bh);
  margin: calc(var(--bh) / -2) 0 0 calc(var(--bd) / -2);
  transform: translateX(calc(var(--bw) / 2)) rotateY(90deg);
  background-color: var(--kraft-3);
  background-image:
    linear-gradient(90deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0) 70%),
    linear-gradient(0deg, rgba(50, 32, 14, 0.5), rgba(50, 32, 14, 0) 76%),
    repeating-linear-gradient(92deg, rgba(255, 255, 255, 0.03) 0 1px, rgba(0, 0, 0, 0.045) 1px 3px);
}

/* Interior surfaces: the same board, in shade. */
.vbox-wall-back {
  width: var(--bw);
  height: var(--bh);
  margin: calc(var(--bh) / -2) 0 0 calc(var(--bw) / -2);
  transform: translateZ(calc(var(--bd) / -2));
  background-color: var(--kraft-in);
  background-image: linear-gradient(180deg, var(--kraft-in-2), var(--kraft-in) 82%);
}

.vbox-wall-left {
  width: var(--bd);
  height: var(--bh);
  margin: calc(var(--bh) / -2) 0 0 calc(var(--bd) / -2);
  transform: translateX(calc(var(--bw) / -2)) rotateY(90deg);
  background-color: var(--kraft-in);
  background-image: linear-gradient(180deg, var(--kraft-in-2), #6f5130 84%);
}

.vbox-floor {
  width: var(--bw);
  height: var(--bd);
  margin: calc(var(--bd) / -2) 0 0 calc(var(--bw) / -2);
  transform: rotateX(90deg) translateZ(calc(var(--bh) / -2));
  background-color: #5c4225;
  background-image:
    radial-gradient(70% 90% at 50% 8%, rgba(0, 0, 0, 0.55), transparent 70%),
    linear-gradient(180deg, #4a3520, #7a5833);
}

/* The cut edges. Cardboard is only convincing where the flutes show, and
   these are the two edges this view exposes. */
.vbox-edge {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
}

.vbox-edge-front {
  width: var(--bw);
  height: var(--card);
  margin: calc(var(--card) / -2) 0 0 calc(var(--bw) / -2);
  transform:
    translateY(calc(var(--bh) / -2))
    translateZ(calc(var(--bd) / 2 - var(--card) / 2))
    rotateX(90deg);
  background: repeating-linear-gradient(
    90deg,
    var(--kraft-2) 0 2px,
    var(--kraft-4) 2px 5px
  );
}

.vbox-edge-right {
  width: var(--card);
  height: var(--bd);
  margin: calc(var(--bd) / -2) 0 0 calc(var(--card) / -2);
  transform:
    translateX(calc(var(--bw) / 2 - var(--card) / 2))
    translateY(calc(var(--bh) / -2))
    rotateX(90deg);
  background: linear-gradient(90deg, var(--kraft-4), var(--kraft-2));
}

/* --- print on the base --------------------------------------------------
   One printed line, in ink that has soaked into brown board. Not a logo
   wall: the lid carries the mark. */

.vbox-print-front {
  position: absolute;
  left: 7%;
  bottom: 13%;
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--kraft-ink);
}

.vbox-print-rule {
  width: 54px;
  height: 2px;
  background: currentColor;
  opacity: 0.55;
}

/* --- the light inside ---------------------------------------------------
   Off while the box is shut. A glow leaking from a closed box is the kind of
   detail that reads as fake; the seam does that job instead, and only while
   something is knocking. */

.vbox-glow {
  position: absolute;
  left: 3%;
  right: 3%;
  top: -48%;
  height: 82%;
  transform: translateZ(-26px);
  background: radial-gradient(
    58% 54% at 50% 82%,
    rgba(74, 222, 128, 0.55),
    rgba(74, 222, 128, 0.16) 52%,
    transparent 78%
  );
  filter: blur(30px);
  opacity: 0;
  transition: opacity 620ms ease 60ms;
}

.vbox.is-opening .vbox-glow,
.vbox.is-open .vbox-glow {
  opacity: 1;
  transition-delay: 260ms;
}

/* Light along the join, only while the box is being knocked from inside. */
.vbox-seam {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--bw) - 24px);
  height: 5px;
  margin: 0 0 0 calc((var(--bw) - 24px) / -2);
  transform:
    translateY(calc(var(--bh) / -2 - var(--seam) / 2))
    translateZ(calc(var(--bd) / 2 + 2px));
  border-radius: 999px;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(134, 239, 172, 0.85) 22%,
    rgba(74, 222, 128, 0.95) 50%,
    rgba(134, 239, 172, 0.85) 78%,
    transparent
  );
  filter: blur(4px);
  opacity: 0;
}

/* --- the lid ------------------------------------------------------------
   A tray in its own right - a top panel, four skirts and an underside - so
   it caps the base the way a shoebox lid does and still looks solid once it
   is a foot in the air. */

.vbox-lid {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--lw);
  height: var(--lh);
  margin: calc(var(--lh) / -2) 0 0 calc(var(--lw) / -2);
  transform: translateY(calc(var(--bh) / -2 - var(--seam) - var(--lh) / 2));
  transform-style: preserve-3d;
}

.vbox-lid-swing {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: translate3d(0, 0, 0);
  transition: transform 820ms cubic-bezier(0.3, 0.86, 0.36, 1);
  will-change: transform;
}

/* Up, back, and turned a little: a lid lifted by hand is never square. */
.vbox.is-opening .vbox-lid-swing,
.vbox.is-open .vbox-lid-swing {
  transform: translate3d(0, -180px, -95px) rotateX(-7deg) rotateZ(-3.5deg);
}

.vbox-lid-knock {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.vbox-lid-top {
  width: var(--lw);
  height: var(--ld);
  margin: calc(var(--ld) / -2) 0 0 calc(var(--lw) / -2);
  transform: translateY(calc(var(--lh) / -2)) rotateX(90deg);
  padding: 30px 40px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  background-color: var(--kraft-1);
  background-image:
    linear-gradient(174deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0) 78%),
    radial-gradient(130% 110% at 24% 4%, rgba(255, 255, 255, 0.13), transparent 72%),
    repeating-linear-gradient(92deg, rgba(255, 255, 255, 0.04) 0 1px, rgba(0, 0, 0, 0.04) 1px 3px);
  box-shadow: inset 0 0 60px rgba(90, 60, 26, 0.22);
}

.vbox-lid-front,
.vbox-lid-back {
  width: var(--lw);
  height: var(--lh);
  margin: calc(var(--lh) / -2) 0 0 calc(var(--lw) / -2);
  background-color: var(--kraft-2);
  box-shadow: inset 0 -3px 5px -2px rgba(38, 24, 10, 0.75);
  background-image:
    linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(40, 26, 12, 0.42)),
    repeating-linear-gradient(92deg, rgba(255, 255, 255, 0.03) 0 1px, rgba(0, 0, 0, 0.045) 1px 3px);
}

.vbox-lid-front {
  transform: translateZ(calc(var(--ld) / 2));
}

.vbox-lid-back {
  transform: translateZ(calc(var(--ld) / -2)) rotateY(180deg);
}

.vbox-lid-left,
.vbox-lid-right {
  width: var(--ld);
  height: var(--lh);
  margin: calc(var(--lh) / -2) 0 0 calc(var(--ld) / -2);
  background-color: var(--kraft-3);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.12), rgba(40, 26, 12, 0.38));
}

.vbox-lid-left {
  transform: translateX(calc(var(--lw) / -2)) rotateY(90deg);
}

.vbox-lid-right {
  transform: translateX(calc(var(--lw) / 2)) rotateY(90deg);
}

.vbox-lid-under {
  width: var(--lw);
  height: var(--ld);
  margin: calc(var(--ld) / -2) 0 0 calc(var(--lw) / -2);
  transform: translateY(calc(var(--lh) / 2)) rotateX(-90deg);
  background: linear-gradient(180deg, #6f5130, #4a3520);
}

/* --- branding, printed on the lid --------------------------------------- */

.vbox-lid-brand {
  display: flex;
  align-items: center;
  gap: 14px;
}

.vbox-lid-brand img {
  width: 34px;
  height: 34px;
  border-radius: 7px;
  /* printed, not applied: the mark gives a little back to the brown board */
  opacity: 0.94;
  mix-blend-mode: multiply;
}

.vbox-lid-word {
  font-family: var(--display);
  font-size: 2rem;
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 1;
  color: #3d2c19;
}

.vbox-lid-rule {
  display: block;
  height: 3px;
  width: 168px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--emerald-deep), rgba(21, 128, 61, 0));
  opacity: 0.85;
}

.vbox-lid-meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-10);
  font-family: var(--mono);
  font-size: var(--text-xs);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--kraft-ink);
}

/* The only instruction on the object, and it is printed on the box rather
   than floated over it. */
.vbox-lid-open {
  padding: 5px 12px;
  border: 1.5px solid rgba(58, 42, 25, 0.45);
  border-radius: 4px;
  transition: opacity 320ms var(--ease);
}

.vbox.is-opening .vbox-lid-open,
.vbox.is-open .vbox-lid-open {
  opacity: 0;
}

/* --- shadows ------------------------------------------------------------ */

/* Contact shadow: its own horizontal plane on the ground, so depth costs an
   opacity change rather than a box-shadow repaint. */
.vbox-ground {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--bw) + 150px);
  height: calc(var(--bd) + 260px);
  margin: calc((var(--bd) + 260px) / -2) 0 0 calc((var(--bw) + 150px) / -2);
  transform: rotateX(90deg) translateZ(calc(var(--bh) / -2 - 2px)) translateY(60px);
  border-radius: 50%;
  background: radial-gradient(
    closest-side,
    rgba(0, 0, 0, 0.92),
    rgba(0, 0, 0, 0.55) 48%,
    transparent 78%
  );
  filter: blur(34px);
  transition: transform 500ms var(--ease), opacity 500ms var(--ease);
}

.vbox.is-closed:hover .vbox-ground {
  transform: rotateX(90deg) translateZ(calc(var(--bh) / -2 - 2px)) translateY(60px) scale(1.07);
  opacity: 0.8;
}

/* What the lid leaves behind on the rim: sharp while it is seated, gone by
   the time it is in the air. */
.vbox-cast {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--lw);
  height: var(--ld);
  margin: calc(var(--ld) / -2) 0 0 calc(var(--lw) / -2);
  transform: rotateX(90deg) translateZ(calc(var(--bh) / 2 - 4px));
  border-radius: 20px;
  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.75), transparent 78%);
  filter: blur(10px);
  opacity: 0.9;
  transition: opacity 700ms var(--ease), filter 700ms var(--ease);
}

.vbox.is-opening .vbox-cast,
.vbox.is-open .vbox-cast {
  opacity: 0.22;
  filter: blur(26px);
}

/* --- what is inside -----------------------------------------------------
   The statistics stand on the floor of the base and rise until they crest
   the rim. The front wall clips their feet, which is the whole trick: they
   are not floating above a box, they are standing in one.

   Two transforms, two elements: the list carries the rise, each card carries
   its own entrance, so the stagger cannot fight the travel. */

.vbox-contents {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--bw) - 56px);
  margin-left: calc((var(--bw) - 56px) / -2);
  transform-style: preserve-3d;
  pointer-events: none;
}

.vbox-stats {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  margin: 0;
  padding: 0;
  transform-style: preserve-3d;
  transform: translateY(-50px);
  transition: transform 760ms cubic-bezier(0.22, 0.61, 0.24, 1);
}

/*
  The height at which the front wall lands on the cards' padded foot: high
  enough that every line of the sentence clears the rim, low enough that the
  cards are still visibly cut off by it. Any less and they are swallowed;
  any more and they float above the box instead of standing in it.

  There is deliberately no `.is-closing` rule anywhere in this component.
  Closing is simply the absence of the open selectors, which hands every
  layer back to the closed values it already has - and to the reverse
  transition-delays below, so the sequence plays backwards for free.
*/
.vbox.is-opening .vbox-stats,
.vbox.is-open .vbox-stats {
  transform: translateY(-254px);
}

.vbox-stat {
  display: grid;
  gap: 10px;
  align-content: start;
  min-height: 220px;
  /* the deep foot is deliberate: it is the part the front wall clips */
  padding: var(--space-5) var(--space-5) 52px;
  border-radius: var(--radius-panel);
  border: 1px solid rgba(148, 175, 214, 0.22);
  /* the application's panel, not a new one: ink surfaces, a hairline, one
     inset highlight, and the green spent on the index and the glow */
  background: linear-gradient(165deg, rgba(31, 44, 71, 0.94), rgba(10, 16, 32, 0.92));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 26px 48px -28px rgba(0, 0, 0, 0.95),
    0 0 34px -18px rgba(74, 222, 128, 0.5);
  opacity: 0;
  transform: translateY(80px);
  transition:
    opacity 420ms ease,
    transform 640ms cubic-bezier(0.22, 0.61, 0.24, 1);
}

.vbox.is-opening .vbox-stat,
.vbox.is-open .vbox-stat {
  opacity: 1;
  transform: translateY(0);
}

/* Opening: left to right. Closing: the reverse. */
.vbox.is-opening .vbox-stat[data-layer='1'],
.vbox.is-open .vbox-stat[data-layer='1'] { transition-delay: 300ms; }
.vbox.is-opening .vbox-stat[data-layer='2'],
.vbox.is-open .vbox-stat[data-layer='2'] { transition-delay: 400ms; }
.vbox.is-opening .vbox-stat[data-layer='3'],
.vbox.is-open .vbox-stat[data-layer='3'] { transition-delay: 500ms; }

.vbox-stat[data-layer='1'] { transition-delay: 140ms; }
.vbox-stat[data-layer='2'] { transition-delay: 70ms; }
.vbox-stat[data-layer='3'] { transition-delay: 0ms; }

.vbox-stat-index {
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.18em;
  color: var(--emerald);
}

.vbox-stat-figure {
  font-family: var(--display);
  font-size: 2.625rem;
  font-weight: 600;
  letter-spacing: -0.05em;
  line-height: 1;
  color: var(--on-ink);
  font-variant-numeric: tabular-nums;
}

.vbox-stat-copy {
  font-size: var(--text-sm);
  line-height: 1.55;
  color: rgba(234, 240, 250, 0.68);
}

/* --- the agitation ------------------------------------------------------
   Something inside wants out. It happens once per approach, it lasts under
   two seconds, and it ends completely still. The box moves; the page does
   not. */

.vbox.is-shaking {
  animation: vbox-agitate 1800ms linear both;
}

.vbox.is-shaking .vbox-lid-knock {
  animation: vbox-knock 1800ms linear both;
}

.vbox.is-shaking .vbox-seam {
  animation: vbox-seam 1800ms linear both;
}

@keyframes vbox-agitate {
  0%, 5% { transform: translate3d(0, 0, 0) rotate(0deg); }

  /* first, small */
  9% { transform: translate3d(-2px, 0, 0) rotate(-0.14deg); }
  12% { transform: translate3d(2px, -1px, 0) rotate(0.14deg); }
  15% { transform: translate3d(-2px, 0, 0) rotate(-0.11deg); }
  18% { transform: translate3d(1px, 0, 0) rotate(0.08deg); }

  /* a beat of nothing */
  21%, 30% { transform: translate3d(0, 0, 0) rotate(0deg); }

  /* stronger */
  34% { transform: translate3d(-4px, -2px, 0) rotate(-0.3deg); }
  38% { transform: translate3d(4px, 0, 0) rotate(0.28deg); }
  42% { transform: translate3d(-4px, -3px, 0) rotate(-0.26deg); }
  46% { transform: translate3d(3px, -1px, 0) rotate(0.2deg); }
  50% { transform: translate3d(-2px, 0, 0) rotate(-0.12deg); }

  /* the lid pops here */
  54%, 59% { transform: translate3d(0, 0, 0) rotate(0deg); }

  /* strongest */
  63% { transform: translate3d(-6px, -3px, 0) rotate(-0.42deg); }
  67% { transform: translate3d(6px, -1px, 0) rotate(0.4deg); }
  71% { transform: translate3d(-5px, -4px, 0) rotate(-0.36deg); }
  75% { transform: translate3d(5px, -1px, 0) rotate(0.3deg); }
  79% { transform: translate3d(-3px, -2px, 0) rotate(-0.18deg); }
  83% { transform: translate3d(2px, 0, 0) rotate(0.1deg); }

  /* and the last knock settles it */
  87% { transform: translate3d(-1px, -1px, 0) rotate(-0.05deg); }
  92%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}

@keyframes vbox-knock {
  0%, 33% { transform: translate3d(0, 0, 0) rotateZ(0deg); }
  37% { transform: translate3d(0, -4px, 0) rotateZ(-0.2deg); }
  41% { transform: translate3d(0, -1px, 0) rotateZ(0.1deg); }
  45%, 52% { transform: translate3d(0, 0, 0) rotateZ(0deg); }

  /* the first real lift */
  55% { transform: translate3d(0, -9px, 0) rotateZ(-0.4deg); }
  59% { transform: translate3d(0, -2px, 0) rotateZ(0.16deg); }
  62%, 84% { transform: translate3d(0, 0, 0) rotateZ(0deg); }

  /* the last, and highest */
  88% { transform: translate3d(0, -14px, 2px) rotateZ(0.55deg); }
  92% { transform: translate3d(0, -4px, 0) rotateZ(-0.22deg); }
  96%, 100% { transform: translate3d(0, 0, 0) rotateZ(0deg); }
}

@keyframes vbox-seam {
  0%, 6% { opacity: 0; }
  14% { opacity: 0.22; }
  24% { opacity: 0.08; }
  38% { opacity: 0.45; }
  52% { opacity: 0.18; }
  57% { opacity: 0.68; }
  70% { opacity: 0.3; }
  88% { opacity: 0.9; }
  94% { opacity: 0.25; }
  100% { opacity: 0; }
}

/* --- laptop ------------------------------------------------------------- */

@media (max-width: 1080px) {
  .vbox-stage {
    height: 470px;
    padding-bottom: 92px;
  }

  .vbox {
    --bw: 540px;
    --bd: 210px;
    --bh: 175px;
    --lh: 30px;
    --lo: 9px;
    perspective: 2000px;
  }

  .vbox-stat {
    min-height: 200px;
    padding: var(--space-4) var(--space-4) 46px;
  }

  .vbox-stat-figure {
    font-size: 2.125rem;
  }

  .vbox.is-opening .vbox-stats,
  .vbox.is-open .vbox-stats {
    transform: translateY(-214px);
  }

  .vbox.is-opening .vbox-lid-swing,
  .vbox.is-open .vbox-lid-swing {
    transform: translate3d(0, -160px, -85px) rotateX(-7deg) rotateZ(-3.5deg);
  }

  .vbox-stat-copy {
    font-size: var(--text-xs);
  }

  .vbox-lid-top { padding: 22px 30px; }
  .vbox-lid-word { font-size: 1.625rem; }
  .vbox-lid-brand img { width: 28px; height: 28px; }
  .vbox-lid-rule { width: 130px; }
}

/* --- tablet ------------------------------------------------------------- */

@media (max-width: 760px) {
  .vbox-stage {
    height: 605px;
    padding-bottom: 80px;
  }

  .vbox {
    --bw: 400px;
    --bd: 190px;
    --bh: 190px;
    --lh: 28px;
    --lo: 8px;
    perspective: 1600px;
  }

  /* Three across stops being readable here, so they stack - still inside,
     still one card each, the figure simply moves beside the sentence. */
  .vbox-stats {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  .vbox-stat {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      'index  copy'
      'figure copy';
    align-items: center;
    column-gap: 16px;
    row-gap: 2px;
    min-height: 0;
    padding: 14px var(--space-4);
  }

  .vbox-stat:last-child {
    padding-bottom: 48px;
  }

  .vbox-stat-index { grid-area: index; }
  .vbox-stat-figure { grid-area: figure; font-size: 1.875rem; }
  .vbox-stat-copy { grid-area: copy; font-size: var(--text-xs); line-height: 1.5; }

  .vbox.is-opening .vbox-stats,
  .vbox.is-open .vbox-stats {
    transform: translateY(-298px);
  }

  .vbox.is-opening .vbox-lid-swing,
  .vbox.is-open .vbox-lid-swing {
    transform: translate3d(0, -248px, -105px) rotateX(-2deg) rotateZ(-3.5deg);
  }
}

/* --- phone -------------------------------------------------------------- */

@media (max-width: 520px) {
  .boxlab {
    padding: var(--space-20) 0 var(--space-16);
  }

  .vbox-stage {
    height: 570px;
    padding-bottom: 52px;
  }

  .vbox {
    --bw: 265px;
    --bd: 170px;
    --bh: 175px;
    --lh: 24px;
    --lo: 7px;
    --seam: 4px;
    --card: 5px;
    perspective: 1200px;
  }

  /* Less turn, so 290px of box never reaches the edge of a 320px screen. */
  .vbox-tilt {
    transform: rotateX(-24deg) rotateY(-9deg);
  }

  .vbox.is-opening .vbox-tilt,
  .vbox.is-open .vbox-tilt {
    transform: rotateX(-26deg) rotateY(-5deg);
  }

  .vbox-contents {
    width: calc(var(--bw) - 30px);
    margin-left: calc((var(--bw) - 30px) / -2);
  }

  .vbox-stat {
    padding: 11px 14px;
    column-gap: 12px;
  }

  .vbox-stat:last-child {
    padding-bottom: 44px;
  }

  .vbox-stat-figure { font-size: 1.625rem; }
  .vbox-stat-copy { font-size: 0.7rem; line-height: 1.45; }

  .vbox.is-opening .vbox-stats,
  .vbox.is-open .vbox-stats {
    transform: translateY(-345px);
  }

  .vbox.is-opening .vbox-lid-swing,
  .vbox.is-open .vbox-lid-swing {
    transform: translate3d(0, -272px, -95px) rotateX(2deg) rotateZ(-3.5deg);
  }

  .vbox-lid-top { padding: 16px 20px; gap: 8px; }
  .vbox-lid-word { font-size: 1.25rem; }
  .vbox-lid-brand { gap: 9px; }
  .vbox-lid-brand img { width: 22px; height: 22px; }
  .vbox-lid-rule { width: 92px; height: 2px; }
  .vbox-lid-meta { font-size: 0.6rem; letter-spacing: 0.14em; }
  .vbox-print-front { font-size: 0.6rem; letter-spacing: 0.16em; }
  .vbox-print-rule { width: 28px; }
}

/* --- motion off ---------------------------------------------------------
   The box keeps its shape and the lid still comes off: that is the content,
   not the decoration. What goes is the agitation, the travel and the
   stagger. */

@media (prefers-reduced-motion: reduce) {
  .vbox.is-shaking,
  .vbox.is-shaking .vbox-lid-knock,
  .vbox.is-shaking .vbox-seam {
    animation: none;
  }

  .vbox-tilt,
  .vbox.is-closed:hover .vbox-tilt,
  .vbox.is-closed:focus-within .vbox-tilt,
  .vbox.is-opening .vbox-tilt,
  .vbox.is-open .vbox-tilt {
    transform: rotateX(-26deg) rotateY(-16deg);
    transition: none;
  }

  .vbox-lid-swing,
  .vbox-ground,
  .vbox-cast,
  .vbox-stats,
  .vbox-stat,
  .vbox.is-opening .vbox-stat,
  .vbox.is-open .vbox-stat,
  .vbox.is-opening .vbox-stat[data-layer='1'],
  .vbox.is-open .vbox-stat[data-layer='1'],
  .vbox.is-opening .vbox-stat[data-layer='2'],
  .vbox.is-open .vbox-stat[data-layer='2'],
  .vbox.is-opening .vbox-stat[data-layer='3'],
  .vbox.is-open .vbox-stat[data-layer='3'] {
    transition-duration: 200ms;
    transition-delay: 0ms;
  }
}

/* ==========================================================================
   Homepage background: drifting glass panels
   ==========================================================================
   Depth behind the two DARK grounds - the hero and the closing CTA - and
   nowhere else. The paper sections in between are an editorial reading
   surface; putting panels behind body copy would be decoration fighting the
   text, and the page already has real depth there in the product pane and
   the loop screen.

   Three decisions worth recording.

   1. NO backdrop-filter below 900px, and none at all without @supports.

      Frosted glass is normally backdrop-filter, but these sit on a nearly
      flat ground: there is little behind them to blur, so on a phone it
      would cost a full-screen GPU pass for an effect nobody can see. The
      convincing part of "glass" here is layered translucency, a hairline
      border, a lit top edge and a wide soft shadow - all free. Desktop,
      where the hero's emerald pools give it something to actually work on,
      opts in.

   2. Only transform is animated.

      Compositor-only, so drifting costs no layout and no paint. Durations
      are 54-76s with negative delays, which starts every panel at a
      different point in its cycle - otherwise they all move in step and the
      eye immediately reads it as an animation rather than as depth.

   3. The panels are inert.

      pointer-events: none and aria-hidden on the container, so they can
      neither swallow a click nor reach a screen reader.
*/

.closer {
  position: relative;
}

/* The hero already clips; the closer needs to, so a panel can sit half off
   the edge without widening the page. */
.closer {
  overflow: hidden;
}

/* Content sits above the field. Without this the panels would be painted in
   the same stacking order as the copy. */
.closer-inner {
  position: relative;
  z-index: 1;
}

.glass-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.glass-card {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  width: var(--w, 240px);
  display: grid;
  gap: 9px;
  align-content: start;
  padding: 14px 16px 16px;
  border-radius: 14px;

  /*
    The glass itself. A diagonal wash so the top-left edge catches more
    light than the bottom-right, a hairline to define the shape, an inset
    highlight along the top edge, and a wide shadow to lift it off the
    ground. Nothing here is a solid fill, so whatever is behind still reads
    through.
  */
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: linear-gradient(
    152deg,
    rgba(255, 255, 255, 0.06),
    rgba(255, 255, 255, 0.015) 58%,
    rgba(255, 255, 255, 0.035)
  );
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 30px 70px -34px rgba(3, 8, 20, 0.95);

  opacity: var(--o, 0.45);
  transform: translate3d(0, 0, 0) rotate(var(--rot, 0deg));
  animation: glass-drift var(--dur, 60s) var(--delay, 0s) ease-in-out infinite alternate;
}

/* Only the two largest are promoted: will-change on every panel costs more
   memory than it saves. */
.glass-card.is-keep {
  will-change: transform;
}

@keyframes glass-drift {
  from {
    transform: translate3d(0, 0, 0) rotate(var(--rot, 0deg));
  }
  to {
    transform: translate3d(var(--dx, 12px), var(--dy, -14px), 0) rotate(var(--rot, 0deg));
  }
}

/* --- the details inside a panel ----------------------------------------- */

.gc-head {
  height: 6px;
  width: 38%;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.16);
}

.gc-row {
  height: 4px;
  width: var(--fill, 60%);
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.09);
}

.gc-bars {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 40px;
}

.gc-bars i {
  flex: 1;
  height: var(--h, 50%);
  border-radius: 2px 2px 0 0;
  background: rgba(255, 255, 255, 0.11);
}

/* One bar per panel picks up the accent, the way a real chart has a subject. */
.gc-bars i.is-accent {
  background: rgba(74, 222, 128, 0.22);
}

.gc-label {
  font-family: var(--mono);
  font-size: 0.5625rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.13);
}

.gc-metric {
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  color: rgba(255, 255, 255, 0.15);
  font-variant-numeric: tabular-nums;
}

.gc-spark {
  display: block;
  width: 100%;
  height: 26px;
  color: rgba(74, 222, 128, 0.24);
}

.gc-spark polyline {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* --- real frosting, where it can actually be seen ----------------------- */

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  @media (min-width: 900px) {
    .glass-card {
      -webkit-backdrop-filter: blur(10px) saturate(115%);
      backdrop-filter: blur(10px) saturate(115%);
    }
  }
}

/* --- motion off -------------------------------------------------------- */

/*
  Not simply "animation: none", which would leave every panel parked at the
  start of its cycle. Each is placed at the midpoint of the drift it would
  have made, so the still composition is the one that was designed rather
  than an accident of where the animation began.
*/
@media (prefers-reduced-motion: reduce) {
  .glass-card {
    animation: none;
    transform: translate3d(calc(var(--dx, 12px) / 2), calc(var(--dy, -14px) / 2), 0)
      rotate(var(--rot, 0deg));
  }
}

/* --- small screens ------------------------------------------------------ */

/*
  A phone shows two panels, not seven. There is far less room for them to sit
  clear of the text, and seven translucent layers plus a blur is exactly the
  kind of thing that makes a marketing page feel slow on a mid-range handset.
*/
@media (max-width: 760px) {
  .glass-card {
    display: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .glass-card.is-keep {
    display: grid;
    width: min(var(--w, 240px), 62vw);
    opacity: calc(var(--o, 0.45) * 0.8);
  }
}

/* ==========================================================================
   Inventory, in motion
   ==========================================================================
   A standalone section. Every selector below is either .veyra-inventory-
   timeline or a vit- prefixed class inside it: nothing here can reach another
   part of the page, and deleting this block deletes the section cleanly.

   The stations sit on a curve that sweeps under the hub. The curve is the
   timeline - stock, usage, prediction, reorder - and the light runs along it
   toward the centre, because that is the direction the readings travel.

   Selection is a click. Hover only lifts a station, so a phone gets the same
   section a desktop does.
   ========================================================================== */

.veyra-inventory-timeline {
  position: relative;
  isolation: isolate;
  padding: var(--space-32) 0 var(--space-24);
  background: #04060a;
  color: #e9f0fb;
  overflow: hidden;

  --vit-edge: rgba(255, 255, 255, 0.1);
  --vit-edge-lit: rgba(120, 190, 235, 0.55);
  --vit-blue: #3ea2d3;
  --vit-glow: rgba(62, 162, 211, 0.45);
  --vit-dim: #8394ad;

  /* The three states a product is allowed to be in, and the only colours the
     section changes. Everything else stays blue whatever happens. */
  --vit-healthy: #4ade80;
  --vit-watch: #f3b93f;
  --vit-urgent: #ff7a7a;
}

/* One source of light behind the middle, so the black is not flat. */
.veyra-inventory-timeline::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    56% 44% at 50% 34%,
    rgba(27, 135, 189, 0.15),
    rgba(20, 106, 153, 0.04) 46%,
    rgba(4, 6, 10, 0) 76%
  );
}

.vit-inner {
  position: relative;
  z-index: 2;
}

/* --- the far ambience --------------------------------------------------- */

.vit-ambient {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.vit-mote {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: calc(150px * var(--s, 1));
  height: calc(150px * var(--s, 1));
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(62, 162, 211, 0.12),
    rgba(62, 162, 211, 0) 68%
  );
  filter: blur(6px);
  animation: vit-adrift var(--dur, 80s) var(--delay, 0s) ease-in-out infinite alternate;
}

@keyframes vit-adrift {
  from {
    transform: translate3d(0, 0, 0) scale(1);
  }
  to {
    transform: translate3d(26px, -30px, 0) scale(1.14);
  }
}

/* --- the words ---------------------------------------------------------- */

.vit-head {
  max-width: 42rem;
  margin: 0 auto var(--space-12);
  text-align: center;
}

.vit-eyebrow {
  margin: 0 0 var(--space-3);
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--vit-blue);
}

.veyra-inventory-timeline h2 {
  margin: 0 0 var(--space-4);
  font-size: clamp(2rem, 3.8vw, 3rem);
  letter-spacing: -0.035em;
  color: #f4f8ff;
}

.vit-lead {
  margin: 0;
  color: var(--vit-dim);
  font-size: var(--text-md);
  line-height: 1.65;
}

/* --- the stage ---------------------------------------------------------- */

.vit-stage {
  position: relative;
  /* Tall enough that the lowest product and its caption finish inside the
     stage. The stations are placed as a share of this box, so the box has to
     hold the tallest one at its lowest point of the drift, plus its name. */
  height: clamp(38rem, 53vw, 47rem);
  perspective: 1500px;
  perspective-origin: 50% 34%;
}

.vit-flow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 1;
}

/* The curve itself: the quietest line on the stage until something happens
   on it. */
.vit-flow-line {
  fill: none;
  stroke: rgba(120, 190, 235, 0.18);
  stroke-width: 1;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.vit-link {
  fill: none;
  stroke: rgba(120, 190, 235, 0.14);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  transition: stroke 0.45s ease, stroke-width 0.45s ease, opacity 0.45s ease;
}

.vit-link.is-lit {
  stroke: var(--vit-blue);
  stroke-width: 1.7;
  filter: drop-shadow(0 0 5px var(--vit-glow));
}

.is-selected .vit-link:not(.is-lit) {
  opacity: 0.35;
}

/*
  One light per connector, running toward the core. Small, and dimmer than
  the spark on the main curve, because five of them are on screen at once and
  the point is traffic rather than announcement.
*/
.vit-bead {
  fill: #cfeeff;
  opacity: 0;
  filter: drop-shadow(0 0 5px var(--vit-glow));
  transition: fill 0.4s ease;
}

.is-selected .vit-bead {
  opacity: 0.35 !important;
}

/* --- the hub ------------------------------------------------------------ */

/*
  The centrepiece. It is decorative from the pointer's side - it can never
  take a click meant for a station - and its contents are a grid, so the
  mark, the wordmark, the tagline and the status each own a row and cannot
  collide however long any of them gets.
*/
.vit-hub {
  position: absolute;
  left: 50%;
  top: 30%;
  translate: -50% -50%;
  z-index: 3;
  display: grid;
  place-items: center;
  pointer-events: none;
  transition: translate 0.6s cubic-bezier(0.22, 0.61, 0.36, 1),
    scale 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* When a product is being read, the hub lifts a little and makes room for
   the panel below it. */
.is-selected .vit-hub {
  translate: -50% -62%;
  scale: 0.92;
}

.vit-halo {
  position: absolute;
  width: 23rem;
  height: 23rem;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(62, 162, 211, 0.2),
    rgba(27, 135, 189, 0.06) 46%,
    rgba(4, 6, 10, 0) 70%
  );
  animation: vit-breathe 7s ease-in-out infinite;
}

/*
  The ring leaves from outside the glass, never from inside it. Starting it
  small looked better in isolation and was wrong here: it swept up across the
  wordmark and the status line on its way out.
*/
.vit-pulse {
  position: absolute;
  width: 19rem;
  height: 19rem;
  border-radius: 50%;
  border: 1px solid rgba(62, 162, 211, 0.4);
  opacity: 0;
  animation: vit-ring 7s cubic-bezier(0.16, 0.7, 0.3, 1) infinite;
}

@keyframes vit-breathe {
  0%,
  100% {
    opacity: 0.7;
    transform: scale(1);
  }
  50% {
    opacity: 1;
    transform: scale(1.05);
  }
}

@keyframes vit-ring {
  0% {
    opacity: 0;
    transform: scale(1);
  }
  12% {
    opacity: 0.6;
  }
  45%,
  100% {
    opacity: 0;
    transform: scale(1.55);
  }
}

/* ==========================================================================
   The core
   --------------------------------------------------------------------------
   An earlier pass put the mark inside a translucent cube. The cube was the
   problem: six panes of glass is a container, and what the middle of this
   section needs to be is a system - the thing the five products report to.

   So there is no box. There are three hairline dials, two arcs of them lit
   and turning at rates that never line up, the brand asset at the centre,
   and the four readings the system takes, stacked in the order it takes
   them. Every connector on the stage ends on the outer dial, and choosing a
   product lights the reading it belongs to.
   ========================================================================== */

.vit-core {
  --vit-dial: clamp(15rem, 23vw, 20rem);
  position: relative;
  display: grid;
  place-items: center;
  width: var(--vit-dial);
  height: var(--vit-dial);
}

/* --- the dials ----------------------------------------------------------- */

.vit-dial {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.vit-dial circle {
  fill: none;
  vector-effect: non-scaling-stroke;
}

.vit-dial-rim {
  stroke: rgba(126, 196, 240, 0.26);
  stroke-width: 1;
}

.vit-dial-rim.is-faint {
  stroke: rgba(126, 196, 240, 0.12);
}

/*
  One arc of each dial, lit. Drawn as a dash on the full circle and turned,
  which is a transform on a stroke and so costs nothing; the two periods
  share no common multiple, so the pair never returns to where it started.
*/
.vit-dial-arc {
  stroke: var(--vit-blue);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-dasharray: 150 805;
  opacity: 0.75;
  filter: drop-shadow(0 0 6px var(--vit-glow));
  transform-box: view-box;
  transform-origin: 50% 50%;
  animation: vit-dial-turn 23s linear infinite;
}

.vit-dial-arc.is-inner {
  stroke-width: 1.1;
  stroke-dasharray: 96 727;
  opacity: 0.5;
  animation: vit-dial-turn 31s linear infinite reverse;
}

@keyframes vit-dial-turn {
  to {
    transform: rotate(360deg);
  }
}

/* The light the core sits in. A radial with no edge, so the dials appear to
   be lit from the middle rather than drawn on a disc. */
.vit-core::before {
  content: '';
  position: absolute;
  inset: 6%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(10, 20, 34, 0.92) 0%,
    rgba(8, 15, 26, 0.72) 48%,
    rgba(4, 6, 10, 0) 78%
  );
}

/* --- what the core says -------------------------------------------------- */

.vit-plate {
  position: relative;
  display: grid;
  justify-items: center;
  row-gap: 4px;
  width: 74%;
  text-align: center;
}

/* The brand asset, cut out of the lockup by scripts/mark-cutout.mjs: the same
   file the opening frame uses, at a tenth of the size. */
.vit-core-mark {
  width: clamp(4.3rem, 6.6vw, 6rem);
  height: auto;
  margin-bottom: 2px;
  filter: drop-shadow(0 0 16px rgba(62, 162, 211, 0.55));
}

.vit-wordmark {
  font-family: var(--display);
  font-size: clamp(1.1rem, 1.5vw, 1.32rem);
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.16;
  color: #f7fbff;
}

.vit-role {
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  line-height: 1.4;
  color: rgba(150, 180, 208, 0.7);
}

/* --- the four readings --------------------------------------------------- */

/*
  A ladder, not a list: one rail down the left with a light falling through
  it, and four nodes on it. The rail is the ::before of the whole list, so
  the four rows own nothing but their own dot and word.
*/
.vit-ladder {
  position: relative;
  display: grid;
  gap: 1px;
  margin: 10px 0 0;
  padding: 0 0 0 16px;
  list-style: none;
  justify-items: start;
  /* The falling light is clipped to the ladder, so it arrives at the last
     reading and stops there rather than running on past it. */
  overflow: hidden;
}

.vit-ladder::before {
  content: '';
  position: absolute;
  left: 3px;
  top: 7px;
  bottom: 7px;
  width: 1px;
  background: linear-gradient(
    to bottom,
    rgba(126, 196, 240, 0.08),
    rgba(126, 196, 240, 0.3),
    rgba(126, 196, 240, 0.08)
  );
}

/* The light that falls. Clipped to the rail, so it is the rail that carries
   it rather than a dot drawn beside one. */
.vit-ladder::after {
  content: '';
  position: absolute;
  left: 3px;
  top: 7px;
  width: 1px;
  height: 22%;
  background: linear-gradient(to bottom, transparent, var(--vit-blue));
  box-shadow: 0 0 7px var(--vit-glow);
  animation: vit-ladder-fall 4.6s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}

@keyframes vit-ladder-fall {
  0% { transform: translateY(-30%); opacity: 0; }
  18% { opacity: 1; }
  82% { opacity: 1; }
  100% { transform: translateY(330%); opacity: 0; }
}

.vit-rung {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
  transition: color 0.4s ease;
}

.vit-rung i {
  position: absolute;
  left: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1px solid rgba(126, 196, 240, 0.45);
  background: #070c14;
  transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}

.vit-rung b {
  font-family: var(--mono);
  font-size: var(--text-2xs);
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(146, 172, 198, 0.62);
  transition: color 0.4s ease;
}

/* The one rung that belongs to what is being read. */
.vit-rung.is-lit i {
  background: var(--vit-blue);
  border-color: var(--vit-blue);
  box-shadow: 0 0 10px var(--vit-glow);
}

.vit-rung.is-lit b {
  color: #eaf4ff;
}

/* --- the stations ------------------------------------------------------- */

/*
  The rail is a positioning context and nothing else. It is preserve-3d and
  the stations sit at different depths inside it, so if it took pointers it
  would swallow the ones behind its own plane - which is exactly how a set of
  cards like this ends up with only the frontmost one working.
*/
.vit-rail {
  position: absolute;
  inset: 0;
  z-index: 2;
  transform-style: preserve-3d;
  pointer-events: none;
}

/*
  A station is not a card. It is a product hanging in the room with its name
  under it, so there is no panel, no border, no glass and no backdrop filter
  anywhere below this line - the cutout's own alpha is the whole shape, and
  the shadow and the glow are cast from that silhouette rather than from a
  box.

  Three elements carry the motion, deliberately, because one cannot:

    .vit-station   selection and hover only - never the drift
    .vit-drift     the rise and fall
    .vit-sway      the side-to-side
    .vit-frame     the tilt and the breath, on the object alone

  Each runs on its own duration and its own negative delay, so the five never
  line up and none of them is ever at the top of its arc at the same moment.
  The name, the count and the status dot sit inside the drifting element, so
  they hang with the product instead of beside it.
*/
.vit-station {
  position: absolute;
  left: var(--x);
  top: var(--y);
  z-index: 2;
  pointer-events: auto;

  display: grid;
  justify-items: center;
  width: 9.5rem;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  cursor: pointer;

  /*
    Two properties, two jobs. `translate` carries the parallax, which
    veyra-timeline.js eases into --px and --py on the stage; `transform`
    carries hover and selection. Keeping them apart is what lets a station be
    lifted by a hover while it is still answering the pointer's position -
    one property cannot hold both without one of them winning.

    --depth is written per product: the ones low on the stage read as nearer
    and travel further.
  */
  translate:
    calc(-50% + var(--px, 0) * var(--depth, 12px))
    calc(-50% + var(--py, 0) * var(--depth, 12px) * 0.62);
  transform: translate3d(0, 0, 0);
  transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.5s ease;
}

.vit-drift,
.vit-sway {
  display: grid;
  justify-items: center;
  width: 100%;
}

.vit-drift {
  animation: vit-lift var(--lift-dur, 5.4s) var(--lift-delay, 0s)
    cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}

.vit-sway {
  row-gap: var(--space-2);
  animation: vit-sway var(--sway-dur, 8.4s) var(--sway-delay, 0s)
    cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}

/* Vertical travel is the full --lift, centred on where the station actually
   sits, so nothing is ever drawn off its own position. */
@keyframes vit-lift {
  from {
    transform: translateY(calc(var(--lift, 11px) / 2));
  }
  to {
    transform: translateY(calc(var(--lift, 11px) / -2));
  }
}

@keyframes vit-sway {
  from {
    transform: translateX(calc(var(--sway, 5px) / -2));
  }
  to {
    transform: translateX(calc(var(--sway, 5px) / 2));
  }
}

/* The object alone tilts and breathes - the label under it stays level. */
@keyframes vit-tilt {
  from {
    transform: rotate(calc(var(--tilt, 0.8deg) * -1)) scale(0.988);
  }
  to {
    transform: rotate(var(--tilt, 0.8deg)) scale(1.012);
  }
}

/*
  The product itself. No crop, no frame, no container: these are cutouts with
  their own alpha, so the shadow is cast from the silhouette and the glow sits
  behind it as light rather than as a panel.
*/
.vit-frame {
  position: relative;
  display: block;
  width: 100%;
  animation: vit-tilt var(--tilt-dur, 11s) var(--tilt-delay, 0s)
    cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
}

/* The light it hangs in. A radial gradient has no edge, so it separates the
   object from the black without drawing anything around it. */
.vit-frame::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 54%;
  width: 150%;
  height: 120%;
  translate: -50% -50%;
  pointer-events: none;
  background: radial-gradient(
    50% 50% at 50% 50%,
    rgba(62, 162, 211, 0.24),
    rgba(62, 162, 211, 0.09) 45%,
    rgba(4, 6, 10, 0) 72%
  );
  opacity: 0.9;
  transition: opacity 0.45s ease;
}

.vit-photo {
  display: block;
  width: 100%;
  height: auto;
  /* Cast from the cutout's alpha, so it is the product's shadow and not a
     rectangle's. Two passes: the weight underneath, the light around it. */
  filter: drop-shadow(0 16px 20px rgba(0, 0, 0, 0.55))
    drop-shadow(0 2px 30px rgba(62, 162, 211, 0.14));
  transition: filter 0.45s ease, transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.vit-body {
  display: grid;
  justify-items: center;
  row-gap: 2px;
  text-align: center;
}

/*
  Days of cover: the one number that is not on the stage until it is asked
  for. It is laid out in a row that is zero high when closed, so nothing
  below it moves when it opens - the product does not shuffle when you point
  at it.
*/
.vit-cover {
  display: block;
  overflow: hidden;
  max-height: 0;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.1em;
  color: var(--vit-blue);
  opacity: 0;
  transition: max-height 0.4s ease, opacity 0.35s ease, margin-top 0.4s ease;
}

.vit-station:hover .vit-cover,
.vit-station:focus-visible .vit-cover,
.vit-station.is-active .vit-cover {
  max-height: 1.4em;
  margin-top: 2px;
  opacity: 1;
}

.vit-name {
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.3;
  color: #eaf2fc;
  transition: color 0.4s ease;
}

.vit-count {
  display: inline-flex;
  align-items: baseline;
  gap: 0.34em;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  color: var(--vit-dim);
}

.vit-count b {
  font-weight: 500;
  color: #cfe2f4;
}

/* The one element that carries the state, kept to a reading light rather
   than a badge: it sits on the count line and is 5px across. */
.vit-dot {
  align-self: center;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--vit-healthy);
  box-shadow: 0 0 7px currentColor;
  color: var(--vit-healthy);
  opacity: 0.75;
  transition: background 0.4s ease, color 0.4s ease, opacity 0.4s ease;
}

.vit-station.is-watch .vit-dot {
  background: var(--vit-watch);
  color: var(--vit-watch);
}

.vit-station.is-urgent .vit-dot {
  background: var(--vit-urgent);
  color: var(--vit-urgent);
}

/*
  Hover lifts it and turns the light up. The drift keeps running underneath -
  pausing it would make every hover start with a jolt.
*/
.vit-station:hover,
.vit-station:focus-visible {
  transform: translate3d(0, -6px, 0);
  outline: none;
}

.vit-station:hover .vit-photo,
.vit-station:focus-visible .vit-photo {
  filter: drop-shadow(0 18px 22px rgba(0, 0, 0, 0.55))
    drop-shadow(0 2px 34px rgba(62, 162, 211, 0.3));
  transform: scale(1.035);
}

.vit-station:hover .vit-frame::before,
.vit-station:focus-visible .vit-frame::before {
  opacity: 1;
}

.vit-station:focus-visible .vit-name {
  color: #ffffff;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The chosen one: drawn toward the hub, larger, and lit from behind. */
.vit-station.is-active {
  z-index: 5;
  transform: translate3d(
      calc((50% - var(--x)) * 0.16),
      calc((30% - var(--y)) * 0.16 - 8px),
      0
    )
    scale(1.07);
}

.vit-station.is-active .vit-photo {
  filter: drop-shadow(0 20px 26px rgba(0, 0, 0, 0.6))
    drop-shadow(0 2px 38px rgba(62, 162, 211, 0.42));
}

.vit-station.is-active .vit-frame::before {
  opacity: 1;
}

.vit-station.is-active .vit-name {
  color: #ffffff;
}

.vit-station.is-active .vit-dot {
  opacity: 1;
}

/* Everything not chosen steps back. */
.is-selected .vit-station:not(.is-active) {
  opacity: 0.4;
}

/* --- the stage marks ---------------------------------------------------- */

/* --- the reading -------------------------------------------------------- */

.vit-panel {
  position: absolute;
  left: 50%;
  top: 62%;
  translate: -50% 0;
  z-index: 4;
  width: min(23rem, calc(100% - 2rem));
  padding: var(--space-5) var(--space-6) var(--space-6);

  border: 1px solid rgba(120, 190, 235, 0.28);
  border-radius: 18px;
  background: linear-gradient(155deg, rgba(16, 30, 46, 0.88), rgba(7, 13, 21, 0.92));
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  box-shadow: 0 40px 80px -40px #000, inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 0 56px -26px var(--vit-glow);
  text-align: center;

  opacity: 0;
  scale: 0.95;
  transition: opacity 0.42s ease, scale 0.42s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.vit-panel[hidden] {
  display: none;
}

.vit-panel.is-in {
  opacity: 1;
  scale: 1;
}

.vit-close {
  position: absolute;
  top: 8px;
  right: 12px;
  padding: 4px 8px;
  border: 0;
  background: none;
  color: var(--vit-dim);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.3s ease;
}

.vit-close:hover {
  color: #fff;
}

.vit-panel-stage {
  margin: 0 0 4px;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--vit-blue);
}

.vit-panel-name {
  margin: 0 0 var(--space-4);
  font-family: var(--display);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #f6fbff;
}

.vit-panel-count {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
}

.vit-panel-count b {
  font-family: var(--display);
  font-size: 2.4rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  color: #ffffff;
  font-variant-numeric: tabular-nums;
}

.vit-panel-count > span:first-of-type {
  font-size: var(--text-base);
  color: var(--vit-dim);
}

.vit-status {
  margin-left: var(--space-2);
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vit-status.is-healthy {
  background: rgba(74, 222, 128, 0.12);
  box-shadow: inset 0 0 0 1px rgba(74, 222, 128, 0.35);
  color: var(--vit-healthy);
}

.vit-status.is-watch {
  background: rgba(243, 185, 63, 0.12);
  box-shadow: inset 0 0 0 1px rgba(243, 185, 63, 0.35);
  color: var(--vit-watch);
}

.vit-status.is-urgent {
  background: rgba(255, 122, 122, 0.12);
  box-shadow: inset 0 0 0 1px rgba(255, 122, 122, 0.38);
  color: var(--vit-urgent);
}

.vit-panel-days {
  margin: 0 0 4px;
  font-size: var(--text-sm);
  color: #dbe7f5;
}

.vit-panel-note {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--vit-dim);
}

/* --- the caption -------------------------------------------------------- */

.vit-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin: var(--space-10) 0 0;
  font-family: var(--mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #5d6d84;
  transition: opacity 0.5s ease;
}

.is-selected .vit-hint {
  opacity: 0;
}

.vit-hint-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--vit-blue);
  animation: vit-blink 3.8s ease-in-out infinite;
}

@keyframes vit-blink {
  0%,
  100% {
    opacity: 0.3;
  }
  50% {
    opacity: 1;
  }
}

.vit-noscript {
  max-width: 34rem;
  margin: var(--space-8) auto 0;
  color: var(--vit-dim);
  text-align: center;
}

/* --- tablet ------------------------------------------------------------- */

@media (max-width: 1180px) {
  .vit-station {
    width: 8.5rem;
  }

}

/* --- the vertical flow -------------------------------------------------- */

/*
  Below this the stage stops being a stage. The curve becomes a single line
  running down the page, the hub sits at its head, and the five stations hang
  off it in order - the same journey, told vertically, rather than the
  desktop composition squeezed.
*/
@media (max-width: 900px) {
  .vit-stage {
    height: auto;
    perspective: none;
    padding-left: 2.25rem;
  }

  /* The line itself, drawn in CSS: the SVG curve has no meaning once the
     stations are in a column. */
  .vit-stage::before {
    content: '';
    position: absolute;
    left: 0.75rem;
    top: 1rem;
    bottom: 3rem;
    width: 1px;
    background: linear-gradient(
      180deg,
      rgba(120, 190, 235, 0.5),
      rgba(120, 190, 235, 0.18) 30%,
      rgba(120, 190, 235, 0.18) 80%,
      rgba(120, 190, 235, 0)
    );
  }

  .vit-flow {
    display: none;
  }

  .vit-hub {
    position: relative;
    left: auto;
    top: auto;
    translate: none;
    margin: 0 0 var(--space-10) -2.25rem;
  }

  .is-selected .vit-hub {
    translate: none;
    scale: 1;
  }

  .vit-halo {
    width: 18rem;
    height: 18rem;
  }

  .vit-pulse {
    width: 15rem;
    height: 15rem;
  }

  /* The core is the head of a column here rather than the middle of a room,
     so it stops being the size of the composition. */
  .vit-core {
    --vit-dial: 15rem;
  }

  .vit-bead {
    display: none;
  }

  .vit-rail {
    position: relative;
    inset: auto;
    display: grid;
    gap: var(--space-4);
    transform-style: flat;
  }

  /* Order matters here: the stations and their stage marks interleave, so
     the column reads stock, usage, prediction, reorder in sequence. */
  .vit-station {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    translate: none;
    transform: none;

    grid-template-columns: 4.5rem 1fr;
    align-items: center;
    justify-items: start;
    column-gap: var(--space-4);
    text-align: left;
  }

  /*
    The column is a list, so the two drifting wrappers stop being boxes and
    the row grid lays out the product and its label directly. Nothing floats
    here: a list that moves is a list that is hard to read on a phone.
  */
  .vit-drift,
  .vit-sway {
    display: contents;
  }

  .vit-frame {
    animation: none;
  }

  .vit-station:hover,
  .vit-station:focus-visible,
  .vit-station.is-active {
    transform: translateX(4px);
  }

  .vit-frame {
    width: 4.5rem;
  }

  .vit-frame::before {
    width: 128%;
    height: 128%;
  }

  .vit-body {
    justify-items: start;
    text-align: left;
  }

  .vit-panel {
    position: relative;
    left: auto;
    top: auto;
    translate: none;
    width: auto;
    margin: var(--space-5) 0 0 -2.25rem;
    text-align: left;
  }

  .vit-panel-count {
    justify-content: flex-start;
  }

  .is-selected .vit-station:not(.is-active) {
    opacity: 0.55;
  }
}

/*
  The stage marks are laid out in source order after the stations, so on the
  column they are pulled back into place between them.
*/
@media (max-width: 900px) {
  .vit-rail {
    grid-auto-flow: row;
  }

  .vit-station[data-vit-station='cups'] {
    order: 2;
  }
  .vit-station[data-vit-station='oat-milk'] {
    order: 4;
  }
  .vit-station[data-vit-station='whole-milk'] {
    order: 6;
  }
  .vit-station[data-vit-station='pastries'] {
    order: 8;
  }
  .vit-station[data-vit-station='espresso-beans'] {
    order: 9;
  }

}

@media (max-width: 480px) {
  .vit-station {
    grid-template-columns: 3.6rem 1fr;
  }

  .vit-frame {
    width: 3.6rem;
  }
}

/* --- motion off --------------------------------------------------------- */

/*
  The drifting, the breathing, the turning block, the ambience and the light
  running the curve all stop. Choosing a product, and everything that follows
  from it, is untouched.
*/
@media (prefers-reduced-motion: reduce) {
  .vit-mote,
.vit-station,
.vit-drift,
.vit-sway,
.vit-frame,
.vit-halo,
.vit-pulse,
.vit-hint-dot {
    animation: none;
  }

  /* Suspended, not floating: the products hold their positions exactly. */
  .vit-drift,
  .vit-sway,
  .vit-frame {
    transform: none;
  }

  .vit-station,
  .vit-panel,
  .vit-hub,
  .vit-photo {
    transition-duration: 0.14s;
  }
}
