/* ==========================================================================
   push-ads.php — page-specific additions
   ==========================================================================

   Loaded AFTER assets/text-ads/css/style.css, which is the shared ad-format
   design and is not edited from here. That sheet owns every section, token
   and breakpoint on this page; this one exists only for what the PUSH formats
   need and the text design has no equivalent for:

     TWO creatives, the carousel that rotates them, and a picker

   text-ads.php's hero holds one white ad card that scroll.js flies down into
   the S3 tablet. This page sells two formats and shows both AT ONCE — one
   centred and the other cut in half at each edge of the viewport, the row
   stepping one place every five seconds:

     classic — the notification the BROWSER draws, outside the page entirely,
               in the corner of the desktop: the advertiser's creative on top,
               then Chrome's own shelf with the mark, the title, the body, the
               sending host and the action button.
     inpage  — the ad the PAGE draws inside itself, with no opt-in: a round
               icon and a blue panel, measured off 7SearchPPC's own live
               widget.

   `data-push-format` on <main> is the FRAME's switch — the tablet's creative,
   the S3 heading and paragraph, and the picker's checked row, the same way
   banner-ads.php keys its six sizes off `data-size`. It no longer reaches the
   hero: the carousel shows both formats at every instant, so there is nothing
   there for it to choose between, and it is written in exactly two places —
   the flight's take-off and the picker. Which is the point of the rewrite: the
   frame holds whatever last landed in it until the reader says otherwise.

   MEASURED FROM THE CLIENT'S REFERENCE — the notification Chrome raises on
   https://v3services.7searchppc.in/push-ad/, captured at 371px wide:

       creative        371 x 216      (1.72 : 1)
       browser row      ~30           icon + "Google Chrome" + ... + close
       content row      ~90           64px thumb, title, body, host
       action button    ~40           full width, one shade up from the shelf
       shelf ground     #1F1F1F       title #FFF, body #C7C7C7, host #A0A0A0

   Everything below is a ratio of the popup's own width so the whole thing
   scales as one object, and every figure traces back to that capture.

   Scoped under `.push-ads-page` so including this sheet can never reach
   text-ads.php or any other format. Tokens (--c-*, --font-*) all come from the
   shared sheet; nothing here re-declares a colour or a face.

   text-ads' OWN flight is off, and is switched off the way banner-ads.php
   switches it off: by not rendering `.ta-hero__flyer` at all. initCardFlight()
   looks that element up first and returns when it is absent. This page runs a
   carousel and a flight of its own instead
   (assets/push-ads/js/hero-slider.js), which flies whichever card is centred
   and has a landing box per format.
   ========================================================================== */

.push-ads-page {
  /* THE POPUP'S WIDTH SETS EVERYTHING ELSE, including the hero's height — the
     notification is roughly as tall as it is wide, where the ad card it
     replaces was 308 x 200. 19.2vw is what the FOLD holds — 274px at 1440, for
     a popup ~320 tall. It was drawn at 21vw first and that is the number to
     resist: 300px wide is a better-looking notification and it put the
     headline at 694 and the CTA row at 864 on a 900-tall window, i.e. the
     page's primary action sat on the bottom edge of the screen. The popup is
     the hero's illustration, not its headline. */
  --pa-push-w: clamp(216px, 19.2vw, 330px);

  /* The creative's window, and it is the format's own shape: 360x240 IS the
     push notification image — the size Chrome asks an advertiser to upload,
     the size this page's S3 copy quotes, and the size the export in
     assets/push-ads/images is cut to. So the window is 3:2, the picture fills
     it exactly, nothing is cropped at any breakpoint, and `object-position`
     has nothing left to choose.

     It was 1.4:1 while the creative was a square export that any landscape
     window had to crop. That compromise is gone with the square. */
  --pa-shot-ar: 3 / 2;

  /* Chrome's own surfaces, sampled from the capture. */
  --pa-shelf:  #1F1F1F;   /* the notification's ground        (measured 31) */
  --pa-action: #3B3B3B;   /* the action button, one step up   (measured 59) */
  --pa-body:   #C7C7C7;   /* the notification's body copy               */
  --pa-host:   #A0A0A0;   /* the sending site, a step quieter           */

  /* ONE radius, all four corners: the desktop's own, 8px on the capture's 371.

     It was briefly two. The creative that shipped first was a square export
     with its corners BAKED IN as transparency, 24px on 362 — so the popup's
     top two had to match that curve exactly or the shelf's near-black ground
     showed through as a notch in each corner. The 360x240 export has square
     corners, so the popup picks its own radius again and picks Chrome's.

     A length, not a percentage: a percentage radius resolves against the box
     on each axis separately, and this box is not square, so `2.2%` would draw
     an ellipse. */
  --pa-push-r: calc(var(--pa-push-w) * 0.022);

  /* --- The hero carousel ------------------------------------------------

     CENTRE-TO-SIDE DISTANCE, and it is nearly a HALF viewport for a reason:
     at 50vw a side slot's centre line lands exactly on the page edge and the
     card is cut precisely in half. 49 sits just inside that, so a sliver of
     the next format always shows and the row reads as a row rather than as
     two stray cards.

     It has to hold for the SHORTER of the two creatives. The in-page ad is
     the wide one and gets cut generously; the notification is narrower, so at
     a smaller throw its whole scaled body fitted inside the margin and it sat
     fully visible in the corner — a third card rather than a hint of the next
     one. At 49vw the side slot's centre is past the content edge either way,
     so every card is cut and the figure stops depending on which format is in
     the slot.

     The 170px floor is for phones, where 49vw is under half the card: it
     holds the cut at roughly half a card down to ~320px. */
  --pa-throw: clamp(170px, 49vw, 980px);
  --pa-side-scale: 0.6;
  /* One duration for the move and the fade, so a card arriving and a card
     leaving are the same gesture. banner-ads' figure — a format change is a
     change of scene and wants to be read, not flicked. */
  --pa-glide: 900ms;
  --pa-ease: cubic-bezier(0.65, 0, 0.35, 1);
}

/* --- The hero notification popup ---------------------------------------- */

/* Replaces `.ta-hero__flyer` + `.ta-adcard` in the card slot. `.ta-hero__note`
   is its sibling and is positioned against `.ta-hero__card-wrap`, which is
   `width: fit-content` — so this element's width is what the note hangs off,
   exactly as the ad card's was. */
.push-ads-page .pa-push {
  position: relative;
  /* `.ta-hero__flyer`'s z-index, and load-bearing for the same reason: GSAP
     leaves a transform on the headline and the CTA row after their reveal, and
     a transformed element paints in the positioned layer — so at `z-index:
     auto` the copy, which comes LATER in the markup, draws straight through
     the popup. */
  z-index: 5;
  width: var(--pa-push-w);
  /* THE SHELF'S TYPE IS SIZED AGAINST THE POPUP, NOT THE VIEWPORT.

     Every figure in the capture is a ratio of its 371px width — a 14px title
     is 3.77% of it — and a notification only reads as a notification while
     those ratios hold. Sized in vw instead, the same 14px title sat on a 270px
     popup and the shelf came out a third too tall for its own creative. `cqw`
     is that ratio expressed directly, so the whole object scales as one and
     the breakpoints below only ever have to change ONE number: the width. */
  container-type: inline-size;
  overflow: hidden;
  border-radius: var(--pa-push-r);
  background-color: var(--pa-shelf);
  /* The notification is a desktop object, not part of the page's type system —
     it takes the OS's UI face, which is what makes it read as Chrome's chrome
     and not as another one of the hero's cards. */
  font-family: 'Segoe UI', system-ui, -apple-system, 'Inter', sans-serif;
  /* NO `will-change` HERE, and it was removed rather than forgotten. The
     crossfade used to translate and fade this element on a loop, so promoting
     it paid for itself. Nothing writes a card any more — the carousel writes
     `.pa-slide` and the flight writes `.pa-flyer`, both of which carry their
     own promotion — and there are six of these on the page now (four in the
     hero, two in the tablet). Six permanent compositor layers for an element
     that never moves is a cost with nothing on the other side of it. */
}

/* THE BLOOM IS `.ta-hero__card-wrap .ta-adcard`'s, verbatim.

   Same three stops, same alphas: the tight rim, the artboard's sigma-40 core,
   and the wide low-alpha wash that carries the halo past 100px. The hero is a
   near-black section and this is the light that keeps whatever sits in the
   card slot from lying flat on it, so a popup that brought a shadow of its own
   would read as a different page.

   NO SPIKE. An earlier pass ran these alphas through a multiplier that the
   script spiked on the frame the card landed, so it arrived overexposed and
   settled. That is gone at the client's call — the arrival is the slide and
   nothing else.

   `--pa-glow` is what is left of it, and it does the opposite job: the flight
   runs it from 1 to 0 over its first quarter, because this halo is the HERO's
   lighting and carried into the tablet it lit the inside of a screen from a
   notification. Authored HERE with a `1` fallback, so the hero renders at full
   bloom on the first paint, with no JS and under reduced motion. */
.push-ads-page .pa-push {
  box-shadow:
    0 0 14px rgba(150, 200, 255, calc(0.96 * var(--pa-glow, 1))),
    0 0 80px 9px rgba(13, 92, 255, var(--pa-glow, 1)),
    0 0 170px 12px rgba(13, 92, 255, calc(0.68 * var(--pa-glow, 1)));
}

/* --- The creative -------------------------------------------------------- */

.push-ads-page .pa-push__shot {
  display: block;
  width: 100%;
  aspect-ratio: var(--pa-shot-ar);
  /* `cover`, not `contain`: a letterboxed creative would show the shelf's
     ground through the bars and stop reading as one banner. */
  object-fit: cover;
  /* The window and the file are both 3:2, so this crops nothing. It is here as
     insurance for the day a creative arrives at some other ratio. */
  object-position: center;
}

/* --- Chrome's shelf ------------------------------------------------------ */

/* 3.8% of the popup's width, which is the capture's 14px on 371. Every inset
   below is a share of the same width so the shelf keeps its proportions when
   the popup scales. */
.push-ads-page .pa-push__shelf {
  padding: 3.2% 3.8% 3.8%;
  /* A HAIRLINE UNDER THE CREATIVE.

     The capture has no divider and does not need one: its creative is a bright
     blue-and-cyan game key art and the shelf under it is #1F1F1F, so the panels
     separate on their own. The placeholder creative is a NAVY night scene at
     roughly the shelf's own lightness, and without a line the two ran together
     into one dark slab with a picture floating in it.

     A `border-top` rather than a shadow or a pseudo-element: it is one line, it
     costs no extra box, and the 1px it adds to the popup's height is the only
     figure in this sheet that is not a ratio of the width — which is fine,
     because a hairline is a hairline at every size. */
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

/* The browser row — who is showing you this. */
.push-ads-page .pa-push__browser {
  display: flex;
  align-items: center;
  gap: 2.4%;
  margin-bottom: 3.4%;
  font-size: 3.7cqw;          /* capture 12px / 371 = 3.23; lifted for legibility */
  line-height: 1;
  color: var(--pa-body);
}

/* Chrome's mark, drawn rather than shipped as a file — at 4.6% of the popup it
   is a 12px glyph, and at that size it is three wedges and a blue eye. A conic
   gradient IS those wedges; a radial on top is the eye and its white ring.
   Nothing here is scaled artwork, so it stays crisp at every breakpoint. */
.push-ads-page .pa-push__chrome {
  flex: 0 0 auto;
  width: 4.6%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 50%,
      #4285F4 0 27%, #FFFFFF 27% 34%, transparent 35%),
    conic-gradient(from -35deg,
      #EA4335 0 118deg, #FBBC05 118deg 238deg, #34A853 238deg 360deg);
}

.push-ads-page .pa-push__browsername { margin-right: auto; }

/* The ... and the x. Decorative — a mock notification's controls do nothing —
   so they are one aria-hidden span, sized to the row rather than to a button's
   hit area, which is what the capture shows. */
.push-ads-page .pa-push__controls {
  display: flex;
  gap: 8%;
  min-width: 14%;
  justify-content: flex-end;
  color: var(--pa-host);
  letter-spacing: 0.02em;
}

/* The content row — thumb, then the ad itself. */
.push-ads-page .pa-push__row {
  display: flex;
  align-items: flex-start;
  gap: 3.4%;
}

/* 17.2% of the popup, which is the capture's 64px on 371. */
.push-ads-page .pa-push__thumb {
  flex: 0 0 17.2%;
  width: 17.2%;
  aspect-ratio: 1 / 1;
  border-radius: 4%;
  object-fit: cover;
}

.push-ads-page .pa-push__text { min-width: 0; }

.push-ads-page .pa-push__title {
  margin: 0 0 1.6%;
  font-size: 4.45cqw;         /* capture 14px / 371 = 3.77 */
  font-weight: 600;
  line-height: 1.25;
  color: #FFFFFF;
}

.push-ads-page .pa-push__desc {
  margin: 0 0 2.2%;
  font-size: 4.05cqw;         /* capture 13px / 371 = 3.50 */
  font-weight: 400;
  line-height: 1.32;
  color: var(--pa-body);
}

.push-ads-page .pa-push__host {
  display: block;
  font-size: 3.7cqw;          /* capture 12px / 371 = 3.23 */
  line-height: 1.2;
  color: var(--pa-host);
}

/* The action button. Full width and flush to the shelf's insets, the way
   Chrome draws it — and NOT a link: the whole popup is an illustration inside
   an `aria-hidden` figure, so a focusable control in it would be a tab stop
   that goes nowhere. */
.push-ads-page .pa-push__action {
  margin-top: 3.4%;
  padding: 3.1% 0;
  border-radius: 1.6%;
  background-color: var(--pa-action);
  font-size: 4.05cqw;         /* capture 13px / 371 = 3.50 */
  font-weight: 500;
  line-height: 1.2;
  color: #FFFFFF;
  text-align: center;
}

/* --- The hero's sideways clip -------------------------------------------- */

/* THE THROWN SIDE SLOTS MADE THE PAGE WIDER THAN THE PHONE.

   They sit up to a full viewport out (see the 767px block), and body's
   `overflow-x: hidden` does not stop mobile Chrome sizing its layout viewport
   to them: measured with a mobile emulation, the document came out 611px wide
   on a 320 phone, 738 on a 390 and 852 on a 768 tablet, and the whole page
   rendered zoomed out with an empty band down the right.

   `clip`, not `hidden`, same as banner-ads' hero: `hidden` would turn the
   hero into a scroll container and drag `overflow-y` to `auto`, cutting off
   the card that flies DOWN out of this section into the S3 tablet. `clip`
   trims only left and right, at the viewport's own edges — where nothing that
   should be seen ever goes, the flight included — and leaves the vertical
   axis visible. */
.push-ads-page .ta-hero { overflow-x: clip; }

/* --- The stage: both formats, one box ------------------------------------ */

/* THE HERO'S CARD SLOT IS A FIXED BOX AND THE CAROUSEL RUNS OVER IT.

   The two creatives are nothing like each other in shape — the notification is
   tall and narrow, the in-page ad is wide and short — so laid out in flow they
   would resize the hero every time the row stepped, walking the headline and
   the CTA row up and down the fold on a five-second clock. A stage sized once,
   with the slider absolutely filling it, holds the composition still and lets
   only the cards change.

   Its width is the WIDER of the two (the in-page card) and its height the
   TALLER (the notification), so neither is ever clipped. `.ta-hero__note` hangs
   off this box's right edge, so a stage that changed size would walk the
   handwritten note across the hero too — which is also why the thrown side
   slots are NOT allowed to grow it: they are absolutely positioned inside
   `.pa-slider`, which is `inset: 0` on this box and adds nothing to it.

   1.29 is the notification's own aspect, measured on the build: at 276 wide the
   card comes out 356 tall. Held as a ratio rather than a pixel figure so the
   stage tracks the card at every breakpoint. */
.push-ads-page .pa-stage {
  position: relative;
  /* `.ta-hero__flyer`'s z-index, and load-bearing for the same reason: GSAP
     leaves a transform on the headline and the CTA row after their reveal, and
     a transformed element paints in the positioned layer — so at `z-index:
     auto` the copy, which comes LATER in the markup, draws straight through
     the cards. */
  z-index: 5;
  width: var(--pa-inpage-w);
  height: calc(var(--pa-push-w) * 1.29);
}

/* --- The slider: three slots, four slides -------------------------------- */

/* THE ROW IS ABSOLUTE OVER THE STAGE, so the stage's box stays exactly what
   it was — the CENTRE slot. `.ta-hero__note` is positioned at
   `left: calc(100% + gap)` of `.ta-hero__card-wrap`, which is `fit-content`
   around this element, so a stage that grew to hold the thrown side slots
   would carry the handwritten note off the side of the hero with it. */
.push-ads-page .pa-slider {
  position: absolute;
  inset: 0;
  /* The hit area is the CENTRE box, not the whole hero: it is where the
     readable card is, and widening it would put an invisible drag surface
     over the headline and the CTA row sitting underneath. The side slots stay
     inert — they are cut in half by the page edge and there is nothing to
     grab. */
  cursor: grab;
  touch-action: pan-y;   /* horizontal is ours; the page still scrolls */
  -webkit-user-select: none;
          user-select: none;
}
.push-ads-page .pa-slider.is-dragging {
  cursor: grabbing;
  /* A drag has to answer faster than the automatic step. 900ms is right for a
     change of scene nobody asked for; under the hand it reads as lag, so the
     glide shortens for as long as the drag lasts and goes back afterwards. */
  --pa-glide: 340ms;
}

/* Re-arranging the row with the glide switched off. Held for one reflow when
   a format is chosen down at the tablet, so the hero is already built around
   that format before the reader scrolls back up into it — see paintInstant()
   in hero-slider.js. */
.push-ads-page .pa-slider.is-instant .pa-slide { transition: none; }

.push-ads-page .pa-slide {
  position: absolute;
  top: 50%;
  left: 50%;
  /* Parked state: any slide that is not in one of the three live slots sits
     centred, small and invisible, so whichever way the index moves a card
     grows out of the middle rather than jumping in from a corner. */
  transform: translate(-50%, -50%) scale(0.4);
  opacity: 0;
  /* The cards carry the artwork and nothing else needs to be clickable, so
     every pointer event lands on `.pa-slider` — one element, whichever format
     happens to be centred. */
  pointer-events: none;
  transition:
    transform var(--pa-glide) var(--pa-ease),
    opacity   var(--pa-glide) var(--pa-ease);
}

.push-ads-page .pa-slide.is-center {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
  z-index: 3;
}
.push-ads-page .pa-slide.is-prev {
  transform: translate(calc(-50% - var(--pa-throw)), -50%) scale(var(--pa-side-scale));
  opacity: 1;
  z-index: 2;
}
.push-ads-page .pa-slide.is-next {
  transform: translate(calc(-50% + var(--pa-throw)), -50%) scale(var(--pa-side-scale));
  opacity: 1;
  z-index: 2;
}

/* THE SIDE SLOTS STAY WHERE THEY ARE WHILE THE CENTRE ONE IS IN THE AIR.

   banner-ads faded them out here first and it read as a fault rather than as
   an intention: the instant the scroll starts, two cards the reader can still
   plainly see blink out, and on the way back up they blink in again a third of
   a screen later. Nothing is needed to freeze them — the carousel's clock is
   stopped for the whole flight (`flying` in hero-slider.js), and with no class
   changing there is nothing for the transition above to run. */

/* The carousel is decoration that moves on its own clock, which is exactly
   what this setting is about. The three slots still show; the row just stops
   advancing (hero-slider.js does not start its timer either) and nothing
   glides. */
@media (prefers-reduced-motion: reduce) {
  .push-ads-page .pa-slide { transition: none; }
}

/* Chrome and Safari start their own image-drag from a mousedown on an <img>,
   which steals the gesture and leaves `pointerup` unfired — the drag would
   stick on. The JS cancels `dragstart` as well; this stops it being offered. */
.push-ads-page .pa-slide img {
  -webkit-user-drag: none;
  user-select: none;
}

/* ONE FLYER PER CARD, AND THE NESTING IS LOAD-BEARING.

   `.pa-slide` above carries the CAROUSEL's transform — which of the three
   slots it is in — and `.pa-flyer` carries the FLIGHT's — how far down towards
   S3 the scroll has taken it. One element cannot hold both: they are written
   by different clocks and whichever wrote last would erase the other. Nested,
   the browser composes them. This is banner-ads' `.ba-slide` /
   `.ba-slide__inner` split.

   IN NORMAL FLOW inside its slide, with no offset of its own. The slide does
   the centring, with a translate the browser resolves against the flyer's real
   rendered height — which is what the margin pull this element used to carry
   could only approximate, since an absolutely positioned box has no height to
   halve and the figure had to be written out as a ratio of the width. The
   flyer's own transform therefore starts at identity and the flight owns it
   outright.

   `transform-origin: top left` because the flight is measured corner to
   corner: the delta puts this box's top-left on its tablet slot's, and the
   scale matches their widths, which is only true from that origin. */
.push-ads-page .pa-flyer {
  position: relative;
  transform-origin: top left;
  will-change: transform;
  /* Its own containment context, so each card's internals can be sized in
     `cqw` — 1% of the card — and the whole creative scales as one object at
     every placement and every breakpoint. */
  container-type: inline-size;
}
.push-ads-page .pa-flyer[data-format="classic"] { width: var(--pa-push-w); }
.push-ads-page .pa-flyer[data-format="inpage"]  { width: var(--pa-inpage-w); }

/* --- Where each format lands in the tablet ------------------------------- */

/* THE TABLET'S SCREEN IS A CONTAINER, and the slots are sized off it.

   Everything about a card is a ratio of its own width, and in the hero that
   width is a `clamp()` this sheet owns. Here it is a share of the screen the
   card lands on — so the screen is declared a container and the slots are
   sized in `cqw`, 1% of that screen.

   `container-type: inline-size` also applies `contain: layout`, which makes an
   element the containing block for absolutely positioned descendants — the
   screen is already `position: relative`, so the bars, the notch, the slots and
   the picker are all positioned against exactly the box they were before. */
.push-ads-page .ta-device__screen { container-type: inline-size; }

/* EACH FORMAT LANDS WHERE ITS OWN KIND OF AD ACTUALLY APPEARS.

   The two used to share the bottom-right corner. Only one of them belongs
   there:

     classic — bottom right, because that is where CHROME draws a notification.
     inpage  — TOP LEFT, because that is where the PAGE draws one. The
               reference puts it there
               (v3services.7searchppc.in/in-page-ad, over the site header at
               the very top left) and the paragraph beside this mock says it
               outright: "In-page push ads load instantly in the top-left
               corner of the publisher's website." The mock was contradicting
               its own caption.

   Same corner on every device, so the insets are the only thing the
   breakpoints touch. These boxes are also the FLIGHT's landing rects — the
   rule below is what fixes where, and at what size, each format arrives, and
   `data-anchor` in the markup tells the flight which EDGE of the card to bring
   down onto which edge of the box. */
.push-ads-page .pa-slot {
  position: absolute;
  /* Above the skeleton, which runs the full width underneath. */
  z-index: 3;
  container-type: inline-size;
}
.push-ads-page .pa-slot[data-format="classic"] {
  right: 2.6cqw;
  bottom: 3.2cqw;
  width: 28.05cqw;
}
.push-ads-page .pa-slot[data-format="inpage"] {
  left: 2.6cqw;
  top: 3.2cqw;
  width: 44cqw;
}

/* The slot's card is a static copy for the no-JS and reduced-motion cases.
   Once the flight is wired, the card visible in this corner is the one that
   flew down from the hero, so the static one would show through underneath it.
   Same trick, and the same reason, as text-ads' `.ta-has-flight` on the
   tablet's own ad card.

   `visibility`, and it HAS to be visibility. The slot has no height of its own
   — it is the card inside that gives it one, and that box is what the flight
   measures its landing on. `display: none` collapsed the slot to zero height,
   and since it is anchored by its BOTTOM edge, the target the flight solved
   for moved down by the whole height of a card: the notification flew out of
   the tablet and came to rest below it, half off the section.

   Nothing writes `visibility` inline here any more, which is what makes this
   safe. It was tried first, and lost — the cycle animated the static copies
   too back then, and `autoAlpha` writes `visibility` inline, which beats any
   selector. The cycle is scoped to `.pa-flyer .pa-card` now. */
.pa-has-flight .push-ads-page .pa-slot .pa-card { visibility: hidden; }

/* --- Which format is showing -------------------------------------------- */

/* THE ATTRIBUTE GOVERNS THE TABLET ONLY. IT NO LONGER TOUCHES THE HERO.

   Both flyers used to be in this rule, because the hero showed one format at a
   time and the other one had to be out of the layout. The carousel shows both
   at once — the centred format with the other one cut in half at each edge —
   so hiding either would empty two of the three slots.

   It still governs the TABLET, where one format at a time is the whole point,
   and `display: none` rather than opacity because a card faded to nothing is
   still hit-testable and still measurable, and the flight measures its landing
   box off exactly these elements. Nothing is on screen to cut when this turns
   over: the attribute is written at the flight's take-off, before the card has
   travelled its first pixel, and by the picker, which is a change the reader
   asked for. */
.push-ads-page[data-push-format="classic"] .pa-slot[data-format="inpage"],
.push-ads-page[data-push-format="inpage"]  .pa-slot[data-format="classic"] {
  display: none;
}

/* --- The in-page push ad ------------------------------------------------- */

/* MEASURED OFF THE LIVE WIDGET on https://v3services.7searchppc.in/in-page-ad/
   — 7SearchPPC's own in-page script — at the 375px width it renders at:

       card    375 x 95, 5px padding
       icon    72 x 68, radius 360px, 3px #2E8FFF border, 10px down
       panel   #2E8FFF, radius 20px, 15px padding, 5px to the left of the icon
       title   14px / 600, 8px beneath it
       body    14px / 300

   Every figure below is that number over 375, in `cqw` against the flyer or
   slot the card sits in. So the card is one object that scales, and the hero's
   copy and the tablet's are the same drawing at two sizes rather than two
   drawings that have to be kept in step. */
.push-ads-page {
  --pa-inpage-w: clamp(280px, 23.6vw, 400px);
  --pa-inpage-blue: #2E8FFF;
}

.push-ads-page .pa-inpage {
  display: flex;
  align-items: flex-start;
  width: 100%;
  padding: 1.33cqw;                 /* 5 / 375 */
  /* The reference's own face. This card is drawn by an ad script, not by the
     publisher's page, so it does not take the page's type — that is part of
     what makes it read as something injected rather than as another one of the
     hero's own panels. */
  font-family: Roboto, 'Inter', system-ui, sans-serif;
}

/* THE ICON IS AN ELLIPSE, NOT A CIRCLE. 72 wide by 68 tall with a 360px radius
   is what the widget draws, and squaring it up would be correcting the
   reference rather than matching it. */
.push-ads-page .pa-inpage__icon {
  flex: 0 0 auto;
  width: 19.2cqw;                   /* 72 / 375 */
  height: 18.13cqw;                 /* 68 / 375 */
  margin-top: 2.67cqw;              /* 10 / 375 */
  object-fit: cover;
  background-color: #FFFFFF;
  border: 0.8cqw solid var(--pa-inpage-blue);   /* 3 / 375 */
  border-radius: 50%;
  box-sizing: border-box;
}

.push-ads-page .pa-inpage__panel {
  flex: 1 1 auto;
  min-width: 0;
  margin-left: 1.33cqw;             /* 5 / 375 */
  padding: 4cqw;                    /* 15 / 375 */
  color: #FFFFFF;
  background-color: var(--pa-inpage-blue);
  border-radius: 5.33cqw;           /* 20 / 375 */
}

/* WHITE IS SET ON THE TWO LINES, NOT JUST INHERITED FROM THE PANEL. Both are
   <p>s, and the sitewide `p { color: #000 }` in assets/css/style.css matches
   them directly — a rule that matches the element beats a colour it would
   only have inherited, so the panel's white never reached the text and both
   lines rendered black on the blue. */
.push-ads-page .pa-inpage__title,
.push-ads-page .pa-inpage__desc { color: #FFFFFF; }

.push-ads-page .pa-inpage__title {
  margin: 0 0 2.13cqw;              /* 8 / 375 */
  font-size: 3.73cqw;               /* 14 / 375 */
  font-weight: 600;
  line-height: 1.25;
}

.push-ads-page .pa-inpage__desc {
  margin: 0;
  font-size: 3.73cqw;               /* 14 / 375 */
  font-weight: 300;
  line-height: 1.35;
}

/* NO HALO ON THIS CARD (removed on request). It used to carry the hero's
   three-stop blue bloom on the icon and the panel, the same one the classic
   notification wears. The in-page ad now sits flat in the hero as it does in
   the tablet; the notification keeps its glow (`.pa-push` above). */

/* --- S3: the copy that follows the creative ------------------------------ */

/* STACKED IN ONE GRID CELL. The two paragraphs are different lengths, and
   swapped in and out of flow the section would jump by the difference every
   time the cycle turned over. Sharing a cell makes the block as tall as the
   longer of the two and holds it there, so only the words change.

   `align-content: start` so the shorter of the two sits at the top of that cell
   rather than floating in the middle of it. */
.push-ads-page .pa-copies {
  display: grid;
  grid-template-areas: "copy";
  align-content: start;
}
.push-ads-page .pa-copy {
  grid-area: copy;
  transition: opacity 320ms ease;
}
/* `[hidden]` is the switch — the script writes it, and it takes the inactive
   block out of the reading order and off the tab ring as well as off screen.
   The `display` reset is what lets it keep its grid cell for the crossfade;
   `opacity` and `visibility` finish the job `hidden` starts. */
.push-ads-page .pa-copy[hidden] {
  display: block;
  opacity: 0;
  visibility: hidden;
}

/* The second heading was an <h3> while the two were stacked under one section.
   They are alternatives now, so both are <h2> — `.ta-what__title` already
   styles them identically, so nothing here restates the type. What goes is the
   top margin the stacked pair needed between them. */
.push-ads-page .pa-copy > .ta-what__title { margin-top: 0; }

/* --- S3: the article underneath ----------------------------------------- */

/* THE SKELETON RUNS FULL WIDTH.

   The shared sheet stops it at 62.42% because on text-ads the ad CARD occupies
   the right third of the screen and the bars fill the two thirds beside it.
   There is no ad column on this page — both formats are drawn OVER the article,
   not sold a slot inside it — so a skeleton that still stopped two thirds across
   left a third of the screen blank and read as a broken page rather than a
   loading one.

   90.7% is the same 4.65% inset the bars already have, mirrored on the right.
   The short variant is re-declared because it has to WIN the rule above it: the
   shared sheet's `.ta-device__bar--short` is one class where this is two, so
   without a scoped copy the short bars would stretch with the long ones.

   Scoped to 768 and up. Below that the shared sheet already runs the skeleton to
   88.3% for the phone mock, and these two would override it. */
@media (min-width: 768px) {
  .push-ads-page .ta-device__bar { width: 90.7%; }
  .push-ads-page .ta-device__bar--short { width: 31.62%; }
}

/* --- S3: the format picker ---------------------------------------------- */

/* banner-ads.php has one of these at the bottom-RIGHT of its tablet. This one is
   bottom-LEFT, because the right-hand corner is where the ad lands and a control
   under it would be covered.

   Everything in here is sized from the font-size below, so the control scales
   with the tablet instead of being pinned to a pixel size that only works at
   1920. */
.push-ads-page .pa-pick {
  position: absolute;
  left: 4%;
  bottom: 6%;
  z-index: 4;
  font-size: clamp(9px, 0.85vw, 16px);
}

.push-ads-page .pa-pick__btn,
.push-ads-page .pa-pick__opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.6em;
  width: 100%;
  font-family: var(--font-body);
  font-size: 1em;
  line-height: 1.35;
  text-align: left;
  white-space: nowrap;
}

/* The label is a one-cell grid holding both format names at once: the live one
   and a hidden copy of the other. The cell takes the width of the wider, so the
   pill stops resizing as the selection changes. `justify-items: start` keeps the
   live name left-aligned in that cell rather than centred in it. */
.push-ads-page .pa-pick__label {
  display: grid;
  grid-template-areas: "name";
  justify-items: start;
  min-width: 0;
}
.push-ads-page .pa-pick__label > * {
  grid-area: name;
  white-space: nowrap;
}
/* `visibility`, not `display: none` — a hidden box still occupies its grid cell
   and so still counts towards the width, which is the entire job. */
.push-ads-page .pa-pick__ghost {
  visibility: hidden;
  pointer-events: none;
}

.push-ads-page .pa-pick__btn {
  padding: 0.72em 1.05em;
  color: var(--c-blue);
  font-weight: 600;
  background-color: var(--c-surface);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color 180ms ease, background-color 180ms ease;
}
.push-ads-page .pa-pick__btn:hover { border-color: rgba(255, 255, 255, 0.4); }
.push-ads-page .pa-pick__btn:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
}
/* The pill is what the panel replaces, so it goes while the panel is up. */
.push-ads-page .pa-pick.is-open .pa-pick__btn { opacity: 0; }

/* The caret and the check are both drawn from two borders rather than shipped
   as files. At this size each is four pixels of line, and an exported glyph
   would be a request for something CSS already draws — and one that could not
   take `currentColor`, which both of these need (the selected row is blue, the
   rest are grey). */
.push-ads-page .pa-pick__caret {
  flex: none;
  width: 0.42em;
  height: 0.42em;
  margin-bottom: 0.15em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}

.push-ads-page .pa-pick__list {
  position: absolute;
  left: 0;
  /* Bottom-anchored to the pill's own bottom edge, so the list grows UPWARD and
     its last row lands where the pill was. Downward it would open past the
     bottom of the tablet's screen. */
  bottom: 0;
  min-width: 100%;
  margin: 0;
  padding: 0.5em 0;
  list-style: none;
  background-color: var(--c-surface);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: clamp(6px, 0.8vw, 14px);
  /* Closed. Kept in the layout rather than `display: none` so the panel can be
     measured and animated; `visibility` is what takes it off hit-testing. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.4em);
  transition: opacity 200ms ease, transform 200ms ease, visibility 200ms;
}
.push-ads-page .pa-pick.is-open .pa-pick__list {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.push-ads-page .pa-pick__opt {
  padding: 0.5em 1.05em;
  color: var(--c-grey);
  cursor: pointer;
  transition: color 140ms ease, background-color 140ms ease;
}
.push-ads-page .pa-pick__opt:hover,
.push-ads-page .pa-pick__opt.is-cursor {
  color: var(--c-white);
  background-color: rgba(255, 255, 255, 0.06);
}
.push-ads-page .pa-pick__opt[aria-selected="true"] {
  color: var(--c-blue);
  font-weight: 600;
}

/* Every row RESERVES the check's space so the labels do not shuffle sideways as
   the selection moves; only the selected one inks it. */
.push-ads-page .pa-pick__tick {
  flex: none;
  width: 0.44em;
  height: 0.8em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  opacity: 0;
}
.push-ads-page .pa-pick__opt[aria-selected="true"] .pa-pick__tick { opacity: 1; }

/* NO-JS / REDUCED MOTION.

   Nothing to park any more. The three live slots are rendered by PHP and the
   stylesheet places them, so a visitor with no GSAP, no JS at all, or a
   reduced-motion setting gets the composition the design asks for on the first
   paint — the classic notification centred, a cut in-page ad either side. It
   simply does not advance, and the picker at the tablet is how the reader sees
   the other format in the frame.

   The `.pa-card.is-static` rule that used to sit here is gone with the
   crossfade it belonged to: the cycle wrote `transform` on the cards and this
   was the release for it. The carousel writes `.pa-slide` and the flight writes
   `.pa-flyer`; nothing writes a card. */

@media (prefers-reduced-motion: reduce) {
  .push-ads-page .pa-copy,
  .push-ads-page .pa-pick__list { transition: none; }
}

/* --- Breakpoints --------------------------------------------------------- */

/* Below 1200 the shared sheet stacks the hero and gives the card slot 62.6% of
   the container. The stage is a fixed object with its own proportions, so it
   keeps a width of its own and the wrapper shrinks back to it — which brings the
   handwritten note along, since the note hangs off the wrapper's right edge and
   that is the layout its arrow was drawn for. */
@media (max-width: 1199px) {
  .push-ads-page {
    --pa-push-w: clamp(210px, 30vw, 300px);
    --pa-inpage-w: clamp(280px, 40vw, 400px);
  }
  .push-ads-page .ta-hero__card-wrap { width: fit-content; }
}

@media (max-width: 767px) {
  .push-ads-page {
    --pa-push-w: clamp(190px, 50vw, 260px);
    --pa-inpage-w: clamp(260px, 78vw, 340px);
    /* ONE CARD AT A TIME ON A PHONE (asked for directly). The desktop throw
       (49vw at 0.6) leaves half of each neighbour showing at the screen's
       edges, which at this width is a sliver of the other format cut
       mid-word on both sides. Thrown a full viewport at full size instead,
       the side slots sit off-screen, and a step reads as a slide: the centre
       card leaves to the left as the next one comes in from the right. */
    --pa-throw: 100vw;
    --pa-side-scale: 1;
  }
  /* Hidden as well as off-screen, so nothing peeks in however wide a card
     gets, and the incoming card fades up as it slides rather than arriving
     already solid at the edge. */
  .push-ads-page .pa-slide.is-prev,
  .push-ads-page .pa-slide.is-next { opacity: 0; }

  /* The tablet becomes a phone standing on end, so each ad takes the share of
     it that ad takes of a phone — 28% of a 572px-wide screen would be a 160px
     notification with a four-word title per line.

     THREE THINGS SHARE THIS SCREEN, and the picker stays in the bottom-left
     corner on every device — so the notification, which is the only one of the
     three that reaches into that corner, is the one sized to clear it.
     Measured at a 390 viewport, where the screen is 358 wide:

       picker         x 20-156   (left 5.7%, ~136 wide at 2.7vw)
       notification   x 173-338  (46cqw wide, right inset 5.7cqw)
       in-page ad     top-left, nowhere near either

     46cqw and not 62: at 62 the card was 222 wide, its left edge landed at 116,
     and it sat straight over the pill. It wins that overlap, too — the card in
     this corner is the one flown down from the hero, whose stage sits at
     z-index 30 in the ROOT stacking context, while the picker is sealed inside
     `.ta-device__screen`, which `container-type` makes a stacking context of
     its own. No z-index on the picker can reach past that, and lowering the
     flown card would bury it behind the tablet it is supposed to land in.
     Geometry is the only lever there is. */
  .push-ads-page .pa-slot[data-format="classic"] {
    right: 5.7cqw;
    bottom: 6cqw;
    width: 46cqw;
  }
  .push-ads-page .pa-slot[data-format="inpage"] {
    left: 5.7cqw;
    top: 6cqw;
    width: 88.3cqw;
  }

  /* BOTTOM LEFT, the same corner it holds on every other device — only the
     inset and the type size change here, to the phone's own 5.7% gutter. The
     picker does not move around between breakpoints; the notification beside it
     is what was resized to leave it the room (see the slot rules above).

     The panel still opens UPWARD from the pill, which it has space for: the
     in-page ad is at the top of this screen and the whole middle is clear. */
  .push-ads-page .pa-pick { left: 5.7%; bottom: 6cqw; font-size: 2.7vw; }
}

/* ==========================================================================
   S6 — the Classic / In-Page switch over the "How Do Push Ads Work" video
   ==========================================================================

   ONE CONTROL, THREE THINGS FOLLOW IT, AND NONE OF THEM IS WRITTEN PER
   ELEMENT. `data-how-format` on .pa-how is the whole state: which label is
   lit, which side the knob is parked on, and which wording step 2 shows are
   all selectors off that one attribute. how-toggle.js writes it and does not
   touch anything else on the section except the panel's video id and poster,
   which are not styling.

   THE LIME IS THE ACTIVE MARK. --c-accent (#E9FD45) is on the label of the
   format that is showing AND on the knob, which sits on that same side — so
   the colour and the position say the same thing twice, which is what makes
   a two-sided switch readable at a glance. The track stays neutral: filling
   it would put the accent on both sides at once and the knob would have
   nothing to distinguish it from.

   The switch is the SECTION's, not the page's. The hero and the tablet follow
   `data-push-format` on <main> and are deliberately left where they are; see
   the markup comment in push-ads.php. */
.push-ads-page .pa-how__switch {
  /* The track's geometry, in one place: everything below is derived from
     these so the switch keeps its proportions at every width. */
  --pa-sw-h:    clamp(28px, 1.98vw, 38px);
  --pa-sw-w:    calc(var(--pa-sw-h) * 1.85);
  --pa-sw-pad:  clamp(3px, 0.21vw, 4px);
  --pa-sw-knob: calc(var(--pa-sw-h) - 2 * var(--pa-sw-pad));

  display: flex;
  align-items: center;
  /* LEFT, under the heading, not centred on the section. The switch reads as
     part of the title block — it is what the title is asking about — so it
     starts on the same edge the heading does rather than floating on the
     section's centre line away from it. */
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: clamp(10px, 1.04vw, 20px);
  margin-top: clamp(16px, 1.46vw, 28px);
}

.push-ads-page .pa-how__label {
  font-family: var(--font-heading);
  font-size: var(--fs-20);
  font-weight: 500;
  line-height: 1.2;
  color: var(--c-light-gray);
  cursor: pointer;
  user-select: none;
  transition: color var(--dur-normal) var(--ease-out);
}
/* The labels are plain spans on purpose. The <button role="switch"> between
   them is the only control in the accessibility tree — a label that was also
   focusable would put three tab stops on a two-state choice — but a reader
   reaching for the words is reaching for the switch, so how-toggle.js listens
   for a click on them too. */
.push-ads-page .pa-how__label:hover { color: var(--c-white); }

.push-ads-page .pa-how[data-how-format="classic"] .pa-how__label[data-format="classic"],
.push-ads-page .pa-how[data-how-format="inpage"]  .pa-how__label[data-format="inpage"] {
  color: var(--c-accent);
}

.push-ads-page .pa-how__track {
  position: relative;
  flex: 0 0 auto;
  width: var(--pa-sw-w);
  height: var(--pa-sw-h);
  padding: 0;
  border: 1px solid var(--c-hairline);
  border-radius: 999px;
  background-color: rgba(255, 255, 255, 0.07);
  cursor: pointer;
  transition: border-color var(--dur-normal) var(--ease-out),
              background-color var(--dur-normal) var(--ease-out);
}
.push-ads-page .pa-how__track:hover {
  border-color: rgba(233, 253, 69, 0.55);
  background-color: rgba(255, 255, 255, 0.11);
}
.push-ads-page .pa-how__track:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
}

/* translate, not `left`: the knob is the only thing on this control that
   moves and a transform keeps that off the layout. */
.push-ads-page .pa-how__knob {
  position: absolute;
  top: 50%;
  left: var(--pa-sw-pad);
  width: var(--pa-sw-knob);
  height: var(--pa-sw-knob);
  border-radius: 50%;
  background-color: var(--c-accent);
  box-shadow: 0 2px 10px rgba(233, 253, 69, 0.45);
  translate: 0 -50%;
  transition: translate var(--dur-normal) var(--ease-out);
}
.push-ads-page .pa-how[data-how-format="inpage"] .pa-how__knob {
  translate: calc(var(--pa-sw-w) - var(--pa-sw-knob) - 2 * var(--pa-sw-pad)) -50%;
}

/* The switch's own name, for screen readers. The visual meaning is carried by
   the two labels either side of it, which a screen reader reads as text rather
   than as part of the control. */
.push-ads-page .pa-how__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* STEP 2's TWO WORDINGS. Both ship in the markup and the format picks one, so
   the rail's buttons — which scroll.js indexed once — are never rebuilt. */
.push-ads-page .pa-how__swap { display: none; }
.push-ads-page .pa-how[data-how-format="classic"] .pa-how__swap[data-format="classic"],
.push-ads-page .pa-how[data-how-format="inpage"]  .pa-how__swap[data-format="inpage"] {
  display: inline;
}

@media (prefers-reduced-motion: reduce) {
  .push-ads-page .pa-how__knob,
  .push-ads-page .pa-how__label,
  .push-ads-page .pa-how__track { transition: none; }
}
