/* ==========================================================================
   Vertical Systems: shared components (site/css/components.css)
   --------------------------------------------------------------------------
   Spec: docs/DESIGN-SYSTEM.md (v1, 16 Sep 2026). Used by the homepage and by
   every service and industry page. Colours come from the Field Manual tokens
   in site/assets/themes.css (never edit that file). Pairs with
   site/js/reveal.js.

   Load order: engine/scrollcraft.css > assets/themes.css > css/home.css >
   this file. Nothing here depends on home.css; it only reads --vs-r and
   --vs-display-weight when they exist.

   CLASS CONTRACT (keep these names stable; other pages depend on them)

   Cards
     .vs-card               surface fill, 1px line, 10px radius, warm shadow.
                            Fine pointers: lift, deeper shadow, stronger
                            border and a one-time light sweep on hover-in
                            and focus-within.
     a.vs-card              the whole card is the link, one focus ring; the
                            .vs-card__title turns the darker accent on hover
     .vs-card--flat         no shadow, for dense lists
     .vs-card--media        16:9 .vs-card__media on top; the image scales
                            1.03 inside the clip on hover
     .vs-card__media        the 16:9 media box (holds an <img>)
     .vs-card__body         padded content box
     .vs-card__kicker       mono label line above the title
     .vs-card__title        card heading
     .vs-card__text         one or two lines of supporting text
     .vs-card__meta         mono footnote line

   Buttons
     .vs-btn                base: 44px tall, display face
     .vs-btn--primary       accent fill, dark ink text. Hover: 1px lift, warm
                            glow under the button, one shine sweep. The hover
                            fill is LIGHTER than rest so ink text stays at
                            5.6:1 (the old darkened hover measured 4.08:1).
     .vs-btn--ghost         1px strong line; hover fills surface, ink border
     .vs-btn--block         full width (used on phones)

   Label chips (evidence labels, never decoration)
     .vs-chip               mono pill with a state dot
     .vs-chip--client       "Reported by the client"
     .vs-chip--self         "Self-reported"
     .vs-chip--projection   "Projection" (dashed)
     .vs-chip--verified     "Verified" (the --vs-ok green)

   Motion hooks (driven by site/js/reveal.js)
     html.js-reveal                 set by reveal.js before anything hides
     [data-reveal]                  fades in and rises 12px once, at 15% in view
     [data-reveal-stagger]          a container: its direct children reveal
                                    60ms apart when it enters
     .is-revealing / .is-revealed   state classes reveal.js writes
     [data-odometer]                digits roll when in view (reel technique
                                    from site/js/estimate-panel.js)
     .vs-odo, .vs-odo__slot, .vs-odo__reel   the reel parts reveal.js builds

   Tokens (zero specificity, so a theme block can override them)
     --vs-ease-card  --vs-card-r  --vs-card-shadow  --vs-card-shadow-hover
     --vs-accent-text   darker accent for text on surface and canvas
                        (Field Manual: #A8470A, 5.5:1 on surface, 5.0:1 on bone)

   Banned here by the spec: neon glow, gradient text, glassmorphism,
   `transition: all`, scroll cues, motion that repeats while reading.
   ========================================================================== */

:where(html) {
  --vs-ease-card: cubic-bezier(.2, .8, .2, 1);
  --vs-card-r: 10px;
  --vs-card-shadow: 0 1px 2px rgba(22, 23, 21, .06), 0 8px 24px -12px rgba(22, 23, 21, .18);
  --vs-card-shadow-hover: 0 2px 4px rgba(22, 23, 21, .06), 0 18px 40px -16px rgba(22, 23, 21, .28);
  --vs-accent-text: color-mix(in srgb, var(--sc-accent) 62%, var(--sc-ink));
}
:where([data-theme="field"]) { --vs-accent-text: #A8470A; }

/* ------------------------------------------------------------------ card -- */
.vs-card {
  position: relative;
  isolation: isolate;          /* the sweep paints above the fill, below the text */
  overflow: hidden;            /* clips the sweep and the media zoom to the radius */
  display: block;
  color: var(--sc-ink);
  background: var(--sc-surface);
  border: 1px solid var(--vs-line);
  border-radius: var(--vs-card-r);
  box-shadow: var(--vs-card-shadow);
  transition:
    transform 240ms var(--vs-ease-card),
    box-shadow 240ms var(--vs-ease-card),
    border-color 240ms var(--vs-ease-card);
}
/* The light sweep: a band tilted 20 degrees off vertical (gradient line at
   110deg), white at 22%. It rests off the left edge with no transition, so it
   only travels on hover-in and snaps back invisibly on hover-out. */
.vs-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(110deg, transparent 32%, rgba(255, 255, 255, .22) 50%, transparent 68%);
  transform: translateX(-120%);
}

a.vs-card { text-decoration: none; }
a.vs-card:focus-visible {
  outline: 2px solid var(--sc-accent);
  outline-offset: 3px;
  border-radius: var(--vs-card-r);
}
a.vs-card :focus-visible { outline: none; }   /* one ring: the card's */

.vs-card__body { padding: clamp(1.1rem, 2.2vw, 1.5rem); }
.vs-card__kicker {
  margin: 0 0 .65rem;
  font-family: var(--vs-font-mono, ui-monospace, monospace);
  font-size: var(--sc-t-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--sc-ink-soft);
}
.vs-card__title {
  margin: 0;
  font-family: var(--sc-font-display);
  font-weight: var(--vs-display-weight, 600);
  font-size: clamp(1.1rem, 1rem + .35vw, 1.3rem);
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-wrap: balance;
  transition: color 240ms var(--vs-ease-card);
}
.vs-card__text {
  margin: .5rem 0 0;
  font-size: var(--sc-t-sm);
  line-height: 1.5;
  color: var(--sc-ink-soft);
  text-wrap: pretty;
}
.vs-card__meta {
  margin: .9rem 0 0;
  font-family: var(--vs-font-mono, ui-monospace, monospace);
  font-size: var(--sc-t-xs);
  color: var(--sc-ink-soft);
}

.vs-card--flat,
.vs-card--flat:hover,
.vs-card--flat:focus-within { box-shadow: none; }

.vs-card--media .vs-card__media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--vs-plate-1);
  border-bottom: 1px solid var(--vs-line);
}
.vs-card--media .vs-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 240ms var(--vs-ease-card);
}

@media (hover: hover) and (pointer: fine) {
  .vs-card:hover,
  .vs-card:focus-within {
    transform: translateY(-4px);
    box-shadow: var(--vs-card-shadow-hover);
    border-color: var(--vs-line-strong);
  }
  .vs-card--flat:hover,
  .vs-card--flat:focus-within { box-shadow: none; }
  .vs-card:hover::after,
  .vs-card:focus-within::after {
    transform: translateX(120%);
    transition: transform 700ms var(--vs-ease-card);
  }
  a.vs-card:hover .vs-card__title,
  a.vs-card:focus-visible .vs-card__title { color: var(--vs-accent-text); }
  .vs-card--media:hover .vs-card__media img,
  .vs-card--media:focus-within .vs-card__media img { transform: scale(1.03); }
}

/* ---------------------------------------------------------------- button -- */
.vs-btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 2.75rem;
  padding: 0 1.125rem;
  font-family: var(--sc-font-display);
  font-weight: var(--vs-display-weight, 600);
  font-size: var(--sc-t-sm);
  letter-spacing: -0.005em;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  color: var(--sc-ink);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--vs-r, 6px);
  cursor: pointer;
  transition:
    background-color 160ms var(--vs-ease-card),
    border-color 160ms var(--vs-ease-card),
    box-shadow 240ms var(--vs-ease-card),
    transform 240ms var(--vs-ease-card);
}
.vs-btn:focus-visible { outline: 2px solid var(--sc-accent); outline-offset: 3px; }
.vs-btn--block { display: flex; width: 100%; }

.vs-btn--primary {
  color: var(--sc-accent-ink);
  background: var(--sc-accent);
  border-color: color-mix(in srgb, var(--sc-accent) 80%, var(--sc-ink));
}
.vs-btn--primary:focus-visible { outline-color: var(--sc-ink); }
/* Shine: a band tilted 25 degrees (gradient line at 115deg), white at 35%. */
.vs-btn--primary::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, .35) 50%, transparent 70%);
  transform: translateX(-120%);
}

.vs-btn--ghost {
  color: var(--sc-ink);
  background: transparent;
  border-color: var(--vs-line-strong);
}

@media (hover: hover) {
  .vs-btn--primary:hover {
    /* Lighter, not darker: ink on this fill is 5.6:1 (rest is 4.95:1). */
    background: color-mix(in srgb, var(--sc-accent) 88%, var(--sc-canvas));
    transform: translateY(-1px);
    box-shadow: 0 6px 18px -8px color-mix(in srgb, var(--sc-accent) 70%, transparent);
  }
  .vs-btn--primary:hover::after {
    transform: translateX(120%);
    transition: transform 600ms var(--vs-ease-card);
  }
  .vs-btn--ghost:hover {
    background: var(--sc-surface);
    border-color: var(--sc-ink);
  }
}
.vs-btn:active { transform: translateY(1px); }
.vs-btn--primary:active {
  transform: translateY(1px);
  box-shadow: 0 2px 6px -3px color-mix(in srgb, var(--sc-accent) 60%, transparent);
}

/* Legacy alias: the homepage chrome still uses .btn--primary from
   css/home.css, whose hover darkens the fill to 4.08:1. Same fix until the
   chrome moves to .vs-btn. */
@media (hover: hover) {
  .btn--primary:hover { background: color-mix(in srgb, var(--sc-accent) 88%, var(--sc-canvas)); }
}

/* ------------------------------------------------------------------ chip -- */
.vs-chip {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  padding: .3em .65em;
  font-family: var(--vs-font-mono, ui-monospace, monospace);
  font-size: var(--sc-t-xs);
  line-height: 1.2;
  letter-spacing: .01em;
  white-space: nowrap;
  color: var(--sc-ink);
  background: var(--sc-canvas);
  border: 1px solid var(--vs-line-strong);
  border-radius: 999px;
}
.vs-chip::before {
  content: "";
  flex: none;
  width: .5em;
  height: .5em;
  border-radius: 50%;
  background: currentColor;
}
.vs-chip--self,
.vs-chip--projection { color: var(--sc-ink-soft); }
.vs-chip--projection { border-style: dashed; background: transparent; }
.vs-chip--projection::before { background: transparent; box-shadow: inset 0 0 0 1.5px currentColor; }
.vs-chip--verified {
  color: var(--vs-ok);
  border-color: color-mix(in srgb, var(--vs-ok) 45%, transparent);
}

/* -------------------------------------------------------- section reveal -- */
/* Hidden only once reveal.js has set html.js-reveal. The rise uses the
   `translate` property, so it never fights a card's hover `transform`. */
html.js-reveal :is([data-reveal], [data-reveal-stagger] > *):not(.is-revealing, .is-revealed) {
  opacity: 0;
  translate: 0 12px;
}
html.js-reveal .is-revealing {
  transition:
    opacity 420ms var(--vs-ease-card),
    translate 420ms var(--vs-ease-card);
  transition-delay: calc(var(--reveal-i, 0) * 60ms);
}
@media (prefers-reduced-motion: reduce) {
  html.js-reveal :is([data-reveal], [data-reveal-stagger] > *):not(.is-revealing, .is-revealed) { translate: none; }
  html.js-reveal .is-revealing { transition: opacity 200ms linear; transition-delay: 0ms; }
}
@media print {
  html.js-reveal :is([data-reveal], [data-reveal-stagger] > *) { opacity: 1 !important; translate: none !important; }
}

/* -------------------------------------------------------------- odometer -- */
/* reveal.js keeps the real number for screen readers in a .vs-vh span.
   home.css defines .vs-vh too; this copy has zero specificity. */
:where(.vs-vh) {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.vs-odo { display: inline-flex; align-items: baseline; font-variant-numeric: tabular-nums; }
.vs-odo__slot {
  display: inline-block;
  height: 1em;
  overflow: hidden;
  line-height: 1;
  vertical-align: baseline;
}
.vs-odo__reel { display: block; will-change: transform; }
.vs-odo__reel > span { display: block; height: 1em; line-height: 1; text-align: center; }

/* ------------------------------------------------------- reduced motion -- */
@media (prefers-reduced-motion: reduce) {
  .vs-card,
  .vs-card__title,
  .vs-card--media .vs-card__media img,
  .vs-btn { transition: none; }
  .vs-card:hover,
  .vs-card:focus-within,
  .vs-btn:hover,
  .vs-btn:active { transform: none; }
  .vs-card::after,
  .vs-btn--primary::after { display: none; }
  .vs-card--media:hover .vs-card__media img { transform: none; }
  .vs-odo__reel { transition: none !important; }
}
