/* The decoration a campaign wears. Paired with /js/decorations.js, which
   builds the marks; everything about how they move lives here.

   The layer never takes a click: it sits over the content, and the content
   underneath is a link on the landing page. */

.decorated { position: relative; }

.decoration {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    /* Above the panel's own background, below its text. */
    z-index: 0;
    border-radius: inherit;
}

.decorated > *:not(.decoration) { position: relative; z-index: 1; }

.deco-mark {
    position: absolute;
    font-size: calc(1.1rem * var(--size, 1));
    line-height: 1;
    /* Emoji at small sizes on a dark panel read as noise at full strength. */
    opacity: 0.55;
    will-change: transform, opacity;
}

@keyframes deco-swing {
    from { transform: rotate(-15deg); }
    to   { transform: rotate(15deg); }
}

/* ----- drifting down --------------------------------------------------- */
.is-fall .deco-mark {
    top: -1.6em;
    animation: deco-fall 12s linear infinite;
}

/* --deco-drop is how far to fall, set from the host's measured height by
   decorate(). A percentage would not do it: a translate percentage is of the
   mark's own size, so every mark would drop about one snowflake and stop. */
@keyframes deco-fall {
    from { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 0; }
    12%  { opacity: 0.55; }
    88%  { opacity: 0.55; }
    to   { transform: translate3d(1.6em, var(--deco-drop, 22rem), 0) rotate(220deg);
           opacity: 0; }
}

/* ----- rising and bobbing ---------------------------------------------- */
.is-float .deco-mark {
    bottom: -1.6em;
    animation: deco-float 14s ease-in-out infinite;
}

@keyframes deco-float {
    from { transform: translate3d(0, 0, 0); opacity: 0; }
    15%  { opacity: 0.6; }
    85%  { opacity: 0.6; }
    to   { transform: translate3d(2.2em, calc(-1 * var(--deco-drop, 22rem)), 0);
           opacity: 0; }
}

/* ----- still, fading in and out ---------------------------------------- */
.is-twinkle .deco-mark {
    animation: deco-twinkle 5s ease-in-out infinite;
}

@keyframes deco-twinkle {
    0%, 100% { opacity: 0.18; transform: scale(0.78); }
    50%      { opacity: 0.95; transform: scale(1.15); }
}

/* ----- lined along the bottom, not moving ------------------------------ */
.is-rest .deco-mark {
    bottom: -0.1em;
    opacity: 0.4;
}

/* Somebody who asked for less motion gets the marks placed and left alone.
   The module already halves how many there are; this stops the rest. */
@media (prefers-reduced-motion: reduce) {
    .deco-mark { animation: none !important; opacity: 0.4; }
    .is-fall .deco-mark { top: 18%; }
    .is-float .deco-mark { bottom: 14%; }
}

/* ---------------------------------------------------------------------------
   Hovering the thing it is on.

   Two jobs. It is a bit of life on the landing strip and the archive cards --
   and on the Look preview it is the answer to "is this one doing anything?",
   because a third of the decorations deliberately do not move and a still
   panel reads as broken rather than as chosen.

   Every motion reacts, including `rest`, which gets the only movement it ever
   has. The inline duration decorate() sets has to be beaten with !important:
   an inline style outranks a stylesheet rule.
   ------------------------------------------------------------------------ */

.decorated:hover .deco-mark { opacity: 0.9; }

/* Strung marks swing wider and quicker, like something has been knocked. */
.decorated:hover .is-string .deco-mark {
    animation-name: deco-swing-big;
    animation-duration: 1.1s !important;
}

@keyframes deco-swing-big {
    from { transform: rotate(-22deg); }
    to   { transform: rotate(22deg); }
}

/* Falling and drifting marks hurry along. */
.decorated:hover .is-fall .deco-mark,
.decorated:hover .is-float .deco-mark {
    animation-duration: 3.2s !important;
}

/* Twinkling ones all come up together rather than at their own offsets. */
.decorated:hover .is-twinkle .deco-mark {
    animation-duration: 1.4s !important;
}

/* And the ones that never move get their only movement, which is what says
   they are there at all. */
.decorated:hover .is-rest .deco-mark {
    animation: deco-hop 0.85s ease-in-out infinite;
}

@keyframes deco-hop {
    0%, 100% { transform: translateY(0) rotate(0deg); }
    45%      { transform: translateY(-0.5em) rotate(-8deg); }
}

/* Somebody who asked for less motion still gets an answer to "is this doing
   anything?" -- they just get it without anything moving. */
@media (prefers-reduced-motion: reduce) {
    .decorated:hover .deco-mark {
        animation: none !important;
        opacity: 0.95;
        transform: none;
    }
}

/* ----- one in each corner, turned to face it --------------------------- */
/* A cobweb strung along the top edge like bunting is not what a cobweb does.
   These are placed rather than scattered, and each is rotated so the web's
   own corner points into the panel's. */
.is-corner .deco-mark {
    opacity: 0.4;
    transform-origin: 50% 50%;
}

.is-corner .deco-mark[data-corner="0"] { top: -0.42em; left: -0.45em; }
.is-corner .deco-mark[data-corner="1"] {
    top: -0.42em; right: -0.45em;
    transform: scaleX(-1);
}
.is-corner .deco-mark[data-corner="2"] {
    bottom: -0.42em; left: -0.45em;
    transform: scaleY(-1);
}
.is-corner .deco-mark[data-corner="3"] {
    bottom: -0.42em; right: -0.45em;
    transform: scale(-1, -1);
}

/* Hovering shivers them, the way a web does when something lands in it.
   Each corner keeps its own flip, so the shiver is added to it rather than
   replacing it. */
.decorated:hover .is-corner .deco-mark {
    animation: deco-shiver 0.5s ease-in-out infinite;
}

.decorated:hover .is-corner .deco-mark[data-corner="1"] { animation-name: deco-shiver-x; }
.decorated:hover .is-corner .deco-mark[data-corner="2"] { animation-name: deco-shiver-y; }
.decorated:hover .is-corner .deco-mark[data-corner="3"] { animation-name: deco-shiver-xy; }

@keyframes deco-shiver {
    0%, 100% { transform: scale(1) rotate(0deg); }
    50%      { transform: scale(1.08) rotate(3deg); }
}
@keyframes deco-shiver-x {
    0%, 100% { transform: scaleX(-1) rotate(0deg); }
    50%      { transform: scaleX(-1) scale(1.08) rotate(3deg); }
}
@keyframes deco-shiver-y {
    0%, 100% { transform: scaleY(-1) rotate(0deg); }
    50%      { transform: scaleY(-1) scale(1.08) rotate(3deg); }
}
@keyframes deco-shiver-xy {
    0%, 100% { transform: scale(-1, -1) rotate(0deg); }
    50%      { transform: scale(-1, -1) scale(1.08) rotate(3deg); }
}

/* ----- what dangles from a corner ------------------------------------- */
/* The thread is a border, not a glyph: a line of text drawn to look like
   string never quite does. */
.deco-thread {
    position: absolute;
    top: 0;
    font-size: 0.95rem;
    line-height: 1;
    opacity: 0.5;
    padding-top: 2.6em;
    border-left: 1px solid currentColor;
    animation: deco-dangle 4s ease-in-out infinite;
    will-change: transform;
    transform-origin: 50% 0;
}

.deco-thread[data-corner="0"] { left: 2.2em; }
.deco-thread[data-corner="1"] { right: 2.2em; }

@keyframes deco-dangle {
    0%, 100% { transform: rotate(-4deg); }
    50%      { transform: rotate(4deg); }
}

/* On hover it drops a little further, the way one does when you disturb it. */
.decorated:hover .deco-thread {
    animation-duration: 1.1s;
    padding-top: 3.4em;
}

@media (prefers-reduced-motion: reduce) {
    .deco-thread { animation: none !important; transform: none; }
    .decorated:hover .deco-thread { padding-top: 2.6em; }
}

/* ----- strung from a line across the top ------------------------------- */
/* Bunting, fairy lights, tinsel, stockings -- all of these are put up by
   being tied to something. Drawing them free-floating was the reason they
   read as "emoji scattered on a box" rather than as decorations. */
.decoration.is-string::before {
    content: "";
    position: absolute;
    left: -2%;
    right: -2%;
    top: 0.55em;
    border-top: 1px solid currentColor;
    opacity: 0.28;
    /* A shallow droop, so it reads as a line under its own weight rather
       than as a rule. */
    border-radius: 50%;
    height: 0.5em;
}

.is-string .deco-mark {
    top: calc(0.5em + var(--drop, 0.4em));
    /* Tied at the top, so it swings from where it hangs rather than about
       its own middle. */
    transform-origin: 50% -0.6em;
    animation: deco-swing 3.5s ease-in-out infinite alternate;
}

/* ----- hanging straight down, rigid ------------------------------------ */
/* An icicle does not sway. It hangs, it catches the light, and eventually it
   drips -- which is the only thing here that moves. */
.is-drip .deco-mark {
    top: calc(-0.15em + var(--drop, 0.4em));
    opacity: 0.5;
}

.decorated:hover .is-drip .deco-mark {
    animation: deco-drip 1.6s ease-in-out infinite;
}

@keyframes deco-drip {
    0%, 70%, 100% { transform: translateY(0); opacity: 0.5; }
    85%           { transform: translateY(0.35em); opacity: 0.85; }
}

/* ----- up the sides ----------------------------------------------------- */
/* Ivy climbs. It does not queue along the ceiling. */
.is-climb .deco-mark {
    animation: deco-creep 5s ease-in-out infinite alternate;
}

.is-climb .deco-mark[data-side="0"] { left: 0.1em; transform-origin: 0 50%; }
.is-climb .deco-mark[data-side="1"] { right: 0.1em; transform-origin: 100% 50%; }

@keyframes deco-creep {
    from { transform: rotate(-7deg) scale(0.96); }
    to   { transform: rotate(7deg) scale(1.04); }
}

.decorated:hover .is-climb .deco-mark { animation-duration: 1.3s !important; }

@media (prefers-reduced-motion: reduce) {
    .is-string .deco-mark,
    .is-climb .deco-mark,
    .decorated:hover .is-drip .deco-mark { animation: none !important; }
}
