/* ───────────────────────────────────────────────────────────────
   PARANOID AND READY — the Action Plan ticker

   Loaded by the homepage and by every scenario deck: the two page types that
   run as full-screen sections and have a fixed wordmark and burger in the
   corners. Written once here rather than twice, because a strip defined in
   two stylesheets is a strip that disagrees with itself within a month —
   the same argument tools/footer.js makes at the top of itself.

   What the host stylesheet has to declare, because the numbers differ per
   page type and this file cannot know them:

     --mark-w        how wide the wordmark is, so the strip starts after it
     --burger-w      how wide the burger is, so it stops before it
     --ticker-band   how much height a section gives up to make room, which
                     is 0 wherever the strip fits beside the chrome
     --safe-t        the notch inset, from base.css or the page's own :root

   Visibility is the host's too: .show goes on from the second screen down,
   set by whichever observer that page already runs.
   ─────────────────────────────────────────────────────────────── */

/* ── The Action Plan ticker ─────────────────────────────────────
   The one thing on the site being sold used to be half of section 06, which
   put it in front of the reader on one screen out of seven. As a strip above
   the deck it is on all of them and costs the deck no room, because it is
   fixed and never enters the flow.

   Inset from both ends rather than run across the width: the wordmark holds
   the left corner and the burger the right, and a full-width bar would be
   drawn straight over both. The two widths are named because this rule has
   to know how much room they take, and they are the one pair of numbers here
   that is measured off the chrome rather than chosen.

   A solid ground rather than a shadow. Red on bone and red on void both
   read, but the strip crosses the hero photograph as well, and 11px of red
   over a photograph does not. The ground flips with the chrome. */
.plan-ticker {
  position: fixed;
  z-index: 33;
  /* The strip is a <button>, and a button that is not reset carries the
     browser's own 2px outset border — a raised grey frame around the whole
     thing. base.css resets every button on the pages that load it and the
     homepage carries its own copy of that reset; scenario.css does not, so
     the strip arrived there framed. Reset here instead of there: a component
     that only looks right on a page that happens to have reset buttons for
     it is a component with a dependency nobody wrote down. */
  border: 0;
  font: inherit;
  /* Struck off the wordmark's own offset rather than the burger's, and
     pulled back by half the difference in height, so the strip's middle
     lands on the wordmark's middle: the two read as one line across the top
     rather than as two things that happen to be near each other. The
     wordmark is 13px of 10px mono; this is 24px tall. */
  top: calc(clamp(16px, 3vh, 30px) + var(--safe-t) - 6px);
  left: calc(var(--gutter) + var(--mark-w) + clamp(18px, 2vw, 40px));
  right: calc(var(--gutter) + var(--burger-w) + clamp(18px, 2vw, 40px));
  height: 24px;
  display: flex;
  align-items: center;
  overflow: hidden;
  padding: 0;
  background: transparent;
  cursor: pointer;
  /* Off on the cover and on from the second panel down, the rule the
     wordmark follows. Both are switched together in the deck observer. */
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.plan-ticker.show { opacity: 1; pointer-events: auto; }

/* The close button is built by js/plan-bar.js on every page that carries
   the strip, at every width, because the script does not know the width
   and should not have to. Every rule that shapes it lives in the phone
   block below, so above that breakpoint it had no rules at all and a
   <button> fell back to inline-block in normal flow: a stray 13x21 cross
   sitting under the footer on every desktop page. Hidden by default, and
   the phone block turns it on with the bar.

   Declared here rather than in the media query so it is the base state,
   which is what the script can rely on before the first measurement. */
.plan-bar-close { display: none; }

/* The bar-only spans. The strip shows the marquee, or the still line when
   motion is off; it never shows these three. */
.plan-ticker-name,
.plan-ticker-sub,
.plan-ticker-cta { display: none; }

/* No ground of its own: body::after paints the whole row, and it flips. */

.plan-ticker-track {
  display: flex;
  flex: none;
  align-items: center;
  white-space: nowrap;
  /* Six identical runs, shifted by three. The loop is seamless as long as
     what it shifts by is at least as wide as the strip: three runs is about
     2500px, which covers every window the two-column layout runs in. */
  animation: plan-ticker 36s linear infinite;
  will-change: transform;
}

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

.plan-ticker-run,
.plan-ticker-still {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--signal);
}

/* Reading it is what precedes clicking it, and a line that will not hold
   still is hard to finish. */
.plan-ticker:hover .plan-ticker-track,
.plan-ticker:focus-visible .plan-ticker-track { animation-play-state: paused; }
.plan-ticker:focus-visible { outline: 1px solid var(--signal); outline-offset: 2px; }

/* The still label is the reduced-motion copy, and the marquee is the
   default. Only one of the two is ever in the box. */
.plan-ticker-still { display: none; }

/* The menu is the whole screen on a phone, and a strip riding over it is a
   strip with nothing to do with what is underneath. */
body:has(.burger[aria-expanded='true']) .plan-ticker { opacity: 0; pointer-events: none; }


@media (max-width: 860px) {
  .plan-ticker {
    /* Under the chrome by its whole box, not by the strip you can see. The
       wordmark's own target ends at about 50px here, and the ten pixels of
       padding below carry no ink but do carry the click: overlapping them
       would take the bottom of the wordmark away from the thumb, which is
       the trade this file spent a whole pass undoing. */
    top: calc(clamp(14px, 2.8vh, 28px) + var(--safe-t) + 34px);
    left: var(--gutter);
    right: var(--gutter);
    /* 44px to the thumb, 24px to the eye. The strip stays the small thing it
       is meant to be and the target underneath it is the size the rest of
       this file was just taken to; background-clip is what separates the
       two, painting the ground on the content box and leaving the padding
       transparent. The band above already reserves the room, so the extra
       twenty pixels are bought from space that belongs to nothing else. */
    height: 44px;
    padding-block: 10px;
    background-clip: content-box;
  }
}

@media (prefers-reduced-motion: reduce) {
  .plan-ticker-track { display: none; }
  .plan-ticker-still { display: block; }
  .plan-ticker { justify-content: center; }

}

/* ── On a phone the strip is a bar ──────────────────────────────
   A marquee is a desktop object. It works in the band beside a wordmark,
   where there is width to spare and the line has room to travel; at 375px
   it had neither, so it ran a sentence past a window a third of its length
   and every still frame of it showed a word cut in half. It also held 44px
   of the top of the screen for the whole visit, on the device with the
   least of it, and competed with the wordmark for the one row up there.

   So below 860px it moves to the foot of the screen and stops moving. Same
   element, same link, same href: this is the strip, rephrased, not a second
   thing to keep in step with it.

   A bar and not a dialog, deliberately. Google's intrusive-interstitial
   signal is about mobile popups that cover the main content, and a banner
   using a reasonable amount of screen space is explicitly outside it. This
   site earns its traffic in search, so the version that cannot be penalised
   is the version worth having. Nothing is ever covered: the page keeps its
   own bottom padding for the bar's height while it is up, set alongside the
   .plan-bar-on class on the root. */
@media (max-width: 860px) {
  .plan-ticker {
    /* Bottom, full width, and no longer struck off the wordmark's offset. */
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    height: auto;
    display: grid;
    /* Two rows of text on the left, the call to action on the right, and a
       column of room for the close button that script puts over the end. */
    grid-template-columns: 1fr auto 44px;
    align-items: center;
    column-gap: clamp(10px, 3vw, 18px);
    row-gap: 2px;
    padding: 11px var(--gutter);
    padding-bottom: calc(11px + var(--safe-b, 0px));
    background: var(--void, #0C0C0C);
    /* The same seam the footer uses, for the same reason: it says the thing
       above has ended without putting a box around the thing below. */
    border-top: 3px solid var(--signal, #E8321E);
    background-clip: border-box;
    /* Up from under the edge rather than fading in on the spot. */
    transform: translateY(110%);
    transition: transform 0.42s cubic-bezier(.16,.84,.36,1), opacity 0.3s ease;
  }

  .plan-ticker.show { transform: translateY(0); }

  /* The marquee itself has nothing to do here. */
  .plan-ticker-track { display: none; }

  /* The imperative belongs to the strip, where it is the only thing there.
     On the bar it wraps mid-phrase in the room left by the button and the
     close, and it is redundant next to SEE IT, so the bar takes the name. */
  .plan-ticker-still { display: none; }

  .plan-ticker-name {
    display: block;
    grid-column: 1;
    grid-row: 1;
    font-family: 'Anton', 'Arial Narrow', Impact, sans-serif;
    font-size: 19px;
    font-weight: 400;
    letter-spacing: 0.02em;
    line-height: 1.05;
    text-transform: uppercase;
    color: var(--bone, #EFEBE4);
  }

  .plan-ticker-sub {
    display: block;
    grid-column: 1;
    grid-row: 2;
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.6px;
    text-transform: none;
    color: rgba(var(--rgb-bone), 0.6);
  }

  /* A span, not a button, because the whole bar is already the link and a
     button inside an anchor is not allowed. It only has to look like the
     target, and the target is the entire bar. */
  .plan-ticker-cta {
    display: inline-flex;
    align-items: center;
    grid-column: 2;
    grid-row: 1 / span 2;
    min-height: 40px;
    padding: 0 16px;
    background: var(--signal, #E8321E);
    color: var(--void, #0C0C0C);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 2px;
    white-space: nowrap;
  }

  /* Injected by inner.js as a sibling, so it is a real button outside the
     anchor. Placed over the third column rather than in it, because a grid
     item cannot be a child of the <a> beside it. */
  .plan-bar-close {
    position: fixed;
    right: 0;
    /* Sits on the bar's content row, above its safe-area padding. The bar
       is the link and this is not, so it has to be outside the anchor and
       therefore cannot be a grid item in it. The third grid column above
       reserves the 44px it lands on. */
    bottom: calc(var(--safe-b, 0px) + 9px);
    z-index: 34;
    width: 44px;
    height: 44px;
    display: none;
    align-items: center;
    justify-content: center;
    color: rgba(var(--rgb-bone), 0.65);
    font-size: 17px;
    line-height: 1;
    background: none;
    border: 0;
  }
  .plan-bar-close.show { display: flex; }

  /* The bar is fixed, so the foot of the page would otherwise sit under it.
     Given back on the root while the bar is up, which is also what makes the
     bar safe: nothing is covered, the page is simply that much longer. */
  .plan-bar-on body { padding-bottom: var(--plan-bar-h, 76px); }
}

/* The reduced-motion rule above swaps the track for the still line on every
   width. On a phone the still line is already the one showing, so all that
   is left to take off is the slide. */
@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .plan-ticker { transition: opacity 0.3s ease; transform: none; opacity: 0; }
  .plan-ticker.show { opacity: 1; }
}

/* ── The bar yields to the menu ─────────────────────────────────
   The menu panel is the whole screen and brings its own ground. The bar is
   fixed to the foot of that screen and the close button is fixed to the
   corner of it, so with the menu open the reader got the panel, a strip of
   Action Plan across the bottom of it, and a second X in the corner under
   the first. Two close buttons on one screen, and only one of them closes
   the thing in front of you.

   Hidden rather than dismissed: this is not the reader saying no to the
   offer, it is the offer standing out of the way, so it comes back when
   the menu does not. Driven off the burger's own state, the same hook
   base.css already uses to fade the wordmark out behind the panel. */
@media (max-width: 860px) {
  body:has(.burger[aria-expanded='true']) .plan-ticker {
    transform: translateY(110%);
    opacity: 0;
    pointer-events: none;
  }
  body:has(.burger[aria-expanded='true']) .plan-bar-close { display: none; }
}
