/* The cookie notice.
   Most sites open with a consent dialog. We have nothing to ask consent for, so
   this says as much and then removes itself.

   It drops in from two thirds up the viewport, bounces to a stop along the
   bottom edge, holds for seven seconds, then tips and falls off the screen. That
   is one keyframe timeline — nothing sequences it, and nothing has to clean up
   after it, because the last keyframe hides it.

   It never takes pointer events, so it cannot swallow a click on its way past. */

.banner{
  position:fixed;
  bottom:14px;
  /* Centred with auto margins rather than left:50%, which would cap the
     available width at half the viewport and wrap the line early. */
  left:0;
  right:0;
  margin-inline:auto;
  width:max-content;
  z-index:10000;          /* above the grain overlay */
  display:flex;
  align-items:center;
  gap:11px;
  /* Wide enough to hold the line without wrapping on a desktop viewport. */
  max-width:min(820px,calc(100vw - 24px));
  padding:11px 34px 11px 28px;   /* extra on the right to clear the close button */
  /* Corners stay square, the way every other edge on the site does. The
     softness comes from the ends fading out instead — so there is no edge to
     draw, and no shadow either, since a mask would clip one anyway. The top and
     bottom stay crisp, which is what keeps it reading as a bar.

     The fade is short on purpose: long enough to take the hard stop off the
     ends, short enough that it still reads as an edge rather than a smear. */
  background:rgba(15,42,67,.94);
  backdrop-filter:blur(10px);
  --fade:8px;
  --fade-y:5px;   /* shorter, because the bar is only about 45px tall */
  -webkit-mask-image:
    linear-gradient(90deg,transparent 0,#000 var(--fade),#000 calc(100% - var(--fade)),transparent 100%),
    linear-gradient(180deg,transparent 0,#000 var(--fade-y),#000 calc(100% - var(--fade-y)),transparent 100%);
  mask-image:
    linear-gradient(90deg,transparent 0,#000 var(--fade),#000 calc(100% - var(--fade)),transparent 100%),
    linear-gradient(180deg,transparent 0,#000 var(--fade-y),#000 calc(100% - var(--fade-y)),transparent 100%);
  /* Both gradients have to agree for a pixel to show, which is what rounds the
     falloff into the corners instead of crossing two independent fades. */
  -webkit-mask-composite:source-in;
  mask-composite:intersect;
  font-family:'Inter',system-ui,sans-serif;
  font-size:13.5px;
  line-height:1.45;
  color:#fff;
  visibility:hidden;
  pointer-events:none;
  transform:translateY(-66vh);
  will-change:transform;
}

/* Close. Sits in the top right corner, inside the padding the bar already has
   on that side, so it never overlaps the text. The banner takes no pointer
   events, so this asks for them back. */
.banner-close{
  position:absolute;
  top:5px;
  right:7px;
  width:22px;
  height:22px;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:0;
  border:0;
  background:none;
  color:var(--inv-soft,#B9CBD8);
  font-family:'Inter',system-ui,sans-serif;
  font-size:17px;
  line-height:1;
  cursor:pointer;
  pointer-events:auto;
  transition:color .15s,background .15s;
}
.banner-close:hover{color:#fff;background:rgba(255,255,255,.1)}
.banner-close:focus-visible{outline:2px solid var(--accent-l,#7FB2E8);outline-offset:1px}

/* The one live link in it, so anyone who wants the detail can reach it. The
   banner itself takes no pointer events, so the link asks for them back. */
.banner a{pointer-events:auto;color:#fff;text-underline-offset:3px;text-decoration-color:rgba(255,255,255,.45)}
.banner a:hover{text-decoration-color:currentColor}

.banner.on{animation:banner-drop 10.3s forwards}

/* Falls are eased in so they accelerate under gravity; rebounds are eased out
   so they run out of energy. Each bounce returns about a third of the last. */
@keyframes banner-drop{
  0%     {visibility:visible;transform:translateY(-66vh) rotate(0deg);animation-timing-function:cubic-bezier(.5,0,1,1)}
  7.3%   {transform:translateY(0) rotate(0deg);animation-timing-function:cubic-bezier(0,0,.5,1)}
  10.3%  {transform:translateY(-12vh) rotate(0deg);animation-timing-function:cubic-bezier(.5,0,1,1)}
  13.3%  {transform:translateY(0) rotate(0deg);animation-timing-function:cubic-bezier(0,0,.5,1)}
  15%    {transform:translateY(-4vh) rotate(0deg);animation-timing-function:cubic-bezier(.5,0,1,1)}
  16.8%  {transform:translateY(0) rotate(0deg);animation-timing-function:cubic-bezier(0,0,.5,1)}
  17.8%  {transform:translateY(-1.2vh) rotate(0deg);animation-timing-function:cubic-bezier(.5,0,1,1)}
  18.7%  {transform:translateY(0) rotate(0deg);animation-timing-function:cubic-bezier(0,0,.5,1)}
  19.3%  {transform:translateY(-.35vh) rotate(0deg);animation-timing-function:cubic-bezier(.5,0,1,1)}
  19.9%  {transform:translateY(0) rotate(0deg)}

  /* settled, and readable, for seven seconds from here */

  87.9%  {transform:translateY(0) rotate(0deg);animation-timing-function:ease-in}
  90.8%  {transform:translateY(2vh) rotate(3deg);animation-timing-function:cubic-bezier(.5,0,1,1)}
  99.9%  {visibility:visible}
  100%   {transform:translateY(120vh) rotate(14deg);visibility:hidden}
}

/* Travel on this scale is exactly what a vestibular trigger looks like, so the
   reduced-motion path keeps the notice and its timing, and drops the movement. */
@media(prefers-reduced-motion:reduce){
  .banner{transform:translateY(0)}
  .banner.on{animation:banner-fade 10.3s forwards}
  @keyframes banner-fade{
    0%    {visibility:visible;opacity:0}
    3%    {opacity:1}
    95%   {opacity:1}
    99.9% {visibility:visible}
    100%  {opacity:0;visibility:hidden}
  }
}

/* Narrow screens cannot hold the line either way, so the bar tightens up and
   wraps rather than running to the edges of the screen. */
@media(max-width:520px){
  .banner{padding:10px 30px 10px 18px;--fade:6px;font-size:12.5px}
}

@media print{.banner{display:none}}
