/* ==========================================================================
   Tech4TIME — pages/service-detail.css
   Shared by the four service detail pages under /pages/services/. Ports the
   NextJS dashboards (SecurityDashboard and its siblings): the layer tabs, the
   node map around a central hub, and the solution card grid.

   The NextJS originals separate their two layers by colour — green for
   proactive, red for reactive. This palette has no hue, and colour alone would
   fail WCAG 1.4.1 in any case, so the layers are told apart by icon, title and
   position instead.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Core capability cards
   -------------------------------------------------------------------------- */

.core-solutions__grid {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
}

.core-card {
  padding: var(--space-xl);
  background-color: var(--bg-elevated);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  transition:
    transform var(--duration) var(--ease-out),
    border-color var(--duration) var(--ease-out),
    box-shadow var(--duration) var(--ease-out);
}

.core-card:hover {
  transform: translateY(-4px);
  border-color: var(--silver-accent-mid);
  box-shadow: var(--shadow);
}

.core-card__icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-block-end: var(--space-md);
  font-size: 1.5rem;
  color: var(--on-accent);
  background-image: var(--silver-gradient-fill);
  border-radius: var(--radius);
}

.core-card__title {
  margin-block-end: var(--space-xs);
  font-size: var(--text-lg);
}

.core-card__text {
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.core-solutions__note {
  margin-block-start: var(--space-lg);
  font-size: var(--text-sm);
  text-align: center;
  color: var(--text-secondary);
}

.core-solutions__note a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  white-space: nowrap;
  font-weight: 600;
  color: var(--accent-text);
}

/* This has to be said again here. `a:hover` in base.css and this rule are both
   one class-level and one type, so they tie on specificity and the later file
   wins — setting the colour above silently took the hover away with it. The
   same override elsewhere (.job__body a, .legal__body a) restates the hover;
   this one had been missed, on all six service pages. */
.core-solutions__note a:hover {
  color: var(--text-primary);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* Nudge the arrow along, as the service cards on the home page do. */
.core-solutions__note a .icon {
  transition: transform var(--duration) var(--ease-out);
}

.core-solutions__note a:hover .icon {
  transform: translateX(0.25rem);
}

/* --------------------------------------------------------------------------
   2. Layer tabs
   The base .tabs component is a row of pills. The dashboards use something
   closer to a sidebar: an icon, a name and a line explaining the layer. This
   modifier supplies that without disturbing the pill variant.
   -------------------------------------------------------------------------- */

.tabs--cards .tabs__list {
  display: grid;
  gap: var(--space-sm);
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}

.tabs--cards .tabs__tab {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  min-height: 0;
  padding: var(--space-md);
  font-size: var(--text-base);
  font-weight: 400;
  text-align: start;
  text-decoration: none;
  background-color: var(--bg-elevated);
  border-radius: var(--radius-lg);
}

.tabs--cards .tabs__tab[aria-selected="true"] {
  color: var(--text-primary);
  background-color: var(--bg-elevated);
  background-image: none;
  border-color: var(--silver-accent-mid);
  box-shadow: var(--shadow-sm);
}

/* The selected tab needs a marker that is not colour. A solid silver bar down
   its leading edge does the job, and the ARIA state carries it for anyone not
   looking at the screen. */
.tabs--cards .tabs__tab[aria-selected="true"]::before {
  content: "";
  position: absolute;
  inset-block: var(--space-sm);
  inset-inline-start: 0;
  width: 4px;
  background-image: var(--silver-gradient-fill);
  border-radius: var(--radius-full);
}

.tabs--cards .tabs__tab {
  position: relative;
}

.tabs--cards .tabs__tab-icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.125rem;
  color: var(--accent-text);
  background-color: var(--bg-surface);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius);
  transition:
    color var(--duration) var(--ease-out),
    background-color var(--duration) var(--ease-out),
    border-color var(--duration) var(--ease-out);
}

.tabs--cards .tabs__tab[aria-selected="true"] .tabs__tab-icon {
  color: var(--on-accent);
  background-image: var(--silver-gradient-fill);
  border-color: transparent;
}

.tabs--cards .tabs__tab-body {
  min-width: 0;
}

.tabs--cards .tabs__tab-name {
  display: block;
  font-weight: 650;
  color: var(--text-primary);
}

.tabs--cards .tabs__tab-text {
  display: block;
  margin-block-start: var(--space-3xs);
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--text-secondary);
}

/* Without JavaScript both panels stay on the page, one after the other, and
   the tabs above are ordinary jump links. A rule between them keeps that
   reading as two sections rather than one run-on list.

   The :not([hidden]) on the FIRST of the pair is what matters: once the tabs
   are live only one panel is on screen, and without this the survivor still
   drew a rule and four rems of padding above itself, leaving an empty gap
   under the tabs — and only ever above the second panel, so the two layers did
   not even match each other. */
.layer:not([hidden]) + .layer {
  margin-block-start: var(--space-2xl);
  padding-block-start: var(--space-2xl);
  border-block-start: var(--border-width) solid var(--border-subtle);
}

/* --------------------------------------------------------------------------
   3. Layer header
   -------------------------------------------------------------------------- */

.layer__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  margin-block-end: var(--space-xl);
  padding: var(--space-lg);
  background-color: var(--bg-elevated);
  border: var(--border-width) solid var(--border-subtle);
  border-inline-start: 4px solid var(--silver-accent-mid);
  border-radius: var(--radius-lg);
}

.layer__title {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-end: var(--space-2xs);
  font-size: var(--text-xl);
}

.layer__icon {
  color: var(--accent-text);
}

.layer__text {
  max-width: 52rem;
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.layer__count {
  flex-shrink: 0;
  padding: var(--space-2xs) var(--space-sm);
  font-size: var(--text-sm);
  font-weight: 650;
  white-space: nowrap;
  color: var(--text-primary);
  background-color: var(--bg-surface);
  border: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius-full);
}

/* --------------------------------------------------------------------------
   4. Node map
   The dashboards scatter each solution around a central hub and swap a detail
   card as you move across them. Here the nodes sit on an even ring, driven by
   two custom properties: --n, how many nodes, and --i, which one this is. That
   keeps the whole thing to plain classes with no inline styles — the CSP on
   this site is style-src 'self', so per-node inline positioning could not run
   at all.

   Panels vary from three nodes to twenty-one, so the ring comes in three sizes
   rather than crowding twenty-one nodes onto a circle built for twelve.

   Every node repeats a card in the grid below, so the ring is a shortcut, not
   the only route to the content: it goes entirely under 52em, where a ring of
   nodes would be illegible.
   -------------------------------------------------------------------------- */

.layer__viz {
  display: none;
}

@media (min-width: 52em) {
  .layer__viz {
    display: grid;
    gap: var(--space-xl);
    align-items: center;
    justify-items: center;
    margin-block-end: var(--space-2xl);
  }

  .soc-map {
    /* Defaults suit the eight-to-fourteen node case. */
    --n: 12;
    --size: 26rem;
    --radius: 10.75rem;
    --node: 3.25rem;

    position: relative;
    width: var(--size);
    height: var(--size);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .soc-map--sm {
    --size: 21rem;
    --radius: 8rem;
  }

  .soc-map--lg {
    --size: 32rem;
    --radius: 13.5rem;
    --node: 2.75rem;
  }

  .soc-map--n2 { --n: 2; }
  .soc-map--n3 { --n: 3; }
  .soc-map--n4 { --n: 4; }
  .soc-map--n5 { --n: 5; }
  .soc-map--n6 { --n: 6; }
  .soc-map--n7 { --n: 7; }
  .soc-map--n8 { --n: 8; }
  .soc-map--n9 { --n: 9; }
  .soc-map--n10 { --n: 10; }
  .soc-map--n11 { --n: 11; }
  .soc-map--n12 { --n: 12; }
  .soc-map--n13 { --n: 13; }
  .soc-map--n14 { --n: 14; }
  .soc-map--n15 { --n: 15; }
  .soc-map--n16 { --n: 16; }
  .soc-map--n17 { --n: 17; }
  .soc-map--n18 { --n: 18; }
  .soc-map--n19 { --n: 19; }
  .soc-map--n20 { --n: 20; }
  .soc-map--n21 { --n: 21; }
  .soc-map--n22 { --n: 22; }
  .soc-map--n23 { --n: 23; }
  .soc-map--n24 { --n: 24; }

  /* THE SPOKES AND THE RING, WHICH ARE REAL GEOMETRY NOW
     They used to be a repeating-conic-gradient masked to a ring, plus a dashed
     border on ::after. One idea, three faults, all of them the same fault --
     a gradient is not a line:

       - A conic wedge is an ANGLE, so its width in pixels grows with the
         radius. Measured on the shipped page: 0.4deg came out 1.20px wide at
         the nodes and 0.39px at the hub. Under a pixel a line does not thin,
         it dissolves, so every spoke faded out before it reached the hub --
         worst on the four cardinal ones, where a sub-pixel horizontal or
         vertical line antialiases to almost nothing.
       - A gradient is rasterised, so a 0.4deg wedge is a staircase, and the
         diagonals read as jagged next to everything else on the page.
       - Both pseudo-elements paint after the <li>s, so the dashed ring sat on
         top of the icons.

     lib/services.php emits an <svg> as the list's first child instead. The box
     here is the RING, not the whole map, which is why that function needs to
     know none of these sizes: inside it a node is always at radius 50 and the
     ring is always the inscribed circle. */
  .soc-map__wires-slot {
    position: absolute;
    /* The ring the nodes sit on, exactly -- the same inset ::after used. */
    inset: calc(var(--size) / 2 - var(--radius));
    /* A pseudo-element hit-tested over its whole box whatever it painted, and
       the ring covered the inner half of every node, so a click aimed at a
       node's centre landed on the <ul>. tools/check_hover.py caught that by
       moving a real pointer. This is a real element and still must not take
       the pointer. */
    pointer-events: none;
  }

  .soc-map__wires {
    display: block;
    width: 100%;
    height: 100%;
  }

  /* Exactly one device pixel at every ring size and every angle.
     vector-effect is right here and would be wrong on the ring below: it moves
     the stroke out of the drawing's coordinate space, which is what a hairline
     wants and what a DASH PATTERN does not -- the dashes would then be
     measured in device pixels too and come out as dots. */
  .soc-map__spoke {
    stroke: var(--border-strong);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
  }

  /* The ring the nodes sit on. Its dashes are in the drawing's own units, so
     they stay in proportion as the ring changes size. */
  .soc-map__ring {
    fill: none;
    stroke: var(--border-subtle);
    stroke-width: 0.3;
    stroke-dasharray: 1 1;
  }

  /* Flex, not grid: two auto grid rows stretch to fill the circle and centre
     their contents separately, which pushed the icon into the top half and the
     label into the bottom. Flex with justify-content centres them as one unit. */
  .soc-map__hub {
    position: absolute;
    top: 50%;
    left: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3xs);
    width: 7rem;
    height: 7rem;
    margin: -3.5rem;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--on-accent);
    background-image: var(--silver-gradient-fill);
    border-radius: 50%;
    box-shadow: var(--shadow);
  }

  .soc-map__hub-label {
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-wider);
  }

  .soc-map__slot {
    /* Fallback so a slot past the last nth-child rule stacks at the top rather
       than breaking the transform outright. */
    --i: 0;

    position: absolute;
    top: 50%;
    left: 50%;
    width: var(--node);
    height: var(--node);
    margin: calc(var(--node) / -2);
    /* Out to the ring, then counter-rotate so the icon stays upright. */
    transform:
      rotate(calc(var(--i) / var(--n) * 360deg))
      translateY(calc(var(--radius) * -1))
      rotate(calc(var(--i) / var(--n) * -360deg));
  }

  /* Child 1 is the spokes and the ring, child 2 the hub, so the nodes start
     at child 3. */
  .soc-map__slot:nth-child(3) { --i: 0 ; }
  .soc-map__slot:nth-child(4) { --i: 1 ; }
  .soc-map__slot:nth-child(5) { --i: 2 ; }
  .soc-map__slot:nth-child(6) { --i: 3 ; }
  .soc-map__slot:nth-child(7) { --i: 4 ; }
  .soc-map__slot:nth-child(8) { --i: 5 ; }
  .soc-map__slot:nth-child(9) { --i: 6 ; }
  .soc-map__slot:nth-child(10) { --i: 7 ; }
  .soc-map__slot:nth-child(11) { --i: 8 ; }
  .soc-map__slot:nth-child(12) { --i: 9 ; }
  .soc-map__slot:nth-child(13) { --i: 10; }
  .soc-map__slot:nth-child(14) { --i: 11; }
  .soc-map__slot:nth-child(15) { --i: 12; }
  .soc-map__slot:nth-child(16) { --i: 13; }
  .soc-map__slot:nth-child(17) { --i: 14; }
  .soc-map__slot:nth-child(18) { --i: 15; }
  .soc-map__slot:nth-child(19) { --i: 16; }
  .soc-map__slot:nth-child(20) { --i: 17; }
  .soc-map__slot:nth-child(21) { --i: 18; }
  .soc-map__slot:nth-child(22) { --i: 19; }
  .soc-map__slot:nth-child(23) { --i: 20; }
  .soc-map__slot:nth-child(24) { --i: 21; }
  .soc-map__slot:nth-child(25) { --i: 22; }
  .soc-map__slot:nth-child(26) { --i: 23; }

  /* The node itself is a button, so it carries the interactive states. */
  .soc-map__node {
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    padding: 0;
    font: inherit;
    color: var(--accent-text);
    background-color: var(--bg-elevated);
    border: var(--border-width) solid var(--border-subtle);
    border-radius: 50%;
    cursor: pointer;
    transition:
      color var(--duration) var(--ease-out),
      background-color var(--duration) var(--ease-out),
      border-color var(--duration) var(--ease-out),
      transform var(--duration) var(--ease-out);
  }

  .soc-map__node:hover {
    transform: scale(1.12);
    border-color: var(--silver-accent-mid);
  }

  /* aria-pressed is the one the script maintains, so the selected node looks
     selected however it was reached — hover, Tab or tap. */
  .soc-map__node[aria-pressed="true"] {
    color: var(--on-accent);
    background-image: var(--silver-gradient-fill);
    border-color: transparent;
    box-shadow: var(--shadow);
  }

  /* In the 52-64em band the map and the card stack, so the card is centred and
     held to a comfortable measure rather than run edge to edge. */
  .layer__detail {
    width: 100%;
    max-width: 30rem;
  }
}

@media (min-width: 64em) {
  /* `auto` rather than a fixed column: the ring has three sizes and the column
     follows whichever one this panel uses. */
  .layer__viz {
    grid-template-columns: auto minmax(0, 1fr);
    justify-items: stretch;
  }

  /* Once they sit side by side the card takes everything the ring leaves,
     instead of stopping at 30rem and leaving the right of the band empty. */
  .layer__detail {
    max-width: none;
  }
}

/* --------------------------------------------------------------------------
   5. Solution cards
   -------------------------------------------------------------------------- */

.layer__grid {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}

.tool-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background-color: var(--bg-elevated);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  transition:
    transform var(--duration) var(--ease-out),
    border-color var(--duration) var(--ease-out),
    box-shadow var(--duration) var(--ease-out);
}

.tool-card:hover {
  transform: translateY(-4px);
  border-color: var(--silver-accent-mid);
  box-shadow: var(--shadow);
}

.tool-card__head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
}

.tool-card__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.125rem;
  color: var(--accent-text);
  background-color: var(--bg-surface);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius);
  transition:
    color var(--duration) var(--ease-out),
    background-color var(--duration) var(--ease-out),
    border-color var(--duration) var(--ease-out);
}

.tool-card:hover .tool-card__icon {
  color: var(--on-accent);
  background-image: var(--silver-gradient-fill);
  border-color: transparent;
}

.tool-card__titles {
  min-width: 0;
}

.tool-card__name {
  margin-block-end: var(--space-3xs);
  font-size: var(--text-base);
  font-weight: 650;
}

.tool-card__category {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
}

.tool-card__desc,
.tool-card__purpose {
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

.tool-card__label {
  display: block;
  margin-block-end: var(--space-3xs);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* The development, cloud and HRaaS data carries a second list per service —
   what the work includes, or which models it is available on. Cybersecurity
   has no equivalent, so cards there simply omit the block. */
.tool-card__features {
  display: grid;
  gap: var(--space-3xs);
  padding: 0;
  margin: 0;
  list-style: none;
}

.tool-card__feature {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3xs);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}

/* Nudged down so the tick sits on the first line's baseline rather than its
   cap height, which reads as misaligned on items that wrap to two lines. */
.tool-card__check {
  flex-shrink: 0;
  margin-block-start: 0.3em;
  color: var(--accent-text);
}

/* Pushed to the bottom so the tag rows line up across a row of cards whose
   descriptions run to different lengths. */
.tool-card__toolset {
  margin-block-start: auto;
  padding-block-start: var(--space-sm);
  border-block-start: var(--border-width) solid var(--border-subtle);
}

.tool-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3xs);
  padding: 0;
  margin: 0;
  list-style: none;
}
