/* =================================================================
   COMPONENTS - pills, buttons, cards, expandables, carousels, skills

   Every raised block follows the 3D recipe from design-rules S3:
   white fill + 1px border + layered shadow + white top highlight.
   The top highlight is what sells the extrusion.
   ================================================================= */

/* -- PILLS - one component, five variants, never a sixth -------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  align-self: flex-start;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.5;
  white-space: nowrap;
  border: 1px solid transparent;
}

.pill::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.85;
  flex: none;
}
.pill--nodot::before { display: none; }

.pill--brand {
  background: var(--grad-brand-solid);
  color: var(--text-on-brand);
  box-shadow: var(--e1);
}
.pill--outline {
  background: var(--surface);
  color: var(--brand-deep);
  border-color: var(--border-brand);
}
.pill--neutral {
  background: var(--surface-sunken);
  color: var(--text-muted);
  border-color: var(--border);
}
.pill--tint {
  background: var(--surface-brand-tint);
  color: var(--brand-deep);
}
.pill--ghost {
  background: transparent;
  color: var(--text-muted);
  border-color: var(--border);
}

/* -- BUTTONS ------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-pill);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: -0.01em;
  transition: transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease),
              background var(--dur-base) var(--ease),
              color var(--dur-base) var(--ease);
}

/* Primary - the only element on the page with a gradient sweep. */
.btn--primary {
  position: relative;
  overflow: hidden;
  color: var(--text-on-brand);
  background: var(--grad-brand-solid);
  box-shadow: var(--e-brand), inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
.btn--primary::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg,
    transparent 25%, rgba(255, 255, 255, 0.42) 50%, transparent 75%);
  transform: translateX(-120%);
  transition: transform 620ms var(--ease);
}
.btn--primary:hover {
  color: var(--text-on-brand);
  transform: translateY(-2px);
  box-shadow: var(--e-brand-hover), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.btn--primary:hover::after { transform: translateX(120%); }

@media (prefers-reduced-motion: reduce) {
  .btn--primary::after { display: none; }
}

.btn--secondary {
  color: var(--text-primary);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: var(--e1), var(--highlight-top);
}
.btn--secondary:hover {
  color: var(--brand-deep);
  border-color: var(--border-brand);
  transform: translateY(-2px);
  box-shadow: var(--e2), var(--highlight-top);
}

/* -- CARD - the 3D block ------------------------------------------ */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom-color: var(--border-bottom);
  border-radius: var(--radius);
  box-shadow: var(--e2), var(--highlight-top);
  overflow: hidden;
  transition: transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease),
              border-color var(--dur-base) var(--ease);
}

/* The one gradient element a card is allowed: a 2px top edge
   that fades in on hover. See design-rules S2. */
.card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--grad-brand-line);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
  z-index: 2;
}

.card:hover {
  transform: translateY(var(--lift));
  border-color: var(--border-strong);
  box-shadow: var(--e4), var(--highlight-top);
}
.card:hover::before { opacity: 1; }

/* Feature card - gradient edge always on, sits a step higher. */
.card--feature {
  box-shadow: var(--e3), var(--highlight-top);
}
.card--feature::before { opacity: 1; }

.card__media {
  position: relative;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border);
}
.card__media video { width: 100%; }
.card__media img { width: 100%; height: 100%; display: block; object-fit: cover; }

/* Landing pages: source screenshot is split into tall segments for export
   quality, then stacked edge-to-edge here so the seam is invisible and the
   whole thing reads as one continuous page inside a fixed phone frame. */
.card__media--scroll {
  aspect-ratio: 9 / 19.5;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.card__media--scroll::-webkit-scrollbar { width: 6px; }
.card__media--scroll img { height: auto; object-fit: initial; }

.card__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-4);
}

.card__title { color: var(--text-primary); }
.card__line { font-size: var(--fs-small); }

.card__ceiling {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-sunken);
  border-radius: var(--radius-xs);
  box-shadow: var(--e-sunken);
  align-self: stretch;
}

.card__live {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--brand-indigo);
}

/* -- PLACEHOLDER GRAPHIC ------------------------------------------ */
.ph-graphic { width: 100%; height: auto; display: block; }

/* -- EXPANDABLE - the load-bearing interaction --------------------- */

.expand {
  align-self: stretch;
  border-top: 1px solid var(--border);
  margin-top: var(--sp-1);
}

.expand__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-3) 0;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--brand-indigo);
  transition: color var(--dur-fast) var(--ease);
}
.expand__trigger:hover { color: var(--brand-deep); }

.expand__trigger::after {
  content: '';
  flex: none;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--surface-brand-tint);
  box-shadow: inset 0 0 0 1px var(--border-brand);
  background-image:
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor);
  background-size: 8px 1.5px, 1.5px 8px;
  background-position: center, center;
  background-repeat: no-repeat;
  transition: transform var(--dur-base) var(--ease);
}
.expand[data-open="true"] .expand__trigger::after {
  transform: rotate(135deg);
}

.expand__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease);
}
.expand[data-open="true"] .expand__panel { grid-template-rows: 1fr; }
.expand__inner { overflow: hidden; }
.expand__inner > * { padding-bottom: var(--sp-4); font-size: var(--fs-small); }

/* -- TEARDOWN - the expanded diagnosis ----------------------------- */

.teardown {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
  margin-bottom: var(--sp-4);
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
  box-shadow: var(--e-sunken);
}
.teardown dt {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: var(--sp-2);
}
.teardown dt:first-child { margin-top: 0; }
.teardown dd { margin: 0; font-size: var(--fs-small); }

/* The hypothesis is the line that separates analysis from theft. */
.teardown dd.is-hypothesis {
  margin-top: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface);
  border-left: 3px solid var(--brand-indigo);
  border-radius: var(--radius-xs);
  color: var(--text-primary);
  box-shadow: var(--e1);
}

/* -- TAB SELECTOR - visual box selector, ARIA tabs pattern ---------
   Tray is sunken (same recipe as .teardown); the active box is
   raised back out of it with the standard 3D extrusion. Reused
   wherever a section needs "show one category at a time" instead
   of stacking every block in sequence. */

.tabselect__tray {
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-2);
  margin-bottom: var(--sp-5);
  background: var(--surface-sunken);
  border-radius: var(--radius-lg);
  box-shadow: var(--e-sunken);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabselect__tray::-webkit-scrollbar { display: none; }

.tabselect__tab {
  position: relative;
  flex: none;
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius);
  border: 1px solid transparent;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-secondary);
  background: transparent;
  overflow: hidden;   /* clips the ::before accent bar to this radius —
                          a straight-edged bar on a rounded box (no
                          clip) looks like a corner-radius mismatch,
                          since the bar's own border-radius can't
                          reproduce the curve at a 2px height. Applies
                          everywhere this accent-line pattern is used:
                          .card, .loop__node, .case__tile. */
  transition: background var(--dur-base) var(--ease),
              border-color var(--dur-base) var(--ease),
              color var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.tabselect__tab:hover {
  color: var(--text-primary);
  background: var(--surface-brand-tint);
}
.tabselect__tab[aria-selected="true"] {
  color: var(--text-primary);
  background: var(--surface);
  border-color: var(--border);
  border-bottom-color: var(--border-bottom);
  box-shadow: var(--e2), var(--highlight-top);
}
.tabselect__tab[aria-selected="true"]::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--grad-brand-line);
}
.tabselect__count {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--text-faint);
}
.tabselect__tab[aria-selected="true"] .tabselect__count { color: var(--brand-deep); }

.tabselect__panel[hidden] { display: none; }

/* -- CAROUSEL -------------------------------------------------------
   Mobile: vertical stack. Desktop: horizontal scroll-snap.
   Native scroll-snap, not a JS carousel - degrades for free and
   works with keyboard and screen readers. */

.carousel {
  display: grid;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
}

@media (min-width: 768px) {
  .carousel {
    grid-auto-flow: column;
    grid-auto-columns: minmax(272px, 1fr);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    /* room for the hover lift and shadow to render un-clipped */
    padding: var(--sp-2) var(--sp-1) var(--sp-5);
    margin-inline: calc(var(--sp-1) * -1);
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
  }
  .carousel > * { scroll-snap-align: start; }
  .carousel::-webkit-scrollbar { height: 8px; }
  .carousel::-webkit-scrollbar-track {
    background: var(--surface-sunken);
    border-radius: var(--radius-pill);
  }
  .carousel::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
  }
  .carousel::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
}

/* -- FRAMEWORK LISTS - recessed wells ------------------------------ */

.framework {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
  box-shadow: var(--e-sunken);
}
.framework li {
  position: relative;
  padding-left: var(--sp-5);
  font-size: var(--fs-small);
}
.framework li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 7px; height: 7px;
  border-radius: 2px;
  background: var(--grad-brand-line);
}

/* Term lists - label above detail, no bullet. */
.framework--terms { gap: var(--sp-4); }
.framework--terms li { padding-left: 0; }
.framework--terms li::before { display: none; }
.framework--terms strong {
  display: block;
  margin-bottom: 2px;
  color: var(--text-primary);
  font-weight: 640;
  font-size: var(--fs-body);
  letter-spacing: -0.015em;
}

/* Numbered steps - the index chip is the gradient element. */
.framework--steps { gap: var(--sp-4); counter-reset: step; }
.framework--steps li {
  counter-increment: step;
  padding-left: var(--sp-7);
  min-height: 32px;
}
.framework--steps li::before {
  content: counter(step, decimal-leading-zero);
  top: 0;
  width: 32px; height: 32px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-xs);
  background: var(--grad-brand-solid);
  color: var(--text-on-brand);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  box-shadow: var(--e1);
}

/* -- WHAT I DELIVER - three numbered rows, then the stack ---------- */
/* v4 (14 Aug 2026): replaces the v3 discipline cards. Full-width
   rows, not a grid — three tiers of the same work have to be read in
   order and compared line by line, which a side-by-side grid at this
   bullet density doesn't allow. Nothing collapses.

   The numbers carry the accent as flat --brand-indigo. The only ramp
   in the section is the hovered row title (design-rules §2, item 10),
   which is one element at a time by definition. */

.delivers {
  display: grid;
  gap: var(--sp-3);
}

.deliver {
  display: grid;
  grid-template-columns: 60px 1fr;
  align-items: start;
  padding: 20px 24px;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-bottom-color: var(--border-bottom);
  /* 12px per the build brief — between --radius-sm and --radius, the
     same one-off the Process module takes for the same reason. */
  border-radius: 12px;
  box-shadow: var(--e1), var(--highlight-top);
}

/* Mono keeps it in line with every other numeral on the page (section
   index, process stages). Loaded weights are 500/600 — 600 is the
   closest thing to "medium" that won't get synthesised. */
.deliver__num {
  font-family: var(--font-mono);
  font-size: 38px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--brand-indigo);
}

/* The gradient sits under the title permanently and is simply hidden
   behind an opaque colour — that's what lets the hover state fade
   INTO the ramp instead of hard-swapping to it. Nothing is visible
   until `color` goes transparent below. */
.deliver__title {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--text-primary);
  margin-bottom: var(--sp-3);
  background: var(--grad-brand-line);
  -webkit-background-clip: text;
  background-clip: text;
  transform-origin: left center;
  transition: scale var(--dur-base) var(--ease),
              color var(--dur-base) var(--ease);
}

/* Hover the row, not the title — the whole card is the target, so
   the mark lands wherever the reader's cursor already is. `scale`
   rather than a font-size bump: 22 -> ~25px reads identically and
   costs no reflow of the bullets underneath.

   [DESIGN] This is the one gradient element in this section — the
   rows themselves carry no ramp, so at most one title is ever lit.
   Added to the design-rules §2 allowlist 14 Aug 2026. */
@media (hover: hover) {
  .deliver:hover .deliver__title {
    scale: 1.13;
    color: transparent;
  }
}

/* Movement is what this setting opts out of; the colour still says
   "hovered", so the state survives without the scale. */
@media (prefers-reduced-motion: reduce) {
  .deliver:hover .deliver__title { scale: 1; }
}

/* The one place on the page that uses real disc bullets — base.css
   strips list-style globally, so it's restored here explicitly. */
.deliver__list {
  list-style: disc;
  padding-left: 1.1em;
  font-size: 14px;
  line-height: 1.7;
  color: var(--text-secondary);
}
.deliver__list li::marker { color: var(--text-faint); }

/* Mobile: the number moves above the title, rows stack unchanged. */
@media (max-width: 599px) {
  .deliver {
    grid-template-columns: 1fr;
    gap: var(--sp-2);
  }
  .deliver__num { font-size: 30px; }
}

/* Secondary tier — tools, not capability claims. Everything here is
   dialled down a step from the rows above: hairline rule, muted
   labels, low-contrast tags. */
.stack {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
}

.stack__label {
  display: block;
  margin-bottom: var(--sp-4);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* 2x2 from tablet up — four groups in one stacked column left a wide
   empty gutter to the right of the tags and made the block taller
   than the rows it's meant to sit under. */
.stack__rows {
  display: grid;
  gap: var(--sp-3);
}
@media (min-width: 768px) {
  .stack__rows {
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-5) var(--sp-7);
  }
}

.stackrow {
  display: grid;
  gap: var(--sp-2);
}
@media (min-width: 640px) {
  .stackrow {
    grid-template-columns: 80px 1fr;
    align-items: baseline;
    gap: var(--sp-4);
  }
}
.stackrow__name {
  font-size: 12px;
  color: var(--text-muted);
}
.stackrow__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Deliberately quieter than .pill — no tint fill, no dot, no accent
   colour. These are the last thing in the section for a reason. */
.tag {
  padding: 3px var(--sp-3);
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-secondary);
}

/* -- STAGGERED REVEAL ----------------------------------------------- */

.reveal {
  opacity: 0;
  translate: 0 12px;
  transition: opacity var(--dur-slow) var(--ease),
              translate var(--dur-slow) var(--ease);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
.reveal.is-in { opacity: 1; translate: 0 0; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; translate: 0 0; }
}
