/* ==========================================================================
   IMS Services — section composition
   ========================================================================== */

/* ==========================================================================
   Hero

   The one deliberately dark screen at the top of the site. Everything below
   runs light; going dark here is punctuation, not a default.
   ========================================================================== */

.ims-hero {
  position: relative;
  background-color: var(--ims-navy-950);
  color: var(--ims-on-dark);
  overflow: hidden;
  /* Clears the sticky header, which sits transparent over this section. */
  padding-block: clamp(7rem, 5rem + 10vw, 11rem) clamp(5.5rem, 3rem + 7vw, 9rem);

  /*
   * The brand arc. Both the client's banner and their LinkedIn cover split the
   * navy panel from the daylight side with a single wide curve; this is that
   * device turned on its side. Horizontal radius is 50% so the curve spans the
   * full width, vertical radius stays small so it reads as a gentle sweep
   * rather than a dome.
   */
  border-radius: 0 0 50% 50% / 0 0 clamp(2rem, 4vw, 4.5rem) clamp(2rem, 4vw, 4.5rem);
}

/* A very low-contrast wash so the flat navy has some depth without becoming
   a gradient showpiece, plus a faint node field picking up the circuit motif
   that runs through the client's printed collateral. */
.ims-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 55% at 78% 18%, rgba(3, 134, 158, 0.20), transparent 62%),
    radial-gradient(ellipse 55% 45% at 12% 92%, rgba(7, 53, 103, 0.55), transparent 60%),
    radial-gradient(circle, rgba(143, 227, 226, 0.13) 1px, transparent 1.5px);
  background-size: 100% 100%, 100% 100%, 30px 30px;
  pointer-events: none;
}

/* The label leader lines on the network graphic. */
.ims-netgraph__tick {
  stroke: var(--ims-teal-600);
  stroke-width: 1;
  opacity: 0;
  animation: ims-fade-in 600ms var(--ims-ease) 1.2s forwards;
}

.ims-hero > * { position: relative; z-index: 1; }

/* The dark-background treatment of the logo. The wordmark is currentColor in
   the SVG, so white here is the whole mechanism; the teal cloud mark and its
   cyan gradient already read on navy and are left alone. */
.ims-hero__logo {
  color: var(--ims-white);
  line-height: 0;
  margin-bottom: var(--ims-sp-6);
}

.ims-hero__logo svg {
  height: clamp(2.75rem, 1.8rem + 3vw, 4.25rem);
  width: auto;
  display: block;
}

.ims-hero__eyebrow { color: var(--ims-cyan-300); margin-bottom: var(--ims-sp-4); }

.ims-hero__title {
  font-size: var(--ims-fs-display);
  font-stretch: var(--ims-display-stretch);
  font-weight: 700;
  line-height: var(--ims-lh-tight);
  letter-spacing: var(--ims-ls-display);
  color: var(--ims-white);
  margin: 0 0 var(--ims-sp-5);
  max-width: 16ch;
}

.ims-hero__lead {
  font-size: var(--ims-fs-lead);
  line-height: var(--ims-lh-normal);
  color: var(--ims-on-dark-mid);
  max-width: 46ch;
  margin: 0 0 var(--ims-sp-7);
}

.ims-hero__actions { gap: var(--ims-sp-4); }

.ims-hero__tel {
  display: inline-flex;
  align-items: center;
  gap: var(--ims-sp-2);
  font-family: var(--ims-font-mono);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ims-on-dark);
  text-decoration: none;
  padding-block: 0.85rem;
}

.ims-hero__tel:hover { color: var(--ims-cyan-300); }
.ims-hero__tel svg { width: 1.05rem; height: 1.05rem; }

/* ---- Hero trust strip -------------------------------------------------- */

.ims-hero__strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ims-sp-3) var(--ims-sp-7);
  margin-top: var(--ims-sp-9);
  padding-top: var(--ims-sp-6);
  border-top: 1px solid var(--ims-line-dark);
  list-style: none;
  padding-left: 0;
}

.ims-hero__strip li {
  display: flex;
  align-items: center;
  gap: var(--ims-sp-2);
  margin: 0;
  font-family: var(--ims-font-mono);
  font-size: var(--ims-fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ims-on-dark-soft);
}

.ims-hero__strip svg { width: 0.95rem; height: 0.95rem; color: var(--ims-cyan-400); flex: none; }

/* ==========================================================================
   Hero network graphic

   The subject's own world, rendered literally: a small network that comes up
   and stays up. Nodes fade in, links draw themselves, then a signal runs the
   paths on a slow continuous loop.

   The loop is the one real risk in this design. Most corporate sites animate
   once on load and freeze. A signal that never stops is the thesis of the
   business rendered as motion: always on, always watched. It is kept slow
   (8s) and low contrast so it reads as ambient rather than attention-seeking,
   and it stops entirely under prefers-reduced-motion.
   ========================================================================== */

.ims-netgraph {
  width: 100%;
  height: auto;
  max-width: 34rem;
  margin-inline: auto;
  overflow: visible;
}

@media (max-width: 59.9375rem) {
  .ims-netgraph { max-width: 24rem; margin-top: var(--ims-sp-8); opacity: 0.9; }
}

.ims-netgraph__link {
  fill: none;
  stroke: var(--ims-teal-600);
  stroke-width: 1;
  opacity: 0.42;
  stroke-linecap: round;
  stroke-dasharray: var(--len, 400);
  stroke-dashoffset: var(--len, 400);
  animation: ims-draw 1.1s var(--ims-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 90ms + 200ms);
}

@keyframes ims-draw { to { stroke-dashoffset: 0; } }

/* The travelling signal. A short dash chasing the same path as the link. */
.ims-netgraph__pulse {
  fill: none;
  stroke: var(--ims-cyan-400);
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-dasharray: 16 var(--len, 400);
  stroke-dashoffset: var(--len, 400);
  opacity: 0;
  animation: ims-pulse var(--ims-dur-pulse) linear infinite;
  animation-delay: calc(var(--i, 0) * 700ms + 1.4s);
  filter: drop-shadow(0 0 4px rgba(26, 199, 198, 0.85));
}

@keyframes ims-pulse {
  0%   { stroke-dashoffset: var(--len, 400); opacity: 0; }
  4%   { opacity: 0.95; }
  26%  { stroke-dashoffset: 0; opacity: 0.95; }
  32%  { stroke-dashoffset: 0; opacity: 0; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}

.ims-netgraph__node {
  fill: var(--ims-navy-950);
  stroke: var(--ims-teal-500);
  stroke-width: 1.25;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: ims-node-in 620ms var(--ims-ease-spring) forwards;
  animation-delay: calc(var(--i, 0) * 110ms);
}

@keyframes ims-node-in {
  from { opacity: 0; transform: scale(0.4); }
  to   { opacity: 1; transform: scale(1); }
}

/* Nodes flagged as "live" breathe gently. Only two on the graph carry it, so
   the eye has somewhere to rest rather than everything twitching. */
.ims-netgraph__node--live {
  fill: var(--ims-cyan-400);
  stroke: var(--ims-cyan-200);
  animation:
    ims-node-in 620ms var(--ims-ease-spring) forwards,
    ims-breathe 3.2s var(--ims-ease) infinite 1.2s;
}

@keyframes ims-breathe {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

.ims-netgraph__halo {
  fill: none;
  stroke: var(--ims-cyan-400);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: ims-halo 3.2s var(--ims-ease-out) infinite 1.2s;
}

@keyframes ims-halo {
  0%   { opacity: 0.5; transform: scale(1); }
  70%  { opacity: 0; transform: scale(2.6); }
  100% { opacity: 0; transform: scale(2.6); }
}

.ims-netgraph__cloud {
  fill: none;
  stroke: var(--ims-teal-600);
  stroke-width: 1.25;
  opacity: 0;
  stroke-dasharray: 520;
  stroke-dashoffset: 520;
  animation: ims-draw 1.6s var(--ims-ease-out) 300ms forwards,
             ims-fade-in 500ms var(--ims-ease) 300ms forwards;
}

@keyframes ims-fade-in { to { opacity: 0.55; } }

.ims-netgraph__label {
  fill: var(--ims-on-dark-soft);
  font-family: var(--ims-font-mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0;
  animation: ims-fade-in-full 600ms var(--ims-ease) forwards;
  animation-delay: calc(var(--i, 0) * 110ms + 700ms);
}

@keyframes ims-fade-in-full { to { opacity: 0.75; } }

/* Stillness for anyone who asked for it: draw the finished state, no motion. */
@media (prefers-reduced-motion: reduce) {
  .ims-netgraph__link,
  .ims-netgraph__node,
  .ims-netgraph__cloud,
  .ims-netgraph__label {
    animation: none !important;
    opacity: 1;
    stroke-dashoffset: 0;
  }

  .ims-netgraph__link  { opacity: 0.42; }
  .ims-netgraph__cloud { opacity: 0.55; }
  .ims-netgraph__label { opacity: 0.75; }
  .ims-netgraph__pulse,
  .ims-netgraph__halo  { display: none; }
}

/* ==========================================================================
   Scroll reveal

   Applied only to section headers and topology layers, never to body copy.
   Text that fades in as you reach it is the fastest way to make a site feel
   like it was generated rather than designed.
   ========================================================================== */

.ims-reveal {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--ims-dur-reveal) var(--ims-ease-out),
    transform var(--ims-dur-reveal) var(--ims-ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.ims-reveal.is-visible { opacity: 1; transform: none; }

/* Without JS, nothing stays hidden. */
.no-js .ims-reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .ims-reveal { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   Page header (interior pages)
   ========================================================================== */

.ims-page-head {
  background-color: var(--ims-mist-100);
  border-bottom: 1px solid var(--ims-border);
  padding-block: clamp(3.5rem, 2.5rem + 5vw, 6rem) clamp(2.5rem, 2rem + 3vw, 4rem);
}

.ims-page-head__title { margin: var(--ims-sp-4) 0 var(--ims-sp-4); max-width: 20ch; }

.ims-page-head__lead {
  font-size: var(--ims-fs-lead);
  line-height: var(--ims-lh-normal);
  color: var(--ims-text-mid);
  max-width: 56ch;
  margin: 0;
}

/* ---- Breadcrumb -------------------------------------------------------- */

.ims-crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ims-sp-2);
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--ims-font-mono);
  font-size: var(--ims-fs-xs);
  letter-spacing: 0.05em;
  color: var(--ims-ink-soft);
}

.ims-crumbs li { margin: 0; display: flex; align-items: center; gap: var(--ims-sp-2); }
.ims-crumbs li + li::before { content: "/"; opacity: 0.5; }
.ims-crumbs a { color: var(--ims-ink-soft); text-decoration: none; }
.ims-crumbs a:hover { color: var(--ims-teal-600); }
.ims-crumbs [aria-current="page"] { color: var(--ims-navy-800); }

/* ==========================================================================
   Interior page grid

   Prose plus a sticky aside. This exists because a lone .ims-prose column
   inside the 76rem shell reads as a 60/40 split with nothing in the 40 —
   the container looks broken rather than deliberately narrow. Filling that
   space with the phone number and the rest of the service stack uses the
   full box without stretching body copy past a readable measure.
   ========================================================================== */

.ims-page-grid {
  display: grid;
  gap: clamp(var(--ims-sp-7), 4vw, var(--ims-sp-10));
}

@media (min-width: 62rem) {
  .ims-page-grid {
    grid-template-columns: minmax(0, 1fr) 19rem;
    align-items: start;
  }
}

/* Inside the grid the column already sets the measure, so the prose max-width
   would only shrink it further and reintroduce the gap. */
.ims-page-grid .ims-prose { max-width: none; }

/* Pages with no aside centre their prose rather than hugging the left edge. */
.ims-page-grid--solo { display: block; }
.ims-page-grid--solo .ims-prose { max-width: 68ch; margin-inline: auto; }

.ims-page-aside {
  display: flex;
  flex-direction: column;
  gap: var(--ims-sp-5);
}

@media (min-width: 62rem) {
  .ims-page-aside {
    position: sticky;
    /* Clears the sticky header. */
    top: 6.5rem;
  }
}

.ims-aside-card {
  padding: var(--ims-sp-6);
  border: 1px solid var(--ims-border);
  border-radius: var(--ims-r-lg);
  background-color: var(--ims-bg);
}

/* The contact card is the one thing on the page we want tapped, so it is the
   only element on an interior page allowed to go dark. */
.ims-aside-card--accent {
  background-color: var(--ims-navy-950);
  border-color: transparent;
  color: var(--ims-on-dark);
  position: relative;
  overflow: hidden;
}

.ims-aside-card--accent::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 80% 60% at 80% 0%, rgba(3, 134, 158, 0.35), transparent 65%);
  pointer-events: none;
}

.ims-aside-card--accent > * { position: relative; }

.ims-aside-card__label {
  font-family: var(--ims-font-mono);
  font-size: var(--ims-fs-label);
  font-weight: 500;
  letter-spacing: var(--ims-ls-label);
  text-transform: uppercase;
  color: var(--ims-teal-600);
  margin: 0 0 var(--ims-sp-3);
}

.ims-aside-card--accent .ims-aside-card__label { color: var(--ims-cyan-300); }

.ims-aside-card__text {
  font-size: var(--ims-fs-sm);
  line-height: 1.55;
  color: var(--ims-on-dark-mid);
  margin: 0 0 var(--ims-sp-5);
  max-width: none;
}

.ims-aside-card__tel {
  display: inline-flex;
  align-items: center;
  gap: var(--ims-sp-2);
  font-family: var(--ims-font-display);
  font-size: 1.25rem;
  font-stretch: 108%;
  font-weight: 600;
  color: var(--ims-white);
  text-decoration: none;
  margin-bottom: var(--ims-sp-5);
}

.ims-aside-card__tel:hover { color: var(--ims-cyan-300); }

.ims-aside-card__meta {
  margin: var(--ims-sp-4) 0 0;
  font-size: var(--ims-fs-xs);
  color: var(--ims-on-dark-soft);
  max-width: none;
}

.ims-aside-card__meta a { color: inherit; }

.ims-aside-list { list-style: none; margin: 0; padding: 0; }
.ims-aside-list li { margin: 0; }

.ims-aside-list a {
  display: flex;
  align-items: center;
  gap: var(--ims-sp-3);
  padding: var(--ims-sp-3) 0;
  border-bottom: 1px solid var(--ims-border);
  color: var(--ims-text);
  text-decoration: none;
  font-size: var(--ims-fs-sm);
  font-weight: 500;
  transition: color var(--ims-dur-fast) var(--ims-ease),
              padding-left var(--ims-dur-base) var(--ims-ease-out);
}

.ims-aside-list li:last-child a { border-bottom: none; padding-bottom: 0; }

.ims-aside-list a:hover { color: var(--ims-teal-600); padding-left: var(--ims-sp-2); }

.ims-aside-list svg { width: 1.1rem; height: 1.1rem; color: var(--ims-teal-600); flex: none; }

/* ==========================================================================
   Prose (page body content)
   ========================================================================== */

.ims-prose { max-width: 68ch; }
.ims-prose > * + * { margin-top: var(--ims-sp-5); }
.ims-prose h2 { margin-top: var(--ims-sp-9); }
.ims-prose h3 { margin-top: var(--ims-sp-7); }
.ims-prose h2 + *, .ims-prose h3 + * { margin-top: var(--ims-sp-4); }
.ims-prose ul, .ims-prose ol { padding-left: 1.25em; }
.ims-prose li::marker { color: var(--ims-teal-600); }
.ims-prose img { border-radius: var(--ims-r-md); }

/* ==========================================================================
   FAQ

   Built on <details>/<summary>, so it is keyboard operable and announced
   correctly with no ARIA of our own, and every answer is still readable with
   JavaScript disabled. The marker is drawn in CSS because the native disclosure
   triangle cannot be styled consistently across browsers.
   ========================================================================== */

.ims-faq {
  border-top: 1px solid var(--ims-border);
}

.ims-faq__item {
  border-bottom: 1px solid var(--ims-border);
}

.ims-faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ims-sp-4);
  padding: var(--ims-sp-5) 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--ims-font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  font-stretch: 104%;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ims-text);
  transition: color var(--ims-dur-fast) var(--ims-ease);
}

/* Hide the native marker in both engines. */
.ims-faq__q::-webkit-details-marker { display: none; }
.ims-faq__q::marker { content: ""; }

.ims-faq__q:hover { color: var(--ims-teal-600); }

.ims-faq__q:focus-visible {
  outline: 3px solid var(--ims-focus);
  outline-offset: -3px;
  border-radius: var(--ims-r-xs);
}

/* Plus sign that becomes a minus when open. */
.ims-faq__marker {
  flex: none;
  position: relative;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.15rem;
  border-radius: var(--ims-r-xs);
  color: var(--ims-teal-600);
}

.ims-faq__marker::before,
.ims-faq__marker::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background-color: currentColor;
  border-radius: 2px;
  transition: transform var(--ims-dur-base) var(--ims-ease-out),
              opacity var(--ims-dur-fast) var(--ims-ease);
}

.ims-faq__marker::before {
  width: 1.05rem;
  height: 2px;
  transform: translate(-50%, -50%);
}

.ims-faq__marker::after {
  width: 2px;
  height: 1.05rem;
  transform: translate(-50%, -50%);
}

.ims-faq__item[open] .ims-faq__marker { color: var(--ims-cyan-400); }
.ims-faq__item[open] .ims-faq__marker::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }

.ims-faq__a {
  padding: 0 0 var(--ims-sp-5);
  max-width: 62ch;
}

.ims-faq__a > * + * { margin-top: var(--ims-sp-4); }
.ims-faq__a p { color: var(--ims-text-mid); line-height: var(--ims-lh-relaxed); margin: 0; }
.ims-faq__a p + p { margin-top: var(--ims-sp-4); }
.ims-faq__a ul, .ims-faq__a ol { color: var(--ims-text-mid); }

/* Gentle reveal, skipped entirely under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  .ims-faq__item[open] .ims-faq__a {
    animation: ims-faq-open var(--ims-dur-base) var(--ims-ease-out);
  }
}

@keyframes ims-faq-open {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

/* ---- Groups ------------------------------------------------------------- */

.ims-faq-group + .ims-faq-group { margin-top: var(--ims-sp-10); }

.ims-faq-group__title {
  font-size: var(--ims-fs-h3);
  margin-bottom: var(--ims-sp-3);
  scroll-margin-top: 7rem;
}

.ims-faq-group__intro {
  color: var(--ims-text-mid);
  margin-bottom: var(--ims-sp-5);
  max-width: 58ch;
}

/* ---- Jump links in the aside -------------------------------------------- */

.ims-faq-nav {
  padding: var(--ims-sp-6);
  border: 1px solid var(--ims-border);
  border-radius: var(--ims-r-lg);
  background-color: var(--ims-bg);
}

.ims-faq-nav ul { list-style: none; margin: 0; padding: 0; }
.ims-faq-nav li { margin: 0; }

.ims-faq-nav a {
  display: block;
  padding: var(--ims-sp-3) 0;
  border-bottom: 1px solid var(--ims-border);
  color: var(--ims-text);
  text-decoration: none;
  font-size: var(--ims-fs-sm);
  font-weight: 500;
  transition: color var(--ims-dur-fast) var(--ims-ease),
              padding-left var(--ims-dur-base) var(--ims-ease-out);
}

.ims-faq-nav li:last-child a { border-bottom: none; padding-bottom: 0; }
.ims-faq-nav a:hover { color: var(--ims-teal-600); padding-left: var(--ims-sp-2); }

/* ---- FAQ block on a service page ----------------------------------------
   Named .ims-service-faq, not .ims-page-faq. The body class for a page is
   ims-is-<slug>, but it used to be ims-page-<slug>, which meant the page
   slugged "faq" matched a rule intended for this component and put a border
   and 7rem of spacing on <body>. Keep component names clear of that pattern.
   ---------------------------------------------------------------------- */

.ims-service-faq {
  margin-top: var(--ims-sp-9);
  padding-top: var(--ims-sp-8);
  border-top: 2px solid var(--ims-border);
}

.ims-service-faq > h2 { margin-bottom: var(--ims-sp-5); }

/* ==========================================================================
   Closing call to action
   ========================================================================== */

.ims-cta { text-align: center; }
.ims-cta__inner { max-width: 40rem; margin-inline: auto; }

.ims-cta__title {
  font-size: var(--ims-fs-h2);
  color: var(--ims-white);
  margin: 0 0 var(--ims-sp-4);
}

.ims-cta__text {
  font-size: var(--ims-fs-lead);
  color: var(--ims-on-dark-mid);
  margin: 0 auto var(--ims-sp-7);
  max-width: 48ch;
}

.ims-cta .ims-btn-row { justify-content: center; }

/* ==========================================================================
   Contact
   ========================================================================== */

.ims-contact-grid {
  display: grid;
  gap: clamp(var(--ims-sp-7), 5vw, var(--ims-sp-10));
}

@media (min-width: 60rem) {
  .ims-contact-grid { grid-template-columns: 1.25fr 0.75fr; align-items: start; }
}

.ims-contact-detail {
  display: flex;
  gap: var(--ims-sp-4);
  padding-block: var(--ims-sp-4);
  border-bottom: 1px solid var(--ims-border);
}

.ims-contact-detail:last-child { border-bottom: none; }

.ims-contact-detail__icon {
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--ims-r-sm);
  background-color: var(--ims-mist-100);
  color: var(--ims-teal-600);
}

.ims-contact-detail__icon svg { width: 1.1rem; height: 1.1rem; }

.ims-contact-detail__label {
  font-family: var(--ims-font-mono);
  font-size: var(--ims-fs-label);
  letter-spacing: var(--ims-ls-label);
  text-transform: uppercase;
  color: var(--ims-ink-soft);
  margin: 0 0 0.15rem;
}

.ims-contact-detail__value { margin: 0; font-weight: 500; color: var(--ims-text); }
.ims-contact-detail__value a { color: inherit; text-decoration: none; }
.ims-contact-detail__value a:hover { color: var(--ims-teal-600); }

/* ==========================================================================
   404
   ========================================================================== */

.ims-404 { text-align: center; padding-block: clamp(5rem, 4rem + 8vw, 9rem); }
.ims-404__code {
  font-family: var(--ims-font-mono);
  font-size: var(--ims-fs-label);
  letter-spacing: var(--ims-ls-label);
  text-transform: uppercase;
  color: var(--ims-teal-600);
  margin-bottom: var(--ims-sp-4);
}
.ims-404__links { justify-content: center; margin-top: var(--ims-sp-7); }
