/* ==========================================================
   CARD GEOMETRY
   The rank badge is already a hexagon; this carries that faceted
   language into the cards themselves.
   ========================================================== */
.standing-side,.team-col{
  --notch:10px;
  --rail:3px;
  border:none;border-radius:0;position:relative;
  background:linear-gradient(90deg, var(--side-rail) 0 var(--rail), var(--side-edge) var(--rail));
  clip-path:polygon(
    var(--notch) 0, 100% 0,
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    0 100%, 0 var(--notch));
}
.standing-side{padding:7px 9px;}
.team-col{padding:11px;}
.standing-side::after,.team-col::after{
  content:'';position:absolute;z-index:0;
  /* Held back by the rail's width on the left, by the 1px edge
     everywhere else. Back when this was a 6% wash the rail showed
     straight through it and still shows faintly at 60%, so the rail
     is drawn at its real width anyway. */
  inset:1px 1px 1px var(--rail);
  /* Mostly opaque. A 6% wash let the 45% edge layer underneath flood the
     interior with near-full-strength team colour and washed out the
     numbers; 60% is where it reads as a hint instead. */
  /* Flat fill first. color-mix is the only use of it in the project,
     and where it is not supported the whole gradient line is dropped -
     which would leave this layer with no background at all and put the
     thin grey numbers straight onto the photograph. */
  background:var(--side-fill);
  background:linear-gradient(180deg,
    color-mix(in srgb, #ffffff 7%, var(--side-fill)), var(--side-fill));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.09), inset 0 -1px 0 rgba(0,0,0,.3);
  clip-path:polygon(
    calc(var(--notch) - 1px) 0, 100% 0,
    100% calc(100% - var(--notch) + 1px), calc(100% - var(--notch) + 1px) 100%,
    0 100%, 0 calc(var(--notch) - 1px));
}
.standing-side > *,.team-col > *{position:relative;z-index:1;}

/* Edge pulse when a number changes. An inset shadow on the fill layer,
   not an outer glow: the card clips its own chamfered corners, so
   anything painted outside the shape is cut off. */
.standing-side.side-pulse::after{animation:side-pulse 1.1s ease-out;}
/* Starts and ends on the card's resting shadow, not on `none`, or the
   relief above would blink off for the length of the pulse. */
@keyframes side-pulse{
  0%{box-shadow:inset 0 1px 0 rgba(255,255,255,.09), inset 0 -1px 0 rgba(0,0,0,.3);}
  16%{box-shadow:inset 0 0 0 2px var(--side-glow), inset 0 0 16px -2px var(--side-glow);}
  100%{box-shadow:inset 0 1px 0 rgba(255,255,255,.09), inset 0 -1px 0 rgba(0,0,0,.3);}
}
.standing-match{
  border-radius:0;
  clip-path:polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}

/* First-place badge only. A 4.5s cycle whose sweep occupies the last
   28% of it. If this ever looks frantic the badges are being rebuilt and
   restarting the animation - the fault is upstream. */
.rank-1::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(115deg, transparent 38%, rgba(255,255,255,.8) 50%, transparent 62%);
  transform:translateX(-130%);
  animation:sheen 4.5s ease-in-out infinite;
}
@keyframes sheen{0%,72%{transform:translateX(-130%);}100%{transform:translateX(130%);}}

/* ==========================================================
   LIVE DATA
   ========================================================== */
@keyframes value-flash{
  0%{background:rgba(127,214,242,.5);box-shadow:0 0 14px rgba(127,214,242,.55);}
  100%{background:transparent;box-shadow:0 0 0 rgba(127,214,242,0);}
}
.value-changed{animation:value-flash 1.5s ease-out;border-radius:3px;padding:0 2px;margin:0 -2px;}
/* Fixed, and parked on <body>, because the cards are clipped by their
   own chamfer - a delta rising inside one would be sheared off at the
   card's top edge. */
.delta{
  position:fixed;z-index:45;transform:translateX(-50%);
  font-size:.64rem;font-weight:800;white-space:nowrap;pointer-events:none;
  animation:delta-rise 1.7s ease-out forwards;
}
.delta-up{color:var(--green-ink);}
.delta-down{color:var(--red-ink);}
@keyframes delta-rise{
  0%{opacity:0;transform:translate(-50%,6px);}
  22%{opacity:1;}
  100%{opacity:0;transform:translate(-50%,-14px);}
}
.standing-vp,.stat-value{position:relative;}

/* Skeleton, in place of a bare "Loading…" */
.skel-match{
  border:1px solid rgba(255,255,255,.05);padding:9px 10px;margin-bottom:10px;
  clip-path:polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}
.skel{
  border-radius:4px;
  background:linear-gradient(90deg, rgba(255,255,255,.04) 25%, rgba(127,214,242,.13) 37%, rgba(255,255,255,.04) 55%);
  background-size:280% 100%;
  animation:skel-sweep 1.5s ease-in-out infinite;
}
@keyframes skel-sweep{0%{background-position:120% 0;}100%{background-position:-40% 0;}}
.skel-title{height:9px;width:46px;margin-bottom:9px;}
.skel-row{height:34px;margin:5px 0;border-radius:8px;}
/* A team on a tier between weeks: a name and its guild list, and
   deliberately none of the furniture a standing carries. No chamfer, no
   team tint, no rank - the row has to read as a list of servers rather
   than as an order they finished in, because that order is not known. */
.standing-stale{
  display:flex;align-items:center;gap:7px;
  margin:4px 0;padding:7px 9px;
  font-size:.8rem;
  background:rgba(255,255,255,.035);
  border-left:3px solid rgba(154,164,178,.3);
  text-shadow:0 1px 2px rgba(0,0,0,.6);
}
.standing-stale .standing-side-name{color:#c3ccd8;font-weight:600;}
/* The one the check was about. Cyan on the rail only, the way every
   other "this is yours" mark on the page reads. */
.standing-stale.is-yours{border-left-color:var(--accent);background:rgba(127,214,242,.06);}
.standing-stale .pin-badge{margin:0 0 0 auto;}
/* Under the shimmer while a tier is between weeks. Quiet on purpose:
   nothing is wrong, the week simply has not been published yet. */
.standings-waiting{
  margin:7px 0 2px;text-align:center;
  font-size:.68rem;color:#8d97a6;font-style:italic;
}

/* Relink inside two hours: the banner starts breathing. The outline
   moves, not a halo behind it - the bar already has a cyan border and a
   lit cyan top edge, so a glow landed on more of the same. The spread is
   -2px because a larger negative one shrinks the glow back inside the
   shape. Quieter than the lockout below, which beats it on hue. */
.relink-banner.is-urgent{
  border-color:rgba(127,214,242,.32);
  animation:urgent-pulse 2.6s ease-in-out infinite;
}
@keyframes urgent-pulse{
  0%,100%{
    border-color:rgba(127,214,242,.30);
    box-shadow:
      inset 0 1px 0 rgba(200,240,255,.18),
      inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),
      0 16px 32px -16px rgba(0,0,0,.85),
      0 0 0 0 rgba(127,214,242,0);
  }
  50%{
    border-color:rgba(175,232,252,.72);
    box-shadow:
      inset 0 1px 0 rgba(200,240,255,.18),
      inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),
      0 16px 32px -16px rgba(0,0,0,.85),
      0 0 22px -2px rgba(127,214,242,.55);
  }
}
/* The region that lights has to be the one running out, which is what
   .is-now marks. This was every .time span, so the one with four days
   left lit up beside the one with minutes. */
.relink-banner.is-urgent .relink-stat:not(.relink-stat--primary) .relink-stat-value .time.is-now{
  color:var(--accent-bright);
  /* Lit, not just recoloured. #f2f6fa to #66f5ff is a hue step at
     almost the same lightness, so on its own it barely registers; the
     halo is what makes the number read as switched on. */
  text-shadow:0 1px 2px rgba(0,0,0,.6), 0 0 12px rgba(102,245,255,.55);
}
/* The label lifts with its number, or NA and EU read the same while one
   of them is the whole point. White, not the accent: in the accent it
   read as a hyperlink, which is what the accent means everywhere else. */
.relink-banner.is-urgent .relink-stat:not(.relink-stat--primary) .relink-stat-value .region.is-now{
  /* Weight, and only a nudge of tone. Every hue on this line is already
     somebody's - grey the other region label, white the other number,
     cyan the number two characters away - so this stays in its grey, one
     step brighter, and separates by weight instead. 400 against 600. */
  color:#a8b3c0;font-weight:600;
}
/* A rule under the word. At .66rem with .1em of tracking there is not
   enough letter to work with: a halo smudged it, a text-stroke closed
   its counters, a chip put a box round it. As text-decoration rather
   than a border it adds no height, so the bar does not jump. */
.relink-banner.is-urgent .relink-stat:not(.relink-stat--primary) .relink-stat-title{
  /* A tinted white, and neither of the two colours already spoken for:
     #f2f6fa is what the numbers wear and the accent is the lockout's
     title. This sits in the cyan family the bar is pulsing in, which is
     what says which alarm is running. The tracking opens up as well -
     widening small caps is a change of shape, and shape is what survives
     being seen out of the corner of the eye. */
  color:#bfe9f7;
  letter-spacing:.14em;
  text-decoration:underline;
  text-decoration-color:var(--accent-bright);
  text-decoration-thickness:1px;
  text-underline-offset:4px;
}



/* ---- Season lockout inside three days --------------------------- */
/* Amber, not cyan. Cyan here means something you can touch or something
   happening now, and a deadline is neither. Louder than the relink pulse
   on every axis, and that ordering is the feature: a relink costs you a
   week of not knowing who you fight, this costs a month on a different
   team from your guild. */
.relink-banner.is-lockout{
  border-color:rgba(255,183,101,.5);
  animation:lockout-pulse 2.1s ease-in-out infinite;
}
@keyframes lockout-pulse{
  0%,100%{
    border-color:rgba(255,183,101,.42);
    box-shadow:
      inset 0 1px 0 rgba(200,240,255,.18),
      inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),
      0 16px 32px -16px rgba(0,0,0,.85),
      0 0 0 0 rgba(255,183,101,0);
  }
  50%{
    border-color:rgba(255,206,150,.95);
    box-shadow:
      inset 0 1px 0 rgba(200,240,255,.18),
      inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),
      0 16px 32px -16px rgba(0,0,0,.85),
      0 0 36px 0 rgba(255,183,101,.66);
  }
}
.relink-banner.is-lockout .relink-stat--primary .relink-stat-title{
  color:var(--warn);
  display:inline-flex;align-items:center;gap:5px;
}
.relink-banner.is-lockout .relink-stat--primary .relink-stat-value{
  color:var(--warn);
  text-shadow:0 1px 2px rgba(0,0,0,.7), 0 0 16px rgba(255,183,101,.45);
}
/* What to do about it, which is the half a countdown cannot say. Sits
   under a hairline so it reads as a consequence of the number above
   rather than as a third stat beside it. */
.relink-alert{
  display:flex;align-items:center;justify-content:center;gap:7px;
  margin-top:7px;padding-top:7px;
  border-top:1px solid rgba(255,183,101,.16);
  color:#f5d9b4;font-size:.74rem;line-height:1.4;text-align:center;
}
.relink-alert svg{flex-shrink:0;color:var(--warn);}

/* ---- The game's crossed swords ---------------------------------- */
/* The file is a flat alpha silhouette, so it is a mask over
   currentColor rather than an <img>: one asset serves every state's
   colour at every size, and nothing has to be recut by hand. */
.swords-icon{
  display:inline-block;width:1em;height:1em;flex-shrink:0;
  vertical-align:-.17em;
  background-color:currentColor;
  -webkit-mask:url('../assets/icons/Event_Swords.webp') center/contain no-repeat;
  mask:url('../assets/icons/Event_Swords.webp') center/contain no-repeat;
}
.relink-alert .swords-icon{width:15px;height:15px;}
.relink-alert--relink .swords-icon{color:var(--accent-bright);}

/* ---- The last week of the season -------------------------------- */
/* Red, blue and green are the three teams, and this is the one state on
   the page that is about the teams changing - so it is the one that
   gets to wear them. Still, though, where the lockout moves: that is
   what keeps it underneath without having to be dimmed into nothing. */
.relink-banner .relink-week .relink-stat-title{
  color:#dfe7f0;letter-spacing:.15em;
  display:inline-flex;align-items:center;gap:6px;padding-bottom:5px;
  background:linear-gradient(90deg,var(--red),var(--blue),var(--green)) bottom/100% 2px no-repeat;
}
.relink-banner .relink-week .relink-stat-title .swords-icon{color:var(--accent-bright);}
.relink-banner .relink-week .relink-stat-value .time{color:#eef4fa;}
/* With the lockout up it keeps the mark and loses the volume. Removing
   it outright would take away the only notice that the final week has
   started; leaving it lit would split the eye with the one alarm that
   can still be acted on. */
.relink-banner.is-lockout .relink-week .relink-stat-title{
  color:#aab4c1;background:none;padding-bottom:0;
}
.relink-banner.is-lockout .relink-week .relink-stat-title .swords-icon{opacity:.45;}
.relink-banner.is-lockout .relink-week .relink-stat-value .time{color:#eaf0f6;}

/* ---- The relink itself ------------------------------------------ */
/* The loudest thing the page can do, and the only state here that is
   not one hue. It keeps the lockout's 2.1s heartbeat and changes colour
   on each beat - red, blue, green, the three teams being redrawn. So it
   reads as the same family rather than as a new widget, and nothing
   else on the page changes hue, so it cannot be mistaken for anything.
   It never has to out-shout the amber either: the lockout is over
   before this exists, and the two are never on screen together. */
.relink-banner.is-rebuild{
  padding:9px 26px;
  animation:rebuild-beat 6.3s ease-in-out infinite;
}
@keyframes rebuild-beat{
  0%,100%{
    border-color:rgba(225,92,92,.40);
    box-shadow:inset 0 1px 0 rgba(200,240,255,.18),inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),0 16px 32px -16px rgba(0,0,0,.85),0 0 0 0 rgba(225,92,92,0);
  }
  16.6%{
    border-color:rgba(255,150,148,.98);
    box-shadow:inset 0 1px 0 rgba(200,240,255,.18),inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),0 16px 32px -16px rgba(0,0,0,.85),0 0 40px 0 rgba(225,92,92,.72);
  }
  33.3%{
    border-color:rgba(91,143,240,.40);
    box-shadow:inset 0 1px 0 rgba(200,240,255,.18),inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),0 16px 32px -16px rgba(0,0,0,.85),0 0 0 0 rgba(91,143,240,0);
  }
  50%{
    border-color:rgba(160,196,255,.98);
    box-shadow:inset 0 1px 0 rgba(200,240,255,.18),inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),0 16px 32px -16px rgba(0,0,0,.85),0 0 40px 0 rgba(91,143,240,.76);
  }
  66.6%{
    border-color:rgba(76,175,125,.40);
    box-shadow:inset 0 1px 0 rgba(200,240,255,.18),inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),0 16px 32px -16px rgba(0,0,0,.85),0 0 0 0 rgba(76,175,125,0);
  }
  83.3%{
    border-color:rgba(140,232,186,.98);
    box-shadow:inset 0 1px 0 rgba(200,240,255,.18),inset 0 -1px 0 rgba(0,0,0,.4),
      0 2px 3px rgba(0,0,0,.4),0 16px 32px -16px rgba(0,0,0,.85),0 0 40px 0 rgba(76,175,125,.70);
  }
}
.relink-banner.is-rebuild .relink-stat{cursor:default;gap:4px;align-self:stretch;}
/* Serif, where the whole page is not. One hero moment a month earns a
   face of its own, and destoning is the point rather than an accident.
   The trailing letter-space is padded back on the left or the word
   drifts off centre by half a space. */
.relink-word{
  display:flex;align-items:center;justify-content:center;gap:18px;width:100%;
  font-family:Georgia,'Times New Roman',serif;
  font-size:1.16rem;font-weight:700;text-transform:uppercase;
}
.relink-word-text{
  color:#f7fbff;letter-spacing:.34em;padding-left:.34em;white-space:nowrap;
  text-shadow:0 1px 3px rgba(0,0,0,.9), 0 0 24px rgba(205,235,255,.5);
}
.relink-word .swords-icon{width:1.75em;height:1.75em;color:var(--accent-bright);}
.relink-rule{
  flex:1 1 auto;height:1px;
  background:linear-gradient(90deg,transparent,rgba(214,238,250,.7));
}
.relink-rule.is-right{background:linear-gradient(90deg,rgba(214,238,250,.7),transparent);}
.relink-banner.is-rebuild .relink-stat-value{font-size:1.1rem;font-weight:700;letter-spacing:.3px;}
.relink-banner.is-rebuild .relink-stat-value .time{color:#e9f0f7;text-shadow:0 1px 2px rgba(0,0,0,.75);}
.relink-banner.is-rebuild .relink-stat-value .region{color:#8d97a6;}
/* Cyan is the one colour not in the cycle, so the region inside two
   hours stands out by not belonging - and cyan already means "now"
   everywhere else on the page. Everything here is white or team
   coloured, so a brighter white had nowhere to go. */
.relink-banner.is-rebuild .time.is-now{
  color:var(--accent-bright);
  animation:rebuild-now 1.5s ease-in-out infinite;
}
.relink-banner.is-rebuild .region.is-now{color:#bfe9f7;font-weight:700;}
@keyframes rebuild-now{
  0%,100%{text-shadow:0 1px 2px rgba(0,0,0,.7), 0 0 8px rgba(102,245,255,.35);}
  50%{text-shadow:0 1px 2px rgba(0,0,0,.7), 0 0 26px rgba(102,245,255,1);}
}
.relink-banner.is-rebuild .relink-alert{
  margin-top:7px;padding-top:7px;
  border-top-color:rgba(200,220,245,.16);color:#dfe7f0;
}
@media (max-width:560px){
  .relink-word{font-size:1rem;gap:10px;}
  .relink-banner.is-rebuild .relink-stat-value{font-size:1.02rem;}
}

/* The relink's own. Quieter than the lockout's amber on every axis, the
   same ordering the two pulses already keep. */
.relink-alert--relink{
  border-top-color:rgba(127,214,242,.16);
  color:#cfe8f4;
  gap:5px;
}
/* Bigger than the lockout's triangle and closer to its text: this one
   is a silhouette rather than a symbol, and it needs the room to read
   as two blades instead of a cross. */
.relink-alert--relink svg{
  width:1.35em;height:1.35em;color:var(--accent-bright);
  filter:drop-shadow(0 0 6px rgba(102,245,255,.55));
}

/* ==========================================================
   TYPOGRAPHY
   ========================================================== */
/* Fixed-width digits: the countdown reflows every minute and the VP
   numbers change under it. Without this they visibly jitter. */
.stat-value,.relink-stat-value,.skirmish-bar-pct{
  font-variant-numeric:tabular-nums;
}
/* drop-shadow, not text-shadow: the title is gradient-clipped text,
   and text-shadow would paint a blur behind the transparent glyphs
   instead of tracing their edges. */
h1{filter:drop-shadow(0 1px 0 rgba(0,0,0,.9)) drop-shadow(0 0 16px rgba(127,214,242,.3));}

/* ==========================================================
   SIEGE IMPACT
   The crest, plus what a trebuchet round actually does: a shockwave,
   a second slower ring, and debris thrown outward. The blast itself,
   the crest breaking and the screen shake live in impact.css.
   ========================================================== */
.impact-ring{
  position:absolute;left:50%;top:50%;
  width:120px;height:120px;margin:-60px 0 0 -60px;border-radius:50%;
  border:2px solid rgba(140,224,255,.9);opacity:0;
}
.impact-overlay.play .impact-ring{animation:ring-out 1s cubic-bezier(.15,.85,.4,1) forwards;}
.impact-overlay.play .impact-ring--slow{
  animation-duration:1.35s;animation-delay:.12s;
  border-color:rgba(127,214,242,.5);border-width:1px;
}
@keyframes ring-out{
  0%{transform:scale(.25);opacity:0;}
  12%{opacity:.95;}
  100%{transform:scale(7);opacity:0;}
}
.impact-shard{
  position:absolute;left:50%;top:50%;width:4px;height:4px;border-radius:50%;
  background:#ffd9a3;box-shadow:0 0 8px 1px rgba(255,170,90,.8);
  opacity:0;animation:shard-fly .9s cubic-bezier(.12,.72,.3,1) forwards;
}
.impact-shard--cold{background:#bdefff;box-shadow:0 0 8px 1px rgba(127,214,242,.85);}
@keyframes shard-fly{
  0%{opacity:1;transform:translate3d(0,0,0) scale(1);}
  100%{opacity:0;transform:translate3d(var(--sx),var(--sy),0) scale(.3);}
}
