/* ===== SERVICES PAGE (dark) ===== */

/* Shantell Sans, a marker hand, for the section labels: at full bounce and
   informality its letters wobble like the hand-lettered titles. Chinese takes
   ZCOOL KuaiLe, a playful hand of its own, loaded only for Chinese text. */
@import url('https://fonts.googleapis.com/css2?family=Shantell+Sans:wght,BNCE,INFM@700,100,100&family=ZCOOL+KuaiLe&display=swap');

/* The site's own variables, turned dark for this page. The header, the mobile menu
   and the language switcher read them, so they follow without their own rules.
   The accent is blue here, not the site's coral: coral on dark read as someone
   else's brand. It is the blue of the pictures (about #408CEE), a step lighter so
   small labels stay as readable as the coral was. */
body.services-dark {
  --bg: #0F0E0C;
  --text: #F3EEE6;
  --text-muted: #B4ADA3;
  --accent: #5B9DF5;
  --accent-hover: #86B6F8;
  --border-subtle: rgba(255, 244, 230, 0.10);
  --sv-surface: #171512;
  --sv-art: #0F1014; /* the background of the service pictures, after recolouring */
  --sv-glow: 64, 140, 238; /* the pictures' blue, as rgb() channels for the glows */
  --sv-line: rgba(255, 244, 230, 0.10);
  --sv-line-strong: rgba(255, 244, 230, 0.22);

  /* Grain, a blue glow behind the hero, a fainter one lower down, then the ground. */
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.06'/%3E%3C/svg%3E"),
    radial-gradient(900px 560px at 88% -6%, rgba(var(--sv-glow), 0.17), transparent 62%),
    radial-gradient(720px 520px at -12% 38%, rgba(var(--sv-glow), 0.06), transparent 62%),
    var(--bg);
  color: var(--text);

  /* style.css sets height: 100% on body, so the grain and glow stopped one screen
     down, with a visible seam. Grown to its content, body paints the whole page. */
  height: auto;
}

/* Overscroll and the strip behind the fixed header show html's background. */
html:has(body.services-dark) {
  background: #0F0E0C;
}

.services-dark header {
  background-color: rgba(15, 14, 12, 0.82);
}

.services-dark .site-logo img {
  filter: invert(1);
}

/* The footer stays light: the Cartesia and ICEC logos are only approved in their
   dark-on-light forms (see the comments in style.css and footer.php). */
.services-dark footer {
  --bg: #FDFCF8;
  --text: #0F0F0F;
  --text-muted: #555555;
  --border-subtle: #ECEAE3;
  background: var(--bg);
  color: var(--text-muted);
  padding-top: 2.5rem;
}

/* ===== LAYOUT ===== */

/* display, justify-items and text-align undo what style.css sets on every main. */
main.services-page {
  display: block;
  justify-items: normal;
  text-align: left;
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: calc(var(--header-h) + 48px) 32px 112px;
  box-sizing: border-box;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  color: var(--text);
}

/* The wordmark with the page's name beside it, after a hairline, and the way in
   for clients at the far end. Only the wordmark links home. When the row runs out
   of room the client link wraps, and wrap-reverse puts it on a line of its own
   above the wordmark rather than under it. */
.sv-mark {
  display: flex;
  flex-wrap: wrap-reverse;
  align-items: center;
  gap: 12px 22px;
  margin-bottom: 88px;
}

.sv-mark-home {
  display: block;
  flex: none;
}

.sv-mark img {
  display: block;
  width: 190px;
  height: auto;
  filter: invert(1);
}

.sv-mark-label {
  padding: 9px 0 9px 22px;
  border-left: 1px solid var(--sv-line-strong);
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Opens the client's space on with.tappatapps.com. Its door skips the password
   for anyone already signed in, so a client lands straight in their folder. */
.sv-access {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
  padding: 6px 6px 6px 18px;
  border: 1px solid var(--sv-line-strong);
  border-radius: 999px;
  color: var(--text);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 200ms ease, background-color 200ms ease;
}

.sv-access:hover {
  border-color: var(--accent);
  background-color: rgba(var(--sv-glow), 0.08);
}

.sv-access:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.sv-access-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--bg);
}

.sv-access-icon svg {
  display: block;
  width: 12px;
  height: 12px;
}

/* ===== HERO ===== */

.sv-hero {
  max-width: 880px;
  margin-bottom: clamp(96px, 14vw, 168px);
}

/* The heading is real text, kept off screen for search engines and screen readers.
   Clip pattern rather than display: none, so assistive tech still announces it. */
.sv-title-text {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.sv-title {
  margin: 0 0 32px;
}

/* Hand lettering, one picture per language (its alt text is the tagline). */
.sv-title-art {
  display: block;
  width: min(100%, 620px);
  height: auto;
}

.sv-lead {
  max-width: 36rem;
  margin: 0;
  font-size: clamp(1.05rem, 1.6vw, 1.2rem);
  line-height: 1.7;
  color: var(--text-muted);
}

/* ===== SECTION LABELS ===== */

.sv-heading {
  display: flex;
  align-items: center;
  gap: 18px;
  margin: 0 0 56px;
  font-family: 'Shantell Sans', 'ZCOOL KuaiLe', 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: clamp(1.3rem, 2.2vw, 1.6rem);
  font-weight: 700;
  line-height: 1.2;
  color: var(--accent);
}

/* A hand-drawn line, made with ChatGPT (images/services/PROMPTS.md), a different
   one in each section. The flick at its start and the taper at its end keep their
   shape; only the long middle stretches to the width that is left. Each picture
   is 60 px tall; --sv-stroke-l is how wide its flick is, and its taper is 60 px. */
.sv-heading::after {
  --sv-line-h: 28px;
  --sv-stroke: url("/images/services/line-1.webp");
  --sv-stroke-l: 90;
  content: "";
  flex: 1;
  min-width: calc(var(--sv-line-h) * (var(--sv-stroke-l) / 60 + 1));
  height: var(--sv-line-h);
  border: 0 solid transparent;
  border-image-source: var(--sv-stroke);
  border-image-slice: 0 60 0 var(--sv-stroke-l) fill;
  border-image-width: 0 var(--sv-line-h) 0 calc(var(--sv-line-h) * var(--sv-stroke-l) / 60);
  border-image-repeat: stretch;
  opacity: 0.55;
}

.sv-background .sv-heading::after {
  --sv-stroke: url("/images/services/line-2.webp");
  --sv-stroke-l: 100;
}

.sv-contact .sv-heading::after {
  --sv-stroke: url("/images/services/line-3.webp");
  --sv-stroke-l: 110;
}

/* ===== SERVICES ===== */

.sv-services {
  margin-bottom: clamp(104px, 14vw, 176px);
}

.sv-list {
  display: grid;
  gap: clamp(64px, 10vw, 128px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sv-item {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(32px, 5.5vw, 80px);
  align-items: center;
}

/* Every other row puts the picture on the right. */
.sv-item:nth-child(even) .sv-figure {
  order: 2;
}

.sv-figure {
  margin: 0;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border: 1px solid var(--sv-line);
  border-radius: 22px;
  background: var(--sv-art);
  box-shadow: 0 40px 90px -50px rgba(var(--sv-glow), 0.45);
}

.sv-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 700ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

.sv-item:hover .sv-figure img {
  transform: scale(1.035);
}

.sv-copy h3 {
  margin: 0 0 14px;
}

/* The services' titles, here and in their popups, are hand lettering too, one
   picture per title (images/services/PROMPTS.md). --w is a picture's width on a
   desktop, set so a line of lettering is about as tall in every title. */
.sv-hand {
  display: block;
  width: calc(var(--w) * var(--sv-hand-scale, 1) * 1px);
  max-width: 100%;
  height: auto;
}

.sv-modal-text h2 .sv-hand {
  --sv-hand-scale: 1.1;
}

.sv-copy p {
  max-width: 32rem;
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--text-muted);
}

/* "More" opens the service's popup (scripts/services.js). */
.sv-more {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  margin-top: 28px;
  padding: 7px 7px 7px 20px;
  border: 1px solid var(--sv-line-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 200ms ease, background-color 200ms ease;
}

.sv-more:hover {
  border-color: var(--accent);
  background-color: rgba(var(--sv-glow), 0.08);
}

.sv-more:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* A plus in a blue disc, which turns a quarter on hover. */
.sv-more-icon {
  position: relative;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent);
  transition: transform 400ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

.sv-more-icon::before,
.sv-more-icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 11px;
  height: 1.5px;
  margin: -0.75px 0 0 -5.5px;
  border-radius: 1px;
  background: var(--bg);
}

.sv-more-icon::after {
  transform: rotate(90deg);
}

.sv-more:hover .sv-more-icon {
  transform: rotate(90deg);
}

/* ===== BACKGROUND ===== */

.sv-background {
  margin-bottom: clamp(104px, 14vw, 176px);
}

.sv-background p {
  max-width: 46rem;
  margin: 0;
  font-size: clamp(1.2rem, 2.2vw, 1.55rem);
  line-height: 1.6;
  color: var(--text);
}

.sv-background p + p {
  margin-top: 1.1em;
}

/* ===== CONTACT ===== */

.sv-contact {
  position: relative;
  overflow: hidden;
  padding: clamp(36px, 6vw, 72px);
  border: 1px solid var(--sv-line);
  border-radius: 28px;
  background:
    radial-gradient(600px 320px at 100% 0%, rgba(var(--sv-glow), 0.16), transparent 70%),
    var(--sv-surface);
}

.sv-contact .sv-heading {
  margin-bottom: 32px;
}

.sv-contact .sv-contact-lead {
  max-width: 30ch;
  margin: 0 0 36px;
  font-weight: 600;
  font-size: clamp(1.6rem, 3.5vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--text);
}

.sv-contact p {
  margin: 0 0 18px;
  color: var(--text-muted);
  line-height: 1.7;
}

.sv-contact p:last-child {
  margin-bottom: 0;
}

.sv-contact strong {
  color: var(--text);
  font-weight: 600;
}

.services-dark .email-wrapper {
  justify-content: flex-start;
  gap: 0.75rem;
}

.services-dark a.email {
  font-size: clamp(1.25rem, 3vw, 1.8rem);
  font-weight: 500;
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: rgba(var(--sv-glow), 0.6);
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}

.services-dark a.email:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}

.services-dark .copy-btn {
  background: transparent;
  border: 1px solid var(--sv-line-strong);
  border-radius: 999px;
  padding: 0.3rem 0.8rem;
  color: var(--text);
  letter-spacing: 0.08em;
}

.services-dark .copy-btn:hover {
  background: transparent;
  border-color: var(--accent);
  color: var(--accent);
}

.services-dark .copy-btn.copied {
  background: #4caf50;
  border-color: #4caf50;
  color: #ffffff;
}

/* ===== POPUPS ===== */

/* One <dialog> per service. scripts/services.js opens it, adds .is-open a frame
   later so it scales up out of the button that opened it, and takes .is-open
   off again before it closes, so it shrinks away. */
.sv-modal {
  width: min(720px, calc(100vw - 32px));
  max-width: none;
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  margin: auto;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--sv-line-strong);
  border-radius: 28px;
  background: var(--sv-art);
  color: var(--text);
  box-shadow:
    0 60px 120px -40px rgba(0, 0, 0, 0.9),
    0 40px 140px -60px rgba(var(--sv-glow), 0.6);
  opacity: 0;
  transform: scale(0.88);
  transform-origin: var(--sv-origin, 50% 50%);
  /* Closing: short and plain. */
  transition: opacity 180ms ease, transform 220ms ease-in;
}

.sv-modal[open] {
  display: flex;
  flex-direction: column;
}

.sv-modal.is-open {
  opacity: 1;
  transform: none;
  /* Opening: fast out of the button, then a long soft settle. */
  transition: opacity 240ms ease-out, transform 560ms cubic-bezier(0.16, 1, 0.3, 1);
}

.sv-modal::backdrop {
  background: rgba(6, 7, 10, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 220ms ease;
}

.sv-modal.is-open::backdrop {
  opacity: 1;
  transition-duration: 320ms;
}

/* The page behind stays still while a popup is open. */
html:has(.sv-modal[open]) {
  overflow: hidden;
}

.sv-modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--sv-line-strong);
  border-radius: 50%;
  background: rgba(15, 16, 20, 0.6);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--text);
  cursor: pointer;
  transition: border-color 200ms ease, color 200ms ease, transform 300ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

.sv-modal-close:hover {
  border-color: var(--accent);
  color: var(--accent);
  transform: rotate(90deg);
}

.sv-modal-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.sv-modal-close svg {
  display: block;
  width: 16px;
  height: 16px;
}

.sv-modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--sv-line-strong) transparent;
}

/* The service's picture, whole. Its background is the popup's, and the edges
   fade out so no seam shows. */
.sv-modal-art {
  display: block;
  width: auto;
  height: clamp(150px, 30vh, 280px);
  max-width: 100%;
  aspect-ratio: 3 / 2;
  margin: 8px auto 0;
  object-fit: cover;
  -webkit-mask-image: radial-gradient(closest-side, #000 74%, transparent);
  mask-image: radial-gradient(closest-side, #000 74%, transparent);
}

.sv-modal-text {
  padding: 0 clamp(24px, 6vw, 64px) clamp(36px, 6vw, 60px);
}

.sv-modal-text h2 {
  margin: 20px 0 18px;
}

.sv-modal-text p {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.7;
  color: var(--text-muted);
}

.sv-modal-text .sv-modal-lead {
  margin-bottom: 20px;
  font-weight: 500;
  font-size: clamp(1.15rem, 2.2vw, 1.4rem);
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--text);
}

.sv-modal-text h3 {
  margin: 34px 0 16px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.sv-modal-text ul {
  display: grid;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sv-modal-text li {
  position: relative;
  padding-left: 30px;
  line-height: 1.6;
  color: var(--text);
}

.sv-modal-text li::before {
  content: "";
  position: absolute;
  top: 0.8em;
  left: 0;
  width: 16px;
  height: 1px;
  background: var(--accent);
}

.sv-modal-fit {
  margin-top: 36px;
  padding: 22px 24px;
  border: 1px solid var(--sv-line);
  border-radius: 18px;
  background: rgba(255, 244, 230, 0.03);
}

.sv-modal-text .sv-modal-fit h3 {
  margin: 0 0 10px;
}

.sv-modal-text .sv-modal-fit p {
  color: var(--text);
}

/* The picture and each block of text rise in one after another once the popup
   has grown, and all go together when it closes. */
.sv-modal-art,
.sv-modal-text > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 120ms ease, transform 120ms ease;
}

.sv-modal-art {
  transform: scale(0.94);
}

.sv-modal.is-open .sv-modal-art,
.sv-modal.is-open .sv-modal-text > * {
  opacity: 1;
  transform: none;
  transition: opacity 500ms ease-out, transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(110ms + var(--sv-i, 0) * 55ms);
}

.sv-modal-text > :nth-child(1) { --sv-i: 1; }
.sv-modal-text > :nth-child(2) { --sv-i: 2; }
.sv-modal-text > :nth-child(3) { --sv-i: 3; }
.sv-modal-text > :nth-child(4) { --sv-i: 4; }
.sv-modal-text > :nth-child(5) { --sv-i: 5; }
.sv-modal-text > :nth-child(6) { --sv-i: 6; }
.sv-modal-text > :nth-child(n + 7) { --sv-i: 7; }

/* ===== CHINESE ===== */

/* Plus Jakarta Sans has no Chinese, so the big contact line names the Chinese
   system fonts, and drops the tight tracking and line height set for Latin. */
.services-dark:lang(zh) .sv-contact .sv-contact-lead {
  font-family: 'Plus Jakarta Sans', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.2;
}

.services-dark:lang(zh) .sv-modal-text .sv-modal-lead {
  font-family: 'Plus Jakarta Sans', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
  font-size: clamp(1.15rem, 2.2vw, 1.35rem);
  font-weight: 500;
  line-height: 1.6;
}

/* ===== MOTION ===== */

@media (prefers-reduced-motion: no-preference) {
  .sv-hero > * {
    animation: sv-rise 900ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }

  .sv-hero > :nth-child(2) {
    animation-delay: 90ms;
  }

  /* Rows rise in as they scroll into view where the browser can tie an animation
     to scrolling; elsewhere they are simply there. */
  @supports (animation-timeline: view()) {
    .sv-item {
      animation: sv-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 45%;
    }
  }
}

@keyframes sv-rise {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Popups still fade, but nothing grows, rises or spins. */
@media (prefers-reduced-motion: reduce) {
  .sv-modal,
  .sv-modal-art,
  .sv-modal-text > *,
  .sv-more:hover .sv-more-icon,
  .sv-modal-close:hover {
    transform: none;
  }

  .sv-modal.is-open .sv-modal-art,
  .sv-modal.is-open .sv-modal-text > * {
    transition-delay: 0s;
  }
}

/* ===== RESPONSIVE ===== */

@media (max-width: 760px) {
  main.services-page {
    padding: calc(var(--header-h) + 24px) 20px 80px;
  }

  .sv-mark {
    gap: 10px 16px;
    margin-bottom: 64px;
  }

  .sv-mark img {
    width: 150px;
  }

  .sv-mark-label {
    padding-left: 16px;
  }

  .sv-heading {
    margin-bottom: 36px;
  }

  .sv-heading::after {
    --sv-line-h: 22px;
  }

  .sv-hand,
  .sv-modal-text h2 .sv-hand {
    --sv-hand-scale: 0.8;
  }

  .sv-item {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  .sv-item:nth-child(even) .sv-figure {
    order: 0;
  }

  .sv-figure {
    border-radius: 18px;
  }

  .sv-contact {
    border-radius: 22px;
  }

  .sv-more {
    margin-top: 22px;
  }

  .sv-modal {
    width: calc(100vw - 24px);
    max-height: calc(100vh - 24px);
    max-height: calc(100dvh - 24px);
    border-radius: 22px;
  }

  .sv-modal-close {
    top: 10px;
    right: 10px;
  }

  .sv-modal-art {
    height: clamp(130px, 26vh, 210px);
  }

  .sv-modal-fit {
    padding: 18px 20px;
  }
}
