/* kb button - mockup 16-hover-og-loading.html, combination "H2 + H4 (hover)" with loading L1;
   colours from 14-knapper-kontrast.html "forslag a" (primary nr. 7 and secondary S8 from 20-primaer-knap.html,
   danger "ensfarvet mørk rød" from 21-slet-knap.html nr. 8, accent "hindbær" and festive "solnedgang, mørk" from
   22-knapper-i-siden.html), laid out as 15-knapper-sider.html "farve i siderne";
   result phase from 04-knapper.html.
   Markup:  <button class="kb-btn kb-btn--primary|--secondary|--danger|--accent|--festive [kb-btn--sm|--lg] [kb-btn--icon]"><span class="kb-btn__label">...</span></button>
            accent = the one stand-out action on a page (raspberry); festive = warm orange tones.
            kb-btn--icon = square, icon only (a delete in a tight table row); give it aria-label and title.
   button.js adds the layers (tone, wave, dots, result, result icon) and runs kb.button.run.
   The button never changes size: width is frozen while busy, motion only moves painted layers. */
@layer kb.components {

  /* ---------- colour stops (light + dark) ----------
     a = idle tile (side nuance 2 . base . side nuance 3 . base . side nuance 2), b = the darker tone
     that slides in while loading. Every white-text stop of a primary/danger/accent/festive button is >= 4.5:1;
     the secondary is text only (no surface, S8): its ink is >= 4.5:1 on the card and on its loading tone. ok = the success surface, green -> emerald -> teal (mockup 17,
     variant 7); its check (--kb-success-ink) is >= 3:1 on every stop. Same pattern as tokens.css: dark exists twice, keep in step. */
  :root,
  [data-theme="light"] {
    --kb-btn-pri-a: #2349b0; --kb-btn-pri-a2: #1c3b8c; --kb-btn-pri-a3: #0b65b8;
    --kb-btn-pri-b: #1a3780; --kb-btn-pri-b2: #152f6e; --kb-btn-pri-b3: #084f90;
    --kb-btn-sec-a: transparent; --kb-btn-sec-a2: transparent; --kb-btn-sec-a3: transparent;
    --kb-btn-sec-b: #e8eefc; --kb-btn-sec-b2: #e8eefc; --kb-btn-sec-b3: #e8eefc;
    --kb-btn-sec-ink: #2349b0;
    --kb-btn-dan-a: #931717; --kb-btn-dan-a2: #931717; --kb-btn-dan-a3: #931717;
    --kb-btn-dan-b: #731111; --kb-btn-dan-b2: #731111; --kb-btn-dan-b3: #731111;
    --kb-btn-acc-a: #be185d; --kb-btn-acc-a2: #9d174d; --kb-btn-acc-a3: #d0246b;
    --kb-btn-acc-b: #9d174d; --kb-btn-acc-b2: #831843; --kb-btn-acc-b3: #ad1a58;
    --kb-btn-fest-a: #b94708; --kb-btn-fest-a2: #9a3412; --kb-btn-fest-a3: #c2410c;
    --kb-btn-fest-b: #9a3412; --kb-btn-fest-b2: #7c2d12; --kb-btn-fest-b3: #a63a0f;
    --kb-btn-ok-a: #15803d; --kb-btn-ok-a2: #059669; --kb-btn-ok-a3: #0d9488;
  }
  :root[data-theme="dark"],
  [data-theme="dark"] {
    --kb-btn-pri-a: #3a5dc8; --kb-btn-pri-a2: #2f4fb0; --kb-btn-pri-a3: #1468b8;
    --kb-btn-pri-b: #284aa6; --kb-btn-pri-b2: #213f8c; --kb-btn-pri-b3: #0f5596;
    --kb-btn-sec-a: transparent; --kb-btn-sec-a2: transparent; --kb-btn-sec-a3: transparent;
    --kb-btn-sec-b: #18264a; --kb-btn-sec-b2: #18264a; --kb-btn-sec-b3: #18264a;
    --kb-btn-sec-ink: #a9c2ff;
    --kb-btn-dan-a: #ad2424; --kb-btn-dan-a2: #ad2424; --kb-btn-dan-a3: #ad2424;
    --kb-btn-dan-b: #8a1b1b; --kb-btn-dan-b2: #8a1b1b; --kb-btn-dan-b3: #8a1b1b;
    --kb-btn-acc-a: #c81e64; --kb-btn-acc-a2: #a8185a; --kb-btn-acc-a3: #d42a6e;
    --kb-btn-acc-b: #a8185a; --kb-btn-acc-b2: #8c1650; --kb-btn-acc-b3: #b31d60;
    --kb-btn-fest-a: #bd4709; --kb-btn-fest-a2: #a63a0f; --kb-btn-fest-a3: #c24b0e;
    --kb-btn-fest-b: #9a3412; --kb-btn-fest-b2: #7c2d12; --kb-btn-fest-b3: #a63a0f;
    --kb-btn-ok-a: #22a05a; --kb-btn-ok-a2: #10b981; --kb-btn-ok-a3: #14b8a6;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme]) {
      --kb-btn-pri-a: #3a5dc8; --kb-btn-pri-a2: #2f4fb0; --kb-btn-pri-a3: #1468b8;
      --kb-btn-pri-b: #284aa6; --kb-btn-pri-b2: #213f8c; --kb-btn-pri-b3: #0f5596;
      --kb-btn-sec-a: transparent; --kb-btn-sec-a2: transparent; --kb-btn-sec-a3: transparent;
      --kb-btn-sec-b: #18264a; --kb-btn-sec-b2: #18264a; --kb-btn-sec-b3: #18264a;
      --kb-btn-sec-ink: #a9c2ff;
      --kb-btn-dan-a: #ad2424; --kb-btn-dan-a2: #ad2424; --kb-btn-dan-a3: #ad2424;
      --kb-btn-dan-b: #8a1b1b; --kb-btn-dan-b2: #8a1b1b; --kb-btn-dan-b3: #8a1b1b;
      --kb-btn-acc-a: #c81e64; --kb-btn-acc-a2: #a8185a; --kb-btn-acc-a3: #d42a6e;
      --kb-btn-acc-b: #a8185a; --kb-btn-acc-b2: #8c1650; --kb-btn-acc-b3: #b31d60;
      --kb-btn-fest-a: #bd4709; --kb-btn-fest-a2: #a63a0f; --kb-btn-fest-a3: #c24b0e;
      --kb-btn-fest-b: #9a3412; --kb-btn-fest-b2: #7c2d12; --kb-btn-fest-b3: #a63a0f;
      --kb-btn-ok-a: #22a05a; --kb-btn-ok-a2: #10b981; --kb-btn-ok-a3: #14b8a6;
    }
  }

  /* ---------- base: tile with colour in the sides ---------- */
  .kb-btn {
    --kb-btn-a: var(--kb-btn-pri-a); --kb-btn-a2: var(--kb-btn-pri-a2); --kb-btn-a3: var(--kb-btn-pri-a3);
    --kb-btn-b: var(--kb-btn-pri-b); --kb-btn-b2: var(--kb-btn-pri-b2); --kb-btn-b3: var(--kb-btn-pri-b3);
    --kb-btn-fg: var(--kb-primary-ink);
    --kb-btn-glow: var(--kb-btn-a);          /* colour of the hover / loading glow */
    --kb-btn-glow-edge: rgba(255, 255, 255, .35);
    --kb-btn-hover-filter: saturate(1.15) brightness(.96);   /* deepening of the colour layers on hover */
    --kb-btn-ok: var(--kb-btn-ok-a2);
    --kb-btn-ok-1: var(--kb-btn-ok-a); --kb-btn-ok-2: var(--kb-btn-ok-a2); --kb-btn-ok-3: var(--kb-btn-ok-a3);
    --kb-btn-ok-ink: var(--kb-success-ink);
    --kb-btn-err: var(--kb-danger);
    --kb-btn-err-ink: var(--kb-danger-ink);

    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    box-sizing: border-box;
    max-width: 100%;
    height: 40px;
    padding: 0 18px;
    border: 0;
    border-radius: var(--kb-radius);
    /* all colour is painted on ::before; the element itself stays clear (else the UA button face shows through the
       secondary, which has no surface of its own) */
    background: transparent;
    color: var(--kb-btn-fg);
    font: inherit;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: box-shadow .3s var(--kb-ease-out);
  }

  /* The colour tile lives on ::before, so the hover deepening (a filter) touches the colour layers only and the
     label stays pure white / pure ink: its contrast is that of the stops, also while hovered.
     The tile is twice the button wide; position 0% -> 200% is one seamless loop. */
  .kb-btn::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(100deg,
      var(--kb-btn-a2) 0%, var(--kb-btn-a) 25%, var(--kb-btn-a3) 50%, var(--kb-btn-a) 75%, var(--kb-btn-a2) 100%) 0% 0 / 200% 100% repeat-x;
    transition: filter .3s var(--kb-ease-out), background-position .7s var(--kb-ease-out);
  }
  /* light inner edge, above the colour layers (an inset shadow on the button itself would sit under ::before) */
  .kb-btn::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    pointer-events: none;
    transition: box-shadow .3s var(--kb-ease-out);
  }

  /* primary (mockup 20, nr. 7) and accent: solid while idle; the tile carries the nuance only in the half that slides
     in on hover, a -> a -> a3 -> a2 -> a keeps the loop seamless for the loading flow. Festive keeps the nuance always. */
  .kb-btn--primary::before,
  .kb-btn--accent::before {
    background-image: linear-gradient(100deg,
      var(--kb-btn-a) 0%, var(--kb-btn-a) 50%, var(--kb-btn-a3) 66%, var(--kb-btn-a2) 83%, var(--kb-btn-a) 100%);
  }
  .kb-btn--secondary {
    --kb-btn-a: var(--kb-btn-sec-a); --kb-btn-a2: var(--kb-btn-sec-a2); --kb-btn-a3: var(--kb-btn-sec-a3);
    --kb-btn-b: var(--kb-btn-sec-b); --kb-btn-b2: var(--kb-btn-sec-b2); --kb-btn-b3: var(--kb-btn-sec-b3);
    --kb-btn-fg: var(--kb-btn-sec-ink);
    --kb-btn-glow: var(--kb-btn-sec-ink);
    --kb-btn-glow-edge: color-mix(in srgb, var(--kb-btn-sec-ink) 25%, transparent);
  }
  .kb-btn--danger {
    --kb-btn-a: var(--kb-btn-dan-a); --kb-btn-a2: var(--kb-btn-dan-a2); --kb-btn-a3: var(--kb-btn-dan-a3);
    --kb-btn-b: var(--kb-btn-dan-b); --kb-btn-b2: var(--kb-btn-dan-b2); --kb-btn-b3: var(--kb-btn-dan-b3);
    --kb-btn-fg: var(--kb-danger-ink);
    --kb-btn-hover-filter: saturate(1.15) brightness(.94);   /* a touch darker: keeps white text >= 4.5:1 on every hovered stop */
  }
  .kb-btn--accent {
    --kb-btn-a: var(--kb-btn-acc-a); --kb-btn-a2: var(--kb-btn-acc-a2); --kb-btn-a3: var(--kb-btn-acc-a3);
    --kb-btn-b: var(--kb-btn-acc-b); --kb-btn-b2: var(--kb-btn-acc-b2); --kb-btn-b3: var(--kb-btn-acc-b3);
  }
  .kb-btn--festive {
    --kb-btn-a: var(--kb-btn-fest-a); --kb-btn-a2: var(--kb-btn-fest-a2); --kb-btn-a3: var(--kb-btn-fest-a3);
    --kb-btn-b: var(--kb-btn-fest-b); --kb-btn-b2: var(--kb-btn-fest-b2); --kb-btn-b3: var(--kb-btn-fest-b3);
  }

  .kb-btn--sm { height: 32px; padding: 0 12px; font-size: 14px; }
  .kb-btn--lg { height: 48px; padding: 0 24px; font-size: 16px; }
  /* icon only: square in every size */
  .kb-btn--icon { width: 40px; padding: 0; }
  .kb-btn--icon.kb-btn--sm { width: 32px; }
  .kb-btn--icon.kb-btn--lg { width: 48px; }

  .kb-btn:focus-visible {
    outline: 2px solid var(--kb-focus-ring);
    outline-offset: 2px;
  }

  .kb-btn__label {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    max-width: 100%;
    transition: opacity .15s;
  }
  .kb-btn__label > svg,
  .kb-btn__label > i[data-lucide] { flex: none; width: 16px; height: 16px; stroke-width: 2; }
  /* a long label is cut with an ellipsis instead of widening the button (button.js wraps bare text in this) */
  .kb-btn__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .kb-btn:disabled,
  .kb-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

  /* ---------- hover: H2 + H4 ----------
     the side colours glide across and get a touch deeper, plus a light inner edge and a coloured glow. No size change. */
  /* :where keeps these at (0,2,0), so the loading glow below (later, same weight) wins while the pointer is still over the button */
  @media (hover: hover) {
    .kb-btn:hover:where(:not(:disabled):not([aria-disabled="true"]))::before { background-position: 100% 0; }
    .kb-btn:hover:where(:not(:disabled):not([aria-disabled="true"]))::before,
    .kb-btn:hover:where(:not(:disabled):not([aria-disabled="true"])) :is(.kb-btn__tone, .kb-btn__wave) {
      filter: var(--kb-btn-hover-filter);
    }
    .kb-btn:hover:where(:not(:disabled):not([aria-disabled="true"])) {
      box-shadow:
        0 0 0 3px color-mix(in srgb, var(--kb-btn-glow) 22%, transparent),
        0 8px 20px -6px color-mix(in srgb, var(--kb-btn-glow) 60%, transparent);
    }
    .kb-btn:hover:where(:not(:disabled):not([aria-disabled="true"]))::after {
      box-shadow: inset 0 0 0 1px var(--kb-btn-glow-edge), inset 0 1px 0 var(--kb-btn-glow-edge);
    }
    .kb-btn--secondary:hover:where(:not(:disabled):not([aria-disabled="true"])) {
      box-shadow:
        0 0 0 3px color-mix(in srgb, var(--kb-btn-sec-ink) 14%, transparent),
        0 8px 20px -8px color-mix(in srgb, var(--kb-btn-sec-ink) 45%, transparent);
    }
    .kb-btn--secondary:hover:where(:not(:disabled):not([aria-disabled="true"]))::after {
      box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--kb-btn-sec-ink) 25%, transparent);
    }
  }

  /* ---------- layers injected by button.js ---------- */
  /* tone: a darker, multicoloured tone; wider than the button so no corner stays uncovered */
  .kb-btn__tone {
    position: absolute; top: 0; bottom: 0; left: -40px; right: -40px; z-index: 0; pointer-events: none;
    background: linear-gradient(100deg,
      var(--kb-btn-b2) 0%, var(--kb-btn-b) 25%, var(--kb-btn-b3) 50%, var(--kb-btn-b) 75%, var(--kb-btn-b2) 100%) 0 0 / 200% 100% repeat-x;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 36px), transparent);
    mask-image: linear-gradient(90deg, #000 calc(100% - 36px), transparent);
    transform: translateX(-100%) skewX(var(--kb-skew));
    transition: transform .38s var(--kb-ease-out), filter .3s var(--kb-ease-out);
  }

  /* wave: five soft bands chase each other with momentum */
  .kb-btn__wave {
    position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
    opacity: 0; transition: opacity .15s, filter .3s var(--kb-ease-out);
  }
  .kb-btn__wave i { position: absolute; inset: 0; display: block; transform: translateX(-100%); }
  .kb-btn__wave i::after {
    content: ""; position: absolute; top: 0; bottom: 0; right: 0; width: 34px;
    background: linear-gradient(90deg, transparent, var(--kb-btn-a) 35%, var(--kb-btn-a) 65%, transparent);
    transform: skewX(var(--kb-skew));
  }

  /* dots replace the text while loading */
  .kb-btn__dots {
    position: absolute; inset: 0; z-index: 1; pointer-events: none;
    display: flex; align-items: center; justify-content: center; gap: 5px;
    opacity: 0; transition: opacity .15s;
  }
  .kb-btn__dots i { display: block; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

  /* result: a green / red layer; the icon pops in once it covers */
  .kb-btn__result {
    position: absolute; top: 0; bottom: 0; left: -48px; right: -48px; z-index: 3; pointer-events: none;
    --kb-btn-c1: var(--kb-btn-ok-1); --kb-btn-c2: var(--kb-btn-ok-2); --kb-btn-c3: var(--kb-btn-ok-3);
    background: linear-gradient(90deg, transparent, var(--kb-btn-c1) 36px, var(--kb-btn-c2) 50%, var(--kb-btn-c3) calc(100% - 36px), transparent);
    transform: translateX(-101%) skewX(var(--kb-skew));
  }
  .kb-btn__result-icon {
    position: absolute; inset: 0; z-index: 4; pointer-events: none;
    display: flex; align-items: center; justify-content: center;
    color: var(--kb-btn-ok-ink);
  }
  .kb-btn__result-icon svg { width: 20px; height: 20px; stroke-width: 2.6; transform: scale(0); opacity: 0; }
  .kb-btn__result-icon .kb-btn__x { display: none; }

  /* ---------- loading: L1 ---------- */
  .kb-btn.is-loading::before { animation: kb-btn-flow 2.6s linear infinite; }
  /* the glow from hover stays, so the change from hover to loading is seamless */
  .kb-btn.is-loading { box-shadow: 0 0 0 3px color-mix(in srgb, var(--kb-btn-glow) 18%, transparent); }
  .kb-btn.is-loading::after { box-shadow: inset 0 0 0 1px var(--kb-btn-glow-edge); }
  .kb-btn.is-loading .kb-btn__label { opacity: 0; }
  .kb-btn.is-loading .kb-btn__dots { opacity: 1; }
  .kb-btn.is-loading .kb-btn__wave { opacity: 1; }
  .kb-btn.is-loading .kb-btn__tone {
    transform: translateX(16px) skewX(var(--kb-skew));
    animation: kb-btn-flow-tone 2.6s linear infinite;
  }
  .kb-btn.is-loading .kb-btn__wave i { animation: kb-btn-sweep 1.65s infinite; }
  .kb-btn.is-loading .kb-btn__wave i:nth-child(2) { animation-delay: .11s; }
  .kb-btn.is-loading .kb-btn__wave i:nth-child(3) { animation-delay: .22s; }
  .kb-btn.is-loading .kb-btn__wave i:nth-child(4) { animation-delay: .33s; }
  .kb-btn.is-loading .kb-btn__wave i:nth-child(5) { animation-delay: .44s; }
  .kb-btn.is-loading .kb-btn__dots i { animation: kb-btn-hop 1.65s infinite; }
  .kb-btn.is-loading .kb-btn__dots i:nth-child(2) { animation-delay: .11s; }
  .kb-btn.is-loading .kb-btn__dots i:nth-child(3) { animation-delay: .22s; }

  /* The flow starts exactly where the tile stands (button.js sets --kb-btn-flow-from from the hover position). */
  @keyframes kb-btn-flow {
    from { background-position: var(--kb-btn-flow-from, 0%) 0; }
    to { background-position: calc(var(--kb-btn-flow-from, 0%) + 200%) 0; }
  }
  @keyframes kb-btn-flow-tone { from { background-position: 0% 0; } to { background-position: 200% 0; } }
  @keyframes kb-btn-sweep {
    0% { transform: translateX(-100%); animation-timing-function: var(--kb-ease-momentum); }
    85%, 100% { transform: translateX(calc(100% + 40px)); }
  }
  @keyframes kb-btn-hop {
    0% { transform: none; animation-timing-function: cubic-bezier(.3, 0, .2, 1); }
    18% { transform: translateY(-6px); animation-timing-function: cubic-bezier(.6, 0, .8, .4); }
    36%, 100% { transform: none; }
  }

  /* ---------- result: success / error ----------
     the layer slides in while loading carries on behind it; the text stays hidden until the layer slides out */
  .kb-btn.is-error { --kb-btn-hold: 2.4s; }
  .kb-btn.is-error .kb-btn__result { --kb-btn-c1: var(--kb-btn-err); --kb-btn-c2: var(--kb-btn-err); --kb-btn-c3: var(--kb-btn-err); }
  .kb-btn.is-done .kb-btn__result,
  .kb-btn.is-error .kb-btn__result {
    animation:
      kb-btn-res-in .4s var(--kb-ease-out) forwards,
      kb-btn-res-out .42s cubic-bezier(.6, 0, .75, .3) forwards var(--kb-btn-hold, 1.6s);
  }
  .kb-btn.is-done .kb-btn__label,
  .kb-btn.is-error .kb-btn__label {
    opacity: 0; transition: none;
    animation: kb-btn-reveal 0s forwards var(--kb-btn-hold, 1.6s);
  }
  .kb-btn.is-done .kb-btn__tone,
  .kb-btn.is-error .kb-btn__tone { transition: none; }
  .kb-btn.is-error .kb-btn__result-icon { color: var(--kb-btn-err-ink); }
  .kb-btn.is-error .kb-btn__result-icon .kb-btn__ok { display: none; }
  .kb-btn.is-error .kb-btn__result-icon .kb-btn__x { display: block; }
  .kb-btn.is-done .kb-btn__result-icon .kb-btn__ok,
  .kb-btn.is-error .kb-btn__result-icon .kb-btn__x {
    animation:
      kb-btn-pop-in .34s var(--kb-ease-spring) forwards .38s,
      kb-btn-pop-out .16s ease-in forwards calc(var(--kb-btn-hold, 1.6s) - .12s);
  }
  @keyframes kb-btn-reveal { to { opacity: 1; } }
  @keyframes kb-btn-res-in { to { transform: translateX(0) skewX(var(--kb-skew)); } }
  @keyframes kb-btn-res-out {
    from { transform: translateX(0) skewX(var(--kb-skew)); }
    to { transform: translateX(101%) skewX(var(--kb-skew)); }
  }
  @keyframes kb-btn-pop-in { to { transform: scale(1); opacity: 1; } }
  @keyframes kb-btn-pop-out { from { transform: scale(1); opacity: 1; } to { transform: scale(.4); opacity: 0; } }

  /* ---------- reduced motion: plain state changes ---------- */
  @media (prefers-reduced-motion: reduce) {
    .kb-btn, .kb-btn::before, .kb-btn::after, .kb-btn * { animation: none !important; transition: none !important; }
    .kb-btn.is-loading .kb-btn__tone { transform: translateX(16px) skewX(var(--kb-skew)); }
    .kb-btn.is-done .kb-btn__result,
    .kb-btn.is-error .kb-btn__result { transform: translateX(0) skewX(var(--kb-skew)); }
    .kb-btn.is-done .kb-btn__result-icon .kb-btn__ok,
    .kb-btn.is-error .kb-btn__result-icon .kb-btn__x { transform: none; opacity: 1; }
  }
}
