/* Sections added for the portfolio site: products, the capability pipeline,
   the two offers, the objection, principle receipts, and the contact additions.
   Every colour here is a token from styles.css. No new palette. */

/* ---------- Products ---------- */

.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
}

.product-card {
  background: var(--paper);
  padding: 34px 30px 32px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.product-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.product-card h3 {
  font-size: 27px;
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: -0.04em;
  margin: 0;
}

.status-badge,
.sub-status {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border-radius: 100px;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.04em;
  white-space: nowrap;
  border: 1px solid var(--control-border);
  color: var(--muted);
  margin-top: 4px;
}

.status-badge::before,
.sub-status::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex: none;
  background: currentColor;
}

.status-live {
  color: var(--accent);
  border-color: var(--accent);
}

.status-preview,
.status-soon {
  color: var(--muted);
}

.product-promise {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}

.product-what {
  font-size: 14px;
  line-height: 1.75;
  color: var(--muted);
  margin: 0;
}

/* A card that is a family of products — BrightKidz since 2026-09-29, a shell
   over the Library and Wrenfield. Each member states its own status from the
   same closed vocabulary; the card's badge speaks for the family. */
.product-family {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

.sub-product {
  padding: 12px 0 0;
  border-top: 1px solid var(--rule);
}

.sub-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  flex-wrap: wrap;
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.sub-head a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.sub-product .sub-status {
  margin-top: 0;
  padding: 3px 9px;
  font-size: 10.5px;
}

.sub-product p:last-child {
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--muted);
  margin: 0;
}

.product-gate {
  border-left: 2px solid var(--accent);
  padding: 2px 0 2px 16px;
  margin: 2px 0;
}

.gate-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.12em;
  color: var(--accent);
  margin: 0 0 7px;
}

.gate-label .icon {
  width: 15px;
  height: 15px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
  flex: none;
}

.product-gate p:last-child {
  font-size: 13px;
  line-height: 1.72;
  color: var(--ink);
  margin: 0;
}

.product-card .inline-tags {
  margin: 0;
}

.product-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin-top: auto;
  padding-top: 6px;
}

.product-note {
  font-size: 12px;
  line-height: 1.7;
  color: var(--muted);
  margin: 0;
  padding-top: 12px;
  border-top: 1px solid var(--rule);
}

.products .assembly-scene {
  margin-top: 76px;
}

/* ---------- Capability pipeline (inside the inverted band) ---------- */

.pipeline {
  list-style: none;
  margin: 0 0 42px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  background: #4b5047;
  border: 1px solid #4b5047;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}

.pipeline > li:not(.pipeline-tracer) {
  background: var(--ink);
  padding: 26px 22px 28px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.pipeline-step {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.12em;
  color: #b5bdad;
}

.pipeline strong {
  font-size: 17px;
  font-weight: 550;
  letter-spacing: -0.02em;
  color: var(--paper);
}

.pipeline p {
  font-size: 13px;
  line-height: 1.7;
  color: #c4c9bf;
  margin: 0;
}

.pipeline-tracer {
  position: absolute;
  top: 0;
  left: 0;
  width: 20%;
  height: 3px;
  background: var(--accent);
  z-index: 1;
  pointer-events: none;
  animation: pipeline-travel 14s cubic-bezier(0.77, 0, 0.175, 1) infinite;
}

/* Five stages, so the tracer rests on each in turn before moving on.
   motion.css owns whether this runs; it only ever declares the timeline.

   ⚠ This timeline is only true of the five-column layout. Stepping to 400% of
   a tracer one column wide lands on the fifth column exactly — but ONLY while
   there are five columns. Below 900px the grid becomes two columns and then
   one, and the width overrides used to follow while the step count did not: at
   two columns the tracer travelled two full pipeline widths and spent half the
   loop outside the box, invisible behind overflow:hidden; at one column it ran
   four widths off the end. A stage tracer that rests on stages that are not
   there is not a smaller version of this idea, so the stacked layouts get a
   different timeline below, not a broken copy of this one. */
@keyframes pipeline-travel {
  0%,
  12% {
    transform: translate3d(0, 0, 0);
    opacity: 0.9;
  }
  20%,
  32% {
    transform: translate3d(100%, 0, 0);
  }
  40%,
  52% {
    transform: translate3d(200%, 0, 0);
  }
  60%,
  72% {
    transform: translate3d(300%, 0, 0);
  }
  80%,
  94% {
    transform: translate3d(400%, 0, 0);
    opacity: 0.9;
  }
  100% {
    transform: translate3d(400%, 0, 0);
    opacity: 0;
  }
}

/* Stacked layouts: one sweep along the top edge, expressed entirely in
   percentages of the tracer's own width, so it enters and leaves the pipeline
   exactly at its edges whatever the column count happens to be. */
@keyframes pipeline-sweep {
  0% {
    transform: translate3d(-100%, 0, 0);
    opacity: 0;
  }
  14%,
  86% {
    opacity: 0.9;
  }
  100% {
    transform: translate3d(250%, 0, 0);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pipeline-tracer {
    animation: none !important;
    transform: translate3d(0, 0, 0);
  }
}

.capability-props {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 18px 30px;
  margin-bottom: 44px;
}

.capability-props > div {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.capability-props .icon {
  width: 19px;
  height: 19px;
  flex: none;
  stroke: var(--accent);
  fill: none;
  stroke-width: 1.6;
  margin-top: 1px;
}

.capability-props span {
  font-size: 13px;
  line-height: 1.6;
  color: #d5d9cf;
}

/* ---------- Services: two offers ---------- */

.offer-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 72px;
}

.offer {
  background: var(--paper);
  padding: 38px 34px 34px;
}

.offer-icon {
  width: 26px;
  height: 26px;
  stroke: var(--accent);
  fill: none;
  stroke-width: 1.5;
  margin-bottom: 20px;
}

.offer h3 {
  font-size: 30px;
  line-height: 1.14;
  font-weight: 450;
  letter-spacing: -0.04em;
  margin: 0 0 16px;
}

.offer > p {
  font-size: 14px;
  line-height: 1.78;
  color: var(--muted);
  margin: 0 0 28px;
}

.offer-terms {
  margin: 0;
  display: grid;
  gap: 4px;
}

.offer-terms dt {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.12em;
  color: var(--accent);
  margin-top: 18px;
}

.offer-terms dt:first-child {
  margin-top: 0;
}

.offer-terms dd {
  margin: 0;
  font-size: 13px;
  line-height: 1.75;
  color: var(--ink);
}

/* ---------- Approach row ---------- */

.approach-row {
  list-style: none;
  margin: 0 0 64px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 34px;
}

.approach-row li {
  border-top: 1px solid var(--rule);
  padding-top: 20px;
}

.approach-row h3 {
  font-size: 17px;
  line-height: 1.3;
  font-weight: 550;
  letter-spacing: -0.03em;
  margin: 10px 0 8px;
}

.approach-row p {
  font-size: 13px;
  line-height: 1.7;
  color: var(--muted);
  margin: 0;
}

/* ---------- The objection ---------- */

.objection {
  margin: 76px 0 0;
  padding: 40px 44px;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 8px;
  max-width: 860px;
}

.objection-question {
  font-size: 21px;
  line-height: 1.4;
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin: 0 0 18px;
  text-wrap: balance;
}

.objection > p:not(.objection-question) {
  font-size: 15px;
  line-height: 1.8;
  color: var(--ink);
  margin: 0;
}

.objection footer {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
  font-size: 12px;
  line-height: 1.7;
  color: var(--muted);
}

/* ---------- Principles: receipts + corrections ---------- */

.principle-list .receipt {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--rule);
  font-size: 12px;
  line-height: 1.7;
  color: var(--muted);
}

.corrections {
  grid-column: 1 / -1;
  margin-top: 56px;
  padding: 30px 34px;
  border: 1px solid var(--control-border);
  border-radius: 8px;
  background: var(--light);
}

.corrections h3 {
  font-size: 19px;
  font-weight: 550;
  letter-spacing: -0.03em;
  margin: 0 0 12px;
}

.corrections p {
  font-size: 14px;
  line-height: 1.8;
  color: var(--muted);
  margin: 0;
  max-width: 74ch;
}

/* ---------- Contact additions ---------- */

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 6px;
}

.button-quiet {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--control-border);
}

.button-quiet:hover:not(:disabled) {
  border-color: var(--ink);
  background: var(--soft);
}

/* A one-line statement of what the primary button does, sitting between it and
   the two local paths. It is not a caption on either — it is the difference
   between them, which is what a person needs before pressing anything. */
.form-notice {
  font-size: 11px;
  line-height: 1.7;
  color: var(--muted);
  margin: 12px 0 0;
  max-width: 58ch;
}

/* Shown only when a send failed on OUR side, or when the address is already at
   its cap. Never on a plain validation error: the sender can fix those
   themselves, and offering the fallback there would read as "give up". */
.form-fallback {
  font-size: 11px;
  line-height: 1.7;
  color: var(--muted);
  margin: 8px 0 0;
  padding: 10px 13px;
  border-left: 2px solid var(--accent);
  background: var(--soft);
  border-radius: 0 4px 4px 0;
}

.form-fallback a {
  color: var(--accent);
  font-weight: 550;
}

/* The reciprocal link: they write us a brief, and we have one of our own. */
.contact-brief-link {
  margin: 20px 0 0;
  font-size: 13px;
  line-height: 1.7;
  color: var(--muted);
}

.contact-brief-link a {
  font-weight: 550;
}

.contact-direct {
  margin: 22px 0 0;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
  font-size: 13px;
  line-height: 1.7;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.contact-direct a {
  color: var(--accent);
  font-weight: 550;
}

#copy-email {
  background: none;
  border: 1px solid var(--control-border);
  border-radius: 4px;
  padding: 5px 10px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  cursor: pointer;
  min-height: 30px;
}

#copy-email:hover {
  color: var(--ink);
  border-color: var(--ink);
}

/* ---------- Footer links ---------- */

/* .footer-links moved to styles.css on 2026-09-16. It lived here while only the
   landing page had one; every page carries it now, and a policy page loads
   styles.css and doc.css but not components.css — so the footer rendered as one
   unbroken run of words with no gaps between the links. Site chrome belongs in
   the stylesheet every page loads. */

/* ---------- Responsive ---------- */

@media (max-width: 1200px) {
  .product-card {
    padding: 28px 24px;
  }

  .offer {
    padding: 32px 26px;
  }

  .pipeline > li:not(.pipeline-tracer) {
    padding: 22px 17px 24px;
  }
}

@media (max-width: 900px) {
  .product-grid {
    grid-template-columns: 1fr;
  }

  .offer-grid {
    grid-template-columns: 1fr;
    margin-bottom: 56px;
  }

  .pipeline {
    grid-template-columns: repeat(2, 1fr);
  }

  .pipeline-tracer {
    width: 40%;
    animation-name: pipeline-sweep;
    animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
  }

  .approach-row {
    grid-template-columns: repeat(2, 1fr);
    gap: 28px;
    margin-bottom: 52px;
  }

  .objection {
    padding: 32px 28px;
    margin-top: 56px;
  }

  .products .assembly-scene {
    margin-top: 56px;
  }
}

@media (max-width: 680px) {
  .pipeline {
    grid-template-columns: 1fr;
  }


  .approach-row {
    grid-template-columns: 1fr;
  }

  .product-card h3 {
    font-size: 24px;
  }

  .offer h3 {
    font-size: 26px;
  }

  .objection {
    padding: 26px 22px;
  }

  .objection-question {
    font-size: 18px;
  }

  .corrections {
    padding: 24px 22px;
    margin-top: 44px;
  }

  .form-actions .button {
    width: 100%;
    justify-content: space-between;
  }
}
