/* ==========================================================================
   Hardware clusters
   --------------------------------------------------------------------------
   Ported from the LBC design system (`hardware-v3.css`), renamed to the `hwc`
   namespace and rebuilt on the landing's own primitives: .card / .card--nested
   for the surfaces, .selector-chip for the country tabs, .btn for the action.

   A globe on the left, a cluster picker and its spec table on the right. The
   globe carries no surface of its own — a sphere inside a rectangle reads as a
   picture of a globe rather than a globe — so only the panel is a card.

   The only clickable things are the country tabs, the globe markers and the
   picker cards; everything else is read-only, so nothing else lifts or glows.

   Without JS the picker shows every cluster and every spec table at once —
   that is the fallback, not a broken state.
   ========================================================================== */

/* No motion tokens exist in variables.css yet, so the section carries its
   own. Everything here eases out: nothing in this component should feel like
   it is being pulled. */
.hwc {
  --hwc-ease: cubic-bezier(.22, .61, .36, 1);
  --hwc-ease-soft: cubic-bezier(.4, 0, .2, 1);
  --hwc-fast: .18s;
  --hwc-slow: .32s;

  position: relative;
  z-index: 1;
}

.hwc__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: var(--gap-lg);
  align-items: start;
}

/* ==========================================================================
   Globe
   No surface, no border: the sphere sits straight on the section, lit by a
   soft brand halo and dropped onto its own shadow.
   ========================================================================== */

.hwc-map {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.hwc-globe {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 8px 8px 4px;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}

.hwc-globe:active { cursor: grabbing; }

/* Atmosphere. Wider than the sphere and very faint, so the globe reads as
   sitting in light rather than on a plate. */
.hwc-globe::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 0;
  width: 116%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(var(--primary-color-rgb), .10) 0%,
    rgba(var(--primary-color-rgb), .04) 46%,
    transparent 66%
  );
  pointer-events: none;
}

.hwc-globe svg {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: auto;
  max-width: 560px;
  overflow: visible;
  filter: drop-shadow(0 26px 46px rgba(0, 0, 0, .55));
}

/* The globe fades up once the geometry is drawn. Keyed on .hwc--globe rather
   than a default-hidden state, so a failed fetch or no JS never leaves an
   invisible column behind. */
.hwc--globe .hwc-globe {
  animation: hwcGlobeIn .8s var(--hwc-ease-soft) both;
}

@keyframes hwcGlobeIn {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to { opacity: 1; transform: none; }
}

/* The globe body: a top-lit sphere, hairline rim, faint graticule. */
.hwc-sphere { fill: url(#hwcSphere); }
.hwc-rim { fill: none; stroke: rgba(255, 255, 255, .07); stroke-width: 1px; }
.hwc-grat { fill: none; stroke: rgba(255, 255, 255, .045); stroke-width: .5px; }
.hwc-land { fill: #333; stroke: #1c1c1c; stroke-width: .6px; }

/* A country holding a cluster is tinted toward the page's brand colour, so the
   globe follows the per-product theming the rest of the page uses. */
.hwc-land.is-host {
  fill: #4a4a58;
  fill: color-mix(in srgb, var(--primary-color) 18%, #333);
}

.hwc-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-xs);
  margin: 0;
  padding: 14px 0 0;
  font-family: var(--mono-font);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gray-500);
}

.hwc-hint svg { width: 13px; height: 13px; }

/* No globe (no JS, or the geometry failed to load): the empty sphere and the
   drag hint have nothing to describe, so they go and the panel takes the
   width. .hwc--globe is set by the script once the geometry is drawn. */
.hwc:not(.hwc--globe) .hwc-globe,
.hwc:not(.hwc--globe) .hwc-hint {
  display: none;
}

.hwc:not(.hwc--globe) .hwc__grid {
  grid-template-columns: minmax(0, 1fr);
}

.hwc-tabs {
  display: flex;
  justify-content: center;
  padding: 18px 16px 0;
}

.hwc-tabs .selector-chips { justify-content: center; }

/* ==========================================================================
   Markers
   Two expanding rings, a halo and a dot. Colour carries latency once it has
   been measured; until then every marker is the neutral brand indigo.

   Only the selected country pulses at full strength — three markers all
   shouting at once is noise, not information.
   ========================================================================== */

.hwc-ping {
  cursor: pointer;
  color: var(--gray-400);
  transition: opacity var(--hwc-fast) linear;
}

.hwc-ping.hwc-lat--good { color: var(--status-green); }
.hwc-ping.hwc-lat--mid { color: var(--status-yellow); }
.hwc-ping.hwc-lat--bad { color: #f43f5e; }
.hwc-ping.is-active { color: var(--primary-color); }

.hwc-ping__hit { fill: transparent; }

.hwc-ping__wave {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6px;
  stroke-opacity: .45;
  transform-box: fill-box;
  transform-origin: center;
  animation: hwcPing 3.4s cubic-bezier(.2, .6, .35, 1) infinite;
}

.hwc-ping__wave--b { animation-delay: 1.7s; }

.hwc-ping.is-active .hwc-ping__wave {
  stroke-opacity: 1;
  animation-duration: 2.2s;
}

.hwc-ping.is-active .hwc-ping__wave--b { animation-delay: 1.1s; }

.hwc-ping__halo {
  fill: currentColor;
  fill-opacity: .1;
  transition: fill-opacity var(--hwc-slow) var(--hwc-ease);
}

.hwc-ping.is-active .hwc-ping__halo { fill-opacity: .18; }

.hwc-ping__sel {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5px;
  opacity: 0;
  transition: opacity var(--hwc-fast) var(--hwc-ease);
}

/* The selection ring breathes, so the active marker stays legible without a
   third expanding wave competing with the pulse. */
.hwc-ping.is-active .hwc-ping__sel {
  opacity: .9;
  animation: hwcSel 2.4s var(--hwc-ease-soft) infinite;
}

@keyframes hwcSel {
  0%, 100% { opacity: .5; }
  50% { opacity: .95; }
}

.hwc-ping__dot {
  fill: currentColor;
  stroke: #151515;
  stroke-width: 1.5px;
  transition: r var(--hwc-slow) var(--hwc-ease);
}

.hwc-ping:hover .hwc-ping__dot { r: 7px; }
.hwc-ping.is-active .hwc-ping__dot { r: 7.5px; }
.hwc-ping:focus { outline: 0; }
.hwc-ping:focus-visible .hwc-ping__dot { r: 8px; stroke: #fff; }

.hwc-ping__label {
  font-family: var(--mono-font);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  fill: var(--gray-300);
  paint-order: stroke;
  stroke: #151515;
  stroke-width: 4px;
  opacity: 0;
  transition: opacity var(--hwc-fast) var(--hwc-ease);
}

.hwc-ping:hover .hwc-ping__label,
.hwc-ping:focus-visible .hwc-ping__label,
.hwc-ping.is-active .hwc-ping__label { opacity: 1; fill: #fff; }

/* Round the back of the globe. */
.hwc-ping.is-behind { opacity: 0; pointer-events: none; }

@keyframes hwcPing {
  0% { transform: scale(.55); opacity: .8; }
  70% { opacity: 0; }
  100% { transform: scale(3.6); opacity: 0; }
}

/* ==========================================================================
   Latency read-out
   ========================================================================== */

.hwc-lat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono-font);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--status-green);
}

.hwc-lat--good { color: var(--status-green); }
.hwc-lat--mid { color: var(--status-yellow); }
.hwc-lat--bad { color: #f43f5e; }

.hwc-lat i {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 6px currentColor;
}

.hwc-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  justify-content: center;
  padding: 16px 0 0;
  font-family: var(--mono-font);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gray-500);
}

.hwc-legend .hwc-lat { font-size: 9.5px; letter-spacing: .16em; }

/* ==========================================================================
   Panel
   ========================================================================== */

.hwc-side { padding: 0; }

.hwc-side__head {
  margin-bottom: 0;
  padding: 24px 24px 0;
}

.hwc-side__head h3 {
  margin: 0;
  font-family: var(--title-font);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-heading);
}

.hwc-side__head p {
  margin: 4px 0 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-muted);
}

.hwc-picks {
  display: grid;
  gap: 10px;
  padding: 20px 24px;
}

/* The picker card is the one surface here that reacts: it carries a real
   contour so the selected cluster is unambiguous. */
.hwc-pick {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  padding: 13px 15px;
  border: 2px solid rgba(255, 255, 255, .15);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition:
    border-color var(--hwc-slow) var(--hwc-ease),
    box-shadow var(--hwc-slow) var(--hwc-ease),
    transform var(--hwc-slow) var(--hwc-ease);
}

/* Lift, don't scale: scaling a card inside a card softens its own text. */
.hwc-pick:hover {
  border-color: var(--primary-color);
  box-shadow: var(--surf-bevel), var(--btn-lift-hi), 0 0 20px 0 rgba(var(--primary-color-rgb), .3);
  transform: translateY(-2px);
}

.hwc-pick:active { transform: translateY(0); }

.hwc-pick:focus-visible {
  outline: none;
  border-color: var(--primary-color);
  box-shadow: var(--surf-bevel), var(--btn-lift), var(--ring-acc-hi);
}

.hwc-pick.is-active {
  border-color: var(--primary-color);
  background-image:
    linear-gradient(180deg, rgba(var(--primary-color-rgb), .12), rgba(var(--primary-color-rgb), 0) 70%),
    linear-gradient(180deg, #1f1f1f, #1a1a1a);
  box-shadow: var(--surf-bevel), var(--btn-lift), 0 0 24px 0 rgba(var(--primary-color-rgb), .32);
}

.hwc-pick__row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  width: 100%;
}

.hwc-pick__code {
  font-family: var(--mono-font);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .05em;
  color: var(--gray-400);
}

.hwc-pick.is-active .hwc-pick__code { color: #c3c9ff; }

.hwc-pick__name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-heading);
}

.hwc-pick__lat { margin-left: auto; }

.hwc-pick__meta {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--gray-500);
}

/* ==========================================================================
   Spec table
   ========================================================================== */

.hwc-detail { padding: 0 24px 22px; }

/* Swapping cluster is a display swap, so it animates rather than transitions.
   The class is set by the script and cleared on animationend. */
.hwc-detail.is-entering { animation: hwcDetailIn .26s var(--hwc-ease) both; }

@keyframes hwcDetailIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

.hwc-specs { display: grid; }

.hwc-spec {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 11px 0;
}

.hwc-spec + .hwc-spec { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05); }

.hwc-spec__k {
  flex: none;
  width: 84px;
  font-family: var(--mono-font);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gray-500);
}

.hwc-spec__v {
  font-family: var(--mono-font);
  font-size: 13px;
  color: var(--text-heading);
}

.hwc-spec__v small {
  display: block;
  margin-top: 3px;
  font-family: var(--body-font);
  font-size: 12px;
  color: var(--gray-500);
}

.hwc-planned {
  margin: 0;
  padding: 14px 0 2px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* One line: status on the left, action on the right. The status label is kept
   short enough in every locale to make that fit at the panel's 360px. */
.hwc-detail__foot {
  flex-wrap: nowrap;
  justify-content: space-between;
  gap: var(--gap-sm);
  margin-top: 14px;
  margin-bottom: 0;
}

.hwc-detail__foot .btn {
  flex: none;
  margin-left: 0;
}

.hwc-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-muted);
}

.hwc-status i {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 6px currentColor;
}

.hwc-status--live { color: var(--status-green); }
.hwc-status--planned { color: var(--status-amber); }
.hwc-status--unavailable { color: var(--gray-500); }

/* ── Clusters this application cannot use ─────────────────────────────────
   Shown rather than hidden, so the map still reads as our whole footprint.
   Dimming alone would leave the state invisible to anyone who cannot compare
   two greys, so the status dot and its label carry the meaning and the opacity
   is only reinforcement. Kept focusable: it is information, not a dead button. */
.hwc-pick.is-unavailable,
.hwc-detail.is-unavailable {
  opacity: 0.55;
}

.hwc-pick.is-unavailable {
  cursor: default;
}

.hwc-pick.is-unavailable:hover {
  transform: none;
}

.hwc-pick.is-unavailable .hwc-pick__code {
  color: var(--gray-500);
}

.hwc-ping.is-unavailable {
  opacity: 0.4;
}

.hwc-unavailable {
  margin: 0;
  padding: 14px 0 2px;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text-muted);
}

/* ── Per-resource rates ───────────────────────────────────────────────────
   Only rendered where show_rates is passed (the landing). Figures come from
   the store per cluster, already tax-inclusive. */
.hwc-rates {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.08));
}

.hwc-rates__k {
  display: block;
  margin-bottom: 8px;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gray-500);
}

.hwc-rates__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 16px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 12.5px;
  color: var(--text-muted);
}

.hwc-rates__list li {
  min-width: 0;
}

.hwc-rates__list span {
  display: block;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary, #fff);
}

.hwc-rates__note {
  display: block;
  margin-top: 10px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--gray-500);
}

@media (max-width: 480px) {
  .hwc-rates__list { grid-template-columns: minmax(0, 1fr); }
}

.hwc-nodes { color: var(--gray-500); }

/* Filtering by country and active cluster. Gated on .hwc--interactive, which
   the script sets once it owns the panel, so the no-JS page keeps every
   cluster and every spec table on screen instead of collapsing to one. */
.hwc--interactive .hwc-pick[hidden],
.hwc--interactive .hwc-detail:not(.is-active) { display: none; }

/* Server-rendered fallback: the tables stack, so they need separating. */
.hwc:not(.hwc--interactive) .hwc-detail + .hwc-detail { margin-top: 8px; }

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 991px) {
  .hwc__grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 575px) {
  .hwc-side__head { padding: 20px 18px 0; }
  .hwc-picks { padding: 16px 18px; }
  .hwc-detail { padding: 0 18px 20px; }
  .hwc-spec { flex-direction: column; gap: 4px; }
  .hwc-spec__k { width: auto; }

  /* Too narrow for one line: the action drops under the status instead of
     squeezing the label. */
  .hwc-detail__foot {
    flex-wrap: wrap;
    row-gap: 10px;
  }

  .hwc-detail__foot .btn { margin-left: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .hwc--globe .hwc-globe { animation: none; }
  .hwc-ping__wave { animation: none; opacity: .4; }
  .hwc-ping,
  .hwc-pick,
  .hwc-ping__dot,
  .hwc-ping__halo,
  .hwc-ping__sel,
  .hwc-ping__label { transition: none; }
  .hwc-ping.is-active .hwc-ping__sel { animation: none; }
  .hwc-detail.is-entering { animation: none; }
  .hwc-pick:hover { transform: none; }
}
