/* =====================================================================
   OTA Manager — exploded 3D workflow diagram
   Loaded only on ota-manager.php. Scoped entirely under .otaw so it cannot
   collide with anything in the site-wide css/style.css.

   Layout: one <ol> is the grid. Its rows sit in columns 1 and 3, and column
   2 is left empty for the diagram, which is overlaid on top of it. That way
   the eight stages stay a single list in DOM order — splitting them into a
   left and a right <ol> would read 8,7,6,5,1,2,3,4 to a screen reader, and
   display:contents on a list strips its semantics in several engines.

   IMPORTANT when editing .otaw-scene: it must not pick up `filter`,
   `opacity` below 1, or `overflow: hidden`. Each of those silently forces
   `transform-style` back to `flat`, which collapses the ring into a disc and
   loses all the depth. Effects of that kind belong on the nodes, which have
   no 3D children of their own.
   ===================================================================== */

.otaw {
  --otaw-ink: var(--navy);
  --otaw-muted: var(--muted);
  --otaw-line: var(--line);

  /* Ring geometry. The nodes' positions come from the template as unit
     vectors, so these are the only numbers that set the diagram's scale. */
  --otaw-size: 470px;   /* the square the scene occupies */
  --otaw-radius: 178px; /* hub centre to node centre */
  --otaw-node: 62px;
  --otaw-hub: 112px;

  --otaw-dur: 380ms;
  --otaw-persp: 1250px;

  /* Follows the site rhythm rather than setting its own, so the ?tune
     spacing panel moves this section with every other one. */
  padding: var(--section-pad) 0;
  background: #fff;
}


.otaw-grid { position: relative; }

/* ---------------------------------------------------------------------
   The eight rows. Column 2 is reserved, empty, for the diagram overlay.
   --------------------------------------------------------------------- */
.otaw-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr var(--otaw-size) 1fr;
  grid-template-rows: repeat(4, auto);
  align-items: center;
  column-gap: 30px;
  row-gap: 12px;
}

/* Clockwise from the top: stages 1-4 run down the right, 5-8 back up the
   left, so the reading order of the list matches the loop of the ring. */
.otaw-item:nth-child(1) { grid-area: 1 / 3; }
.otaw-item:nth-child(2) { grid-area: 2 / 3; }
.otaw-item:nth-child(3) { grid-area: 3 / 3; }
.otaw-item:nth-child(4) { grid-area: 4 / 3; }
.otaw-item:nth-child(5) { grid-area: 4 / 1; }
.otaw-item:nth-child(6) { grid-area: 3 / 1; }
.otaw-item:nth-child(7) { grid-area: 2 / 1; }
.otaw-item:nth-child(8) { grid-area: 1 / 1; }

.otaw-trigger {
  all: unset;
  box-sizing: border-box;
  display: flex;
  gap: 12px;
  width: 100%;
  padding: 14px 16px;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--otaw-dur) ease, box-shadow var(--otaw-dur) ease;
}
.otaw-trigger:hover,
.otaw-trigger:focus-visible,
.otaw-trigger.is-active { background: var(--c-soft); }
.otaw-trigger:focus-visible { outline: 2px solid var(--c); outline-offset: 2px; }

/* Rows on the left mirror, so their text runs toward the diagram. */
.otaw-item:nth-child(n + 5) .otaw-trigger { flex-direction: row-reverse; text-align: right; }

.otaw-num {
  flex: none;
  font: 700 11px/1 var(--sans);
  letter-spacing: .08em;
  color: var(--c);
  padding-top: 4px;
  opacity: .75;
  transition: opacity var(--otaw-dur) ease;
}
.otaw-trigger.is-active .otaw-num { opacity: 1; }

.otaw-copy { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.otaw-title {
  font: 400 19px/1.25 var(--serif);
  color: var(--otaw-ink);
  transition: color var(--otaw-dur) ease;
}
.otaw-trigger.is-active .otaw-title { color: var(--c); }
.otaw-body { font-size: 13px; line-height: 1.55; color: var(--otaw-muted); }

/* ---------------------------------------------------------------------
   The diagram, overlaid on the reserved middle column.
   --------------------------------------------------------------------- */
.otaw-stage {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  perspective: var(--otaw-persp);
  /* The overlay spans the whole grid, so it must not swallow hovers meant
     for the rows underneath it — only the scene itself takes pointer input. */
  pointer-events: none;
}

.otaw-scene {
  position: relative;
  width: var(--otaw-size);
  height: var(--otaw-size);
  transform-style: preserve-3d;
  /* --otaw-rx/ry come from the pointer (js/ota-workflow.js). They default to
     a slight resting tilt so the ring still reads as 3D with no JS at all. */
  transform: rotateX(var(--otaw-rx, 6deg)) rotateY(var(--otaw-ry, -8deg));
  transition: transform 220ms ease-out;
  pointer-events: auto;
}

/* Dashed spoke from the hub out to each node, drawn at that node's depth so
   it travels with it rather than lying flat underneath. */
.otaw-spoke {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--otaw-radius) - var(--otaw-hub) / 2 - var(--otaw-node) / 2 - 22px);
  height: 0;
  border-top: 1px dashed var(--otaw-line);
  transform-origin: 0 0;
  transform: translateZ(var(--z)) rotate(var(--a)) translateX(calc(var(--otaw-hub) / 2 + 11px));
  transition: border-color var(--otaw-dur) ease, opacity var(--otaw-dur) ease;
}
.otaw-spoke.is-active { border-top-color: var(--c); border-top-style: solid; }

.otaw-hub {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--otaw-hub);
  height: var(--otaw-hub);
  margin: calc(var(--otaw-hub) / -2);
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--otaw-ink);
  color: #fff;
  box-shadow: 0 18px 36px rgba(11, 35, 64, .22);
}
.otaw-hub-label {
  font: 600 13px/1.3 var(--sans);
  letter-spacing: .03em;
  text-align: center;
}

.otaw-node {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--otaw-node);
  height: var(--otaw-node);
  /* Centred by margin rather than a translate, so the transform below stays
     purely the ring placement and is easy to reason about. */
  margin: calc(var(--otaw-node) / -2);
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--c);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 10px 22px rgba(11, 35, 64, .18);
  transform: translate3d(calc(var(--ux) * var(--otaw-radius)),
                         calc(var(--uy) * var(--otaw-radius)),
                         var(--z));
  transition: transform var(--otaw-dur) ease, box-shadow var(--otaw-dur) ease, opacity var(--otaw-dur) ease;
}
.otaw-node svg { pointer-events: none; }

/* While any pair is engaged, the rest of the ring recedes. */
.otaw-scene.is-hovering .otaw-node:not(.is-active) { opacity: .32; }
.otaw-scene.is-hovering .otaw-spoke:not(.is-active) { opacity: .35; }

.otaw-node.is-active {
  transform: translate3d(calc(var(--ux) * var(--otaw-radius)),
                         calc(var(--uy) * var(--otaw-radius)),
                         calc(var(--z) + 58px));
  box-shadow: 0 22px 44px rgba(11, 35, 64, .3);
}

/* ---------------------------------------------------------------------
   Reduced motion — keep the depth, drop the movement. The pointer parallax
   is not attached at all in that case (see js/ota-workflow.js).
   --------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .otaw-scene { transition: none; }
  .otaw-node { transition: opacity 120ms linear, box-shadow 120ms linear; }
  .otaw-node.is-active { transform: translate3d(calc(var(--ux) * var(--otaw-radius)), calc(var(--uy) * var(--otaw-radius)), var(--z)); }
  .otaw-trigger, .otaw-spoke, .otaw-num, .otaw-title { transition-duration: 1ms; }
}

/* ---------------------------------------------------------------------
   Responsive
   --------------------------------------------------------------------- */
@media (max-width: 1180px) {
  .otaw { --otaw-size: 400px; --otaw-radius: 152px; --otaw-node: 56px; --otaw-hub: 96px; }
  .otaw-list { column-gap: 18px; }
  .otaw-title { font-size: 17px; }
  .otaw-body { font-size: 12.5px; }
}

@media (max-width: 1080px) {
  /* A ring with eight labelled spokes needs width it does not have here, and
     stacked above the rows it would just be a tall decorative block pushing
     the content down. The list already carries every stage's title and
     description — which is why the diagram is aria-hidden — so it goes. */
  .otaw-stage { display: none; }
  .otaw-list {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    row-gap: 4px;
  }
  .otaw-item:nth-child(n) { grid-area: auto; }
  .otaw-item:nth-child(n + 5) .otaw-trigger { flex-direction: row; text-align: left; }
  .otaw-trigger { padding: 14px 12px; }
}

@media (max-width: 640px) {
  .otaw { padding: 66px 0 72px; }
  .otaw-title { font-size: 18px; }
  .otaw-body { font-size: 13px; }
}

/* =====================================================================
   Page furniture for ota-manager.php
   Kept in this file rather than style.css because every rule here is
   scoped to this page — .platform and .detail-card are both shared
   components, and the site-wide versions must keep their own behaviour.
   ===================================================================== */

/* Shown until a logo file exists for that channel — see $logoFile in
   ota-manager.php. Deliberately a plain wordmark, not an imitation of the
   brand's own mark. */
.logo-marquee .platform--wordmark { font-size: 15px; letter-spacing: .01em; }


/* --- Core Management cards ------------------------------------------
   A square card holding its illustration inside a 10px frame, with the
   copy laid over the bottom. On hover the image swings out past the card
   edge — so the card is deliberately NOT clipped, and the hovered one is
   raised above its neighbours so the escaping corner draws over them
   rather than sliding underneath.
   -------------------------------------------------------------------- */
.otacards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px;
  align-items: start;
}

.otacard {
  position: relative;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: visible; /* required: the image leaves the box on hover */
  background: #fff;
  box-shadow: 0 10px 30px rgba(23, 53, 84, .05);
  isolation: isolate;
  transition: box-shadow .25s ease;
}
/* Raised only while hovered, so an escaping corner is never cut off by
   the card sitting next to it. */
.otacard:hover { z-index: 3; box-shadow: 0 18px 44px rgba(23, 53, 84, .12); }

/* The 10px frame between the card border and the artwork. */
.otacard-media { position: absolute; inset: 10px; z-index: 1; }

.otacard-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 6px;
  /* No overscan at rest: nothing is clipping the image any more, so the
     scale that used to hide its edges would only shrink the frame. */
  transform: translate3d(0, 0, 0) rotate(0deg) scale(1);
  transform-origin: center center;
  transition: transform .32s cubic-bezier(.2, .75, .2, 1), box-shadow .32s ease;
  will-change: transform;
  user-select: none;
  pointer-events: none;
}
.otacard:hover .otacard-image { box-shadow: 0 16px 36px rgba(23, 53, 84, .18); }

/* The illustrations are pale and their lower halves vary, so the copy gets
   a white scrim rather than relying on the artwork underneath staying
   light enough — it also covers the card's own background once the image
   has swung away from the bottom corner. */
.otacard-copy {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: 64px 24px 24px;
  border-radius: 0 0 10px 10px;
  background: linear-gradient(to top,
    #fff 0%,
    rgba(255, 255, 255, .96) 42%,
    rgba(255, 255, 255, .82) 66%,
    rgba(255, 255, 255, 0) 100%);
}

.otacard-title {
  margin: 0 0 6px;
  font: 400 clamp(24px, 1.9vw, 31px)/1.05 var(--serif);
  letter-spacing: -.025em;
  color: var(--teal);
  text-shadow: 0 0 0 rgba(11, 35, 64, 0);
  transition: text-shadow .28s ease;
}
/* Lifts the title off the artwork on hover, when the image behind it is
   also moving — the shadow is what keeps it reading as a fixed label
   rather than part of the picture. */
.otacard:hover .otacard-title { text-shadow: 0 3px 14px rgba(11, 35, 64, .28); }
.otacard-text { margin: 0; color: var(--muted); font-size: 14.5px; line-height: 1.5; }

@media (prefers-reduced-motion: reduce) {
  .otacard-image { transition: none; }
  /* The shadow still appears on hover, it just stops easing in. */
  .otacard-title { transition-duration: 1ms; }
}

@media (max-width: 980px) {
  .otacards { grid-template-columns: 1fr; }
  .otacard { max-width: 460px; }
}

/* The card images leave their cards on hover, at every width. On a narrow
   screen the card nearly fills the viewport, so a swung-out corner reached
   about 15px past the edge and widened the whole document.

   This contains it at the section instead of the card: the image is still
   free to swing over the container's gutter — which is the whole point —
   and is only cut at the viewport edge, where it would otherwise have
   produced a horizontal scrollbar.

   clip, not hidden: `hidden` makes this a scroll container, which breaks
   position:sticky for anything inside and lets stray scripts scroll it.
   `clip` also leaves the vertical axis genuinely visible, so the image can
   still swing above and below the card. */
.otacards-section { overflow-x: clip; }

/* --- Channel marquee --------------------------------------------------
   One box for every logo (120x32) rather than one height: the brands are
   wildly different shapes — Booking.com is 5:1, Agoda nearly square — and
   matching only their heights would leave the wide ones dominating the row.
   Fitting each inside the same box is what makes them read as equal.

   The track holds two identical copies and travels exactly half its width,
   so the moment it snaps back is the moment copy two sits where copy one
   began. Hover or keyboard focus pauses it; movement a visitor cannot stop
   is a nuisance when they are trying to look at something. */
.logo-marquee {
  position: relative;
  overflow: hidden;
  /* Fades the two ends so logos enter and leave instead of being clipped. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.logo-track {
  display: flex;
  width: max-content;
  animation: logo-marquee 34s linear infinite;
}
.logo-marquee:hover .logo-track,
.logo-marquee:focus-within .logo-track { animation-play-state: paused; }

.logo-set { display: flex; gap: 18px; padding-right: 18px; }

.logo-marquee .platform {
  flex: none;
  width: 190px;
  display: grid;
  place-items: center;
  min-height: 84px;
  padding: 18px;
  background: #fff;
  transition: border-color 220ms ease, box-shadow 220ms ease;
}
.logo-marquee .platform:hover { border-color: #cfe6dd; box-shadow: 0 10px 24px rgba(11, 35, 64, .07); }
.logo-marquee .platform img {
  max-height: 32px;
  max-width: 120px;
  width: auto;
  height: auto;
  object-fit: contain;
}

@keyframes logo-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* Reduced motion gets the old grid back: the second copy is hidden so
   nothing is announced or shown twice. */
@media (prefers-reduced-motion: reduce) {
  .logo-track { animation: none; flex-wrap: wrap; width: auto; justify-content: center; }
  .logo-set:last-child { display: none; }
  .logo-set { flex-wrap: wrap; justify-content: center; padding-right: 0; }
  .logo-marquee { -webkit-mask-image: none; mask-image: none; }
}
