/* Service and industry detail pages. No pins, no heavy canvas. These stay light and fast. */

/* ============================= SECTION GROUNDS ============================= */

/* Detail pages used to run every block on the same ground, so five or six sections separated by
   nothing but a hairline read as one continuous scroll. The home page solves this by alternating
   --bg and --bg-elev, and these pages now do the same. Both tones are near-black, so the page
   stays monochrome while a visitor can still see one block end and the next begin.

   Counted from the BOTTOM, and that is the whole trick. The footer is --bg-elev, so the last
   section has to be --bg or the two merge into a single slab with a hairline through it. Anchoring
   the alternation to the last section makes that true on every page whatever the section count
   happens to be (services carry six including the hero, industries five, work two), and a page can
   gain or lose a section later without anyone re-checking the parity by hand.

   :nth-last-of-type is safe here in the way it was not for the bento diagrams. The bug there was
   that the thing being counted was a class and the selector counted element types, so a stray
   <span> shifted every index. Here every child of <main> IS a <section>, so counting by type and
   counting by role are the same count. */
main > section:nth-last-of-type(odd) {
  background: var(--bg);
}

main > section:nth-last-of-type(even) {
  background: var(--bg-elev);
}

/* ============================= HERO ============================= */

.phero {
  position: relative;
  padding-block: clamp(9rem, 18vh, 13rem) var(--space-4);
  overflow: hidden;
}

/* One accent, site-wide. This used to read var(--accent, …) with each page overriding --accent
   in its <head>. Which, once --accent became the single accent token, repainted every link,
   button and tick on that page in a translucent violet/pink/green. The orb is decoration; it
   uses the shared glow and nothing overrides it. */
.phero__orb {
  position: absolute;
  top: -30%;
  left: 50%;
  width: min(900px, 110vw);
  height: min(900px, 110vw);
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-glow), transparent 62%);
  filter: blur(70px);
  opacity: 0.45;
  pointer-events: none;
}

.phero .container {
  position: relative;
  z-index: 1;
}

.crumbs {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.crumbs a:hover {
  color: var(--text);
}

.crumbs span[aria-hidden] {
  opacity: 0.5;
}

/* Smaller than the home hero, a detail page leads with its promise, not with scale. */
.phero h1 {
  font-size: clamp(2.2rem, 4.5vw + 0.6rem, 4.5rem);
  max-width: 20ch;
  margin-bottom: var(--space-3);
}

.phero__promise {
  font-size: var(--fs-lead);
  color: var(--text-dim);
  max-width: 52ch;
}

/* ============================= EXCHANGE ============================= */

/* "You bring / You get back", the handoff framing, reused on every service page. */
.exchange {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--space-3);
  align-items: stretch;
}

.exchange__col {
  /* A grid item defaults to min-width:auto, so it refuses to shrink below the min-content width
     of whatever it holds. The code-diff artifact sets `white-space: pre`, whose min-content is the
     full length of the longest line, which dragged the 1fr track to 425px inside a 390px viewport
     and overflowed the page. Only the column that carries code was affected, so it read as a
     one-page bug rather than the layout rule it actually is. */
  min-width: 0;
  padding: var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: var(--glass);
}

.exchange__col--out {
  background: var(--accent-soft);
  border-color: rgba(91, 140, 255, 0.24);
}

.exchange__label {
  display: block;
  margin-bottom: 1rem;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.exchange__col--out .exchange__label {
  color: var(--accent);
}

.exchange__col p {
  font-size: 1.05rem;
  line-height: 1.65;
}

.exchange__arrow {
  display: flex;
  align-items: center;
  color: var(--accent);
  font-size: 1.5rem;
}

@media (max-width: 800px) {
  .exchange {
    grid-template-columns: 1fr;
  }
  .exchange__arrow {
    justify-content: center;
    transform: rotate(90deg);
  }
}

/* ============================= DELIVERABLES ============================= */

.deliverables {
  display: flex;
  flex-direction: column;
}

.deliverable {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-2);
  align-items: baseline;
  padding-block: var(--space-2);
  border-top: 1px solid var(--glass-border);
}

/* The .section-head above already draws this list's opening rule. Drawing it again here is what
   produced two hairlines ~30px apart on every service page. */
.deliverable:first-child {
  border-top: 0;
}

.deliverable:last-child {
  border-bottom: 1px solid var(--glass-border);
}

/* A tick says "included". The 01/02/03 it replaced said nothing, the list has no order. */
.deliverable__tick {
  width: 17px;
  height: 17px;
  flex: none;
  color: var(--accent);
  transform: translateY(0.28em);
}

.deliverable__tick path {
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.deliverable__text {
  font-size: clamp(1.05rem, 1vw + 0.8rem, 1.3rem);
  color: var(--text);
}

/* ============================= PAIN POINTS (industry pages) ============================= */

.pains {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
}

/* A short red rule instead of a "01". It marks the card as a problem without pretending the
   three are ranked or sequential. A real element, not ::before: .card::before is already the
   pointer-glow layer, and a second rule for the same pseudo-element merges with it rather than
   replacing it, which pinned this to the card corner and wiped out the glow. */
.pain__rule {
  display: block;
  width: 26px;
  height: 2px;
  border-radius: 2px;
  background: var(--text-faint);
  opacity: 0.85;
}

.pain__title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 700;
  margin-block: 1.1rem 0.5rem;
}

.pain__text {
  color: var(--text-dim);
  font-size: 0.96rem;
}

@media (max-width: 800px) {
  .pains { grid-template-columns: 1fr; }
}

/* Rows linking an industry to the services that fix it. */
.helps {
  display: flex;
  flex-direction: column;
}

.help {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-2);
  align-items: center;
  padding-block: var(--space-3);
  border-top: 1px solid var(--glass-border);
  transition: padding-left var(--dur) var(--ease-out);
}

/* Same as .deliverable, the section head owns the opening rule. */
.help:first-child {
  border-top: 0;
}

.help:last-child {
  border-bottom: 1px solid var(--glass-border);
}

.help:hover {
  padding-left: 0.75rem;
}

.help__title {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 1.4vw + 0.8rem, 1.6rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.help__text {
  color: var(--text-dim);
  font-size: 0.96rem;
  margin-top: 0.3rem;
  max-width: 56ch;
}

.help__go {
  font-size: 1.2rem;
  color: var(--accent);
  transition: transform var(--dur) var(--ease-out);
}

.help:hover .help__go {
  transform: translateX(6px);
}

/* ============================= FAQ ============================= */

.faq {
  display: flex;
  flex-direction: column;
}

.qa {
  border-top: 1px solid var(--glass-border);
}

/* Same again. :first-child / :last-child rather than :first-of-type. .faq holds only these,
   and type selectors have already miscounted once on this site. */
.qa:first-child {
  border-top: 0;
}

.qa:last-child {
  border-bottom: 1px solid var(--glass-border);
}

.qa summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding-block: var(--space-2);
  cursor: pointer;
  list-style: none;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 1vw + 0.85rem, 1.3rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.qa summary::-webkit-details-marker {
  display: none;
}

.qa__sign {
  position: relative;
  flex: none;
  width: 18px;
  height: 18px;
}

.qa__sign::before,
.qa__sign::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: var(--accent);
  border-radius: 2px;
  transition: transform var(--dur) var(--ease-out);
}

.qa__sign::after {
  transform: rotate(90deg);
}

.qa[open] .qa__sign::after {
  transform: rotate(0deg);
}

/* Height is animated in JS. <details> can't transition its own auto height. */
.qa__body {
  overflow: hidden;
}

.qa__body p {
  padding-bottom: var(--space-2);
  color: var(--text-dim);
  max-width: 64ch;
}

/* ============================= CTA BAND ============================= */

.cta {
  position: relative;
  margin-block: var(--space-5) 0;
  padding: var(--space-4) var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  text-align: center;
  overflow: hidden;
}

.cta h2 {
  max-width: 20ch;
  margin-inline: auto;
  margin-bottom: var(--space-2);
}

.cta p {
  color: var(--text-dim);
  max-width: 46ch;
  margin-inline: auto;
  margin-bottom: var(--space-3);
}

/* ============================= RELATED ============================= */

.related__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
}

@media (max-width: 850px) {
  .related__grid { grid-template-columns: 1fr; }
}

/* ============================= CASE STUDIES ============================= */

/* Each case study is its own <section> now, so the alternating grounds at the top of this file
   separate them the way the home page separates its blocks. They used to be five articles stacked
   inside one section, which put the whole page on a single tone and read as one long slab.

   Half the usual section padding, because two of these meet at every boundary and a full
   var(--space-5) on each side doubled the gap the .cases flex column used to give. */
.section--case {
  padding-block: calc(var(--space-5) / 2);
}

.case {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: var(--space-4);
  align-items: center;
}

/* Alternate which side the screenshot sits on so the page doesn't march. */
/* An explicit class, not :nth-child(even). Each case is now the only article in its section, so
   every one of them is child 1 and the positional rule silently stopped matching, which would have
   put every screenshot on the same side. Same failure the bento diagrams hit with :nth-of-type:
   never index these by position. */
.case--flip .case__shot {
  order: 2;
}

.case__shot {
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: var(--bg-elev);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
}

/* Browser chrome, so a screenshot reads as "this is the live site". */
.case__chrome {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--glass-border);
  background: rgba(255, 255, 255, 0.03);
}

.case__chrome i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--glass-border-lit);
}

.case__url {
  margin-left: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-faint);
}

/* A fixed-ratio window onto the top of a full-page capture.

   These are whole-page screenshots, so they are tall: 780x900 and 780x1215. Shown at their real
   height, one card ran to 911px and the three never lined up. The window crops to a constant 4:3,
   anchored to the top of the page, so every card is the same height and you always see the part
   of the site that actually introduces it.

   The ratio lives on the container, which means the space is reserved before the image arrives,
   so this also removes any dependence on the width/height attributes being right. */
.case__window {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.case__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}

/* The page carries on past the crop, so the bottom edge dissolves instead of being guillotined.
   It fades to the panel's own ground, not the section's, so it stays correct on both the --bg and
   --bg-elev sections the page alternates between.

   No "top of the page" caption underneath: the fade already says the screenshot is truncated, and
   a mono uppercase label restating it is exactly the eyebrow this site does not use. */
.case__window::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 34%;
  background: linear-gradient(to bottom, transparent, var(--bg-elev));
  pointer-events: none;
}

.case__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.case__tag {
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.case__name {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 2vw + 0.9rem, 2.4rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  margin-bottom: 0.75rem;
}

.case__what {
  color: var(--text-dim);
  margin-bottom: var(--space-2);
}

.case__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--accent);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur) var(--ease-out);
}

.case__link:hover {
  border-color: currentColor;
}

/* The MoWoB half of each study. Amber and dashed until the founder supplies the real detail. What was broken, what we changed, what it achieved. Same rule as the testimonials: we do not
   describe work we cannot substantiate. */
/* The finished state. This used to be a dashed amber panel, a deliberate "not written yet" marker
   while the three case studies had placeholder text in them. They are written now, so the marker
   goes, and with it the last non-accent hue anywhere in the CSS. */
.case__role {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  background: var(--glass);
}

/* Still genuinely unfinished: the two capability entries have no client and nothing to show. They
   keep a marker, but it is drawn in tone rather than in a second colour, the same way the site
   says "broken" everywhere else. */
.case__role--todo {
  border-style: dashed;
  border-color: var(--text-faint);
  background: transparent;
}

.case__role h3 {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 0.85rem;
}

.case__role dl {
  display: grid;
  gap: 0.7rem;
  margin: 0;
}

.case__role dt {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.case__role dd {
  margin: 0.15rem 0 0;
  color: var(--text-dim);
  font-size: 0.95rem;
}

@media (max-width: 900px) {
  .case {
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }
  .case--flip .case__shot {
    order: 0;
  }
}

/* ---- capability entries ----
   Two entries have no live product to capture. Rather than fake a screenshot or leave a hole,
   the panel carries the actual technical spec. Which is more use to a technical reader anyway.
   The dashed frame says plainly that this is not a product shot. */
.case--spec .case__shot {
  border-style: dashed;
  box-shadow: none;
}

.spec {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: var(--space-3);
  gap: var(--space-2);
}

.spec > div {
  display: grid;
  gap: 0.3rem;
}

.spec dt {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.spec dd {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--text-dim);
}

/* ============================= EXCHANGE ARTIFACTS ============================= */

/* Each service page gets its own artifact, in two states: what arrives, and what leaves.
   Six different visual FORMS, not six recolours of one, so the pages don't feel stamped out:
   a diff, a findings ledger, a wireframe, a test run, a pipeline, a schedule.
   Monochrome. "Before" sits back in --text-faint with dashed edges; "after" comes forward in
   --text and the accent. */

.xviz {
  margin-top: var(--space-3);
  padding: 0.9rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--glass-border);
  background: rgba(0, 0, 0, 0.22);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  line-height: 1.75;
  overflow: hidden;
}

.xviz--in {
  border-style: dashed;
  color: var(--text-faint);
}

.xviz--out {
  border-color: var(--accent-dim);
  color: var(--text-dim);
}

.xviz__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.7rem;
  padding-bottom: 0.55rem;
  border-bottom: 1px solid var(--glass-border);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.xviz--out .xviz__head { color: var(--accent); }

/* ---- 1. code rescue: a diff ---- */
/* pre-wrap, not pre. `pre` kept the code shaped like code but refused to break, so the longest
   line (46 chars) was clipped by the panel's own overflow:hidden at every width where the column
   is narrow: 49px on a 390px phone, and 82px at 801px, where the exchange is still two columns
   but each one is only ~350px. pre-wrap breaks only the lines that genuinely do not fit, so every
   line that has room renders exactly as `pre` drew it. That is why this is not behind a media
   query: the wrap point depends on the column width, not on the viewport. */
.dl { display: grid; grid-template-columns: 1ch 1fr; gap: 0 0.7rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.dl b { font-weight: 400; opacity: 0.6; }
.xviz--in .dl span { text-decoration: line-through; text-decoration-thickness: 1px; opacity: 0.75; }
.xviz--out .dl b { color: var(--accent); }
.xviz--out .dl span { color: var(--text); }

/* ---- 2. security: a findings ledger ---- */
.fnd { display: grid; grid-template-columns: 1fr auto; gap: 0.35rem 0.75rem; align-items: center; }
.fnd i { font-style: normal; }
.fnd u {
  text-decoration: none; font-size: 0.55rem; letter-spacing: 0.12em;
  padding: 0.1rem 0.45rem; border-radius: var(--radius-pill);
  border: 1px solid currentColor; opacity: 0.8;
}
.xviz--out .fnd u { color: var(--accent); opacity: 1; }

/* ---- 3. ui/ux: greybox, then a composed screen ---- */
.wire { display: flex; flex-direction: column; gap: 0.45rem; }
.wire i { display: block; height: 9px; border-radius: 3px; background: rgba(255,255,255,0.1); }
.wire i:nth-child(1) { width: 45%; }
.wire i:nth-child(2) { width: 88%; }
.wire i:nth-child(3) { width: 72%; }
.wire i:nth-child(4) { width: 34%; height: 22px; border-radius: var(--radius-pill); }
.comp { display: flex; flex-direction: column; gap: 0.5rem; }
.comp b { font-family: var(--font-display); font-size: 0.95rem; color: var(--text); }
.comp i { font-style: normal; font-size: 0.66rem; }
.comp u {
  text-decoration: none; margin-top: 0.35rem; padding: 0.45rem; text-align: center;
  border-radius: var(--radius-pill); background: var(--accent); color: #0a1230;
  font-size: 0.62rem; font-weight: 600; letter-spacing: 0.04em;
}

/* ---- 4. QA: a test run ---- */
.run { display: flex; flex-direction: column; }
.run i { font-style: normal; }
.run i::before { content: "✗  "; opacity: 0.7; }
.xviz--out .run i::before { content: "✓  "; color: var(--accent); }
.run b { font-weight: 400; opacity: 0.65; margin-top: 0.4rem; }

/* ---- 5. deployment: a pipeline ---- */
.pipe { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.pipe i {
  font-style: normal; padding: 0.28rem 0.6rem; border-radius: var(--radius-sm);
  border: 1px dashed var(--glass-border-lit);
}
.xviz--out .pipe i { border-style: solid; border-color: var(--accent-dim); color: var(--text); }
.pipe s { text-decoration: none; opacity: 0.45; }
.pipe__note { margin-top: 0.6rem; display: flex; gap: 0.9rem; flex-wrap: wrap; opacity: 0.8; }

/* ---- 6. launch: an eight-week schedule ---- */
.gantt { display: grid; grid-template-columns: 4.2rem repeat(8, 1fr); gap: 0.3rem 0.2rem; align-items: center; }
.gantt i { font-style: normal; font-size: 0.6rem; }
.gantt u { text-decoration: none; height: 7px; border-radius: 2px; background: rgba(255,255,255,0.07); }
.xviz--out .gantt u.on { background: var(--accent); }
.gantt em { grid-column: 2 / -1; font-style: normal; font-size: 0.55rem; letter-spacing: 0.12em; opacity: 0.7; }

/* ============================= STACK ("What we work with") ============================= */

/* A spec sheet: label on the left, chips on the right, hairline between rows. Another distinct
   form again, so a service page reads as several different kinds of information rather than the
   same block repeated. Monochrome; the accent appears only on the row labels. */
.stack {
  display: flex;
  flex-direction: column;
}

.stack__row {
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: var(--space-2) var(--space-3);
  align-items: start;
  padding-block: var(--space-2);
  border-top: 1px solid var(--glass-border);
}

.stack__row:first-child {
  border-top: 0;
}

.stack__row:last-child {
  border-bottom: 1px solid var(--glass-border);
}

.stack__label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  padding-top: 0.35rem;
}

.stack__items {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.stack__items span {
  padding: 0.32rem 0.75rem;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  background: var(--glass);
  font-size: 0.85rem;
  color: var(--text-dim);
  transition: border-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}

.stack__items span:hover {
  border-color: var(--glass-border-lit);
  color: var(--text);
}

.stack__note {
  margin-top: var(--space-3);
  color: var(--text-dim);
  font-size: 0.96rem;
  max-width: 62ch;
}

@media (max-width: 720px) {
  .stack__row {
    grid-template-columns: 1fr;
    gap: 0.7rem;
  }

  .stack__label {
    padding-top: 0;
  }
}
