  :root{
    --dur-open: 1.2s;
    --dur-close: 1s;
    --dur-text: .25s;
    --crack-deg: 16deg;
    /* full visible width of the cookie (idle, closed state) */
    --cookie-size: clamp(76px, 52vmin, 320px);
    /* approximate visible horizontal radius of one open half */
    --cookie-open-radius:clamp(33px,23vmin,140px);
    /* keep the complete opened cookie at roughly 90vw */
    --gap-final:max(46px, calc(45vw - var(--cookie-open-radius)));
    /* the paper's edges stay exactly on the two cookie seams */
    --paper-w-final:calc(var(--gap-final) + var(--gap-final));
    --font-roboto-regular:'Roboto','Roboto Regular',sans-serif;
    --font-roboto-medium:'Roboto Medium','Roboto',sans-serif;
    --font-general-sans-medium:'General Sans Medium','General Sans',sans-serif;
  }
  *{ box-sizing:border-box; }
  html,body{
    margin:0; padding:0; width:100%; height:100%;
    overflow:hidden;
    font-family:var(--font-roboto-regular);
    font-weight:400;
  }

  /* ===================== BRAND + THEME PALETTES ===================== */
  html.brand-gmx{ --accent:#1657ea; --accent-2:#4b7bf5; --accent-soft:#d7e6ff; }
  html.brand-webde{ --accent:#ffd200; --accent-2:#ffe066; --accent-soft:#fff3b0; }

  h1,h2,h3,h4{
    font-family:var(--font-roboto-medium);
    font-weight:500;
  }
  h5,h6{
    font-family:var(--font-roboto-regular);
    font-weight:400;
  }
  html.brand-gmx h1,
  html.brand-gmx h2,
  html.brand-gmx h3{
    font-family:var(--font-general-sans-medium);
  }
  @media (max-width:979.98px){
    html.brand-gmx h3:not(.xl){
      font-family:var(--font-roboto-medium);
    }
  }

  html.brand-gmx.theme-light{
    --fg:#1c2433; --fg-soft:#5b6577;
    --paper-bg:#fdf6e3; --paper-bg2:#f7ecc9; --paper-fg:#3a2f1d;
    --cookie-a:#f3cc84; --cookie-b:#c9903e; --crease:#3550a8;
  }
  html.brand-gmx.theme-dark{
    --fg:#eef1f7; --fg-soft:#aab3c5;
    --paper-bg:#fdf6e3; --paper-bg2:#f7ecc9; --paper-fg:#3a2f1d;
    --cookie-a:#d6a45a; --cookie-b:#8a5a1f; --crease:#6f8fe0;
  }
  html.brand-webde.theme-light{
    --fg:#241d02; --fg-soft:#6b5f24;
    --paper-bg:#fdf6e3; --paper-bg2:#f7ecc9; --paper-fg:#3a2f1d;
    --cookie-a:#f3cc84; --cookie-b:#c9903e; --crease:#8a5a12;
  }
  html.brand-webde.theme-dark{
    --fg:#f7f1de; --fg-soft:#c9b877;
    --paper-bg:#fdf6e3; --paper-bg2:#f7ecc9; --paper-fg:#3a2f1d;
    --cookie-a:#d6a45a; --cookie-b:#8a5a1f; --crease:#e0b23a;
  }

  html.theme-light{
    --confetti-1:var(--accent);
    --confetti-2:var(--accent-2);
    --confetti-3:#ff6b6b;
    --confetti-4:#4dd8a8;
    --confetti-5:#ffffff;
    --confetti-6:#ffd166;
  }
  html.theme-dark{
    --confetti-1:color-mix(in srgb, var(--accent) 55%, #ffffff);
    --confetti-2:color-mix(in srgb, var(--accent-2) 45%, #ffffff);
    --confetti-3:#ff9d9d;
    --confetti-4:#8ff0c7;
    --confetti-5:#ffffff;
    --confetti-6:#ffe6a0;
  }

  body{
    /* Shared reference-color gradient, independent of brand and theme. */
    background:
      radial-gradient(ellipse 55% 115% at 50% 100%,
        #c2e3f9 0%,
        rgba(194,227,249,.86) 20%,
        rgba(194,227,249,.68) 40%,
        rgba(194,227,249,.48) 60%,
        rgba(194,227,249,.2) 82%,
        rgba(194,227,249,0) 100%),
      linear-gradient(180deg,
        #3d82c4 0%,
        #549fd8 25%,
        #65b0e4 50%,
        #78bbe9 75%,
        #90c6ec 100%);
    color:var(--fg);
    width:100vw; height:100vh;
  }

  #app{
    width:100%; height:100%;
    display:flex; flex-direction:column;
    position:relative;
  }

  /* ===================== HEADER ===================== */
  #header{
    flex:0 0 auto;
    display:flex; align-items:center;
    padding:clamp(6px,2.5vmin,16px) clamp(8px,3vmin,20px);
    min-width:0;
  }
  #title{
    flex:1 1 auto;
    min-width:0;
    margin:0;
    text-align:center;
    font-size:clamp(10px,4.1vmin,26px);
    font-weight:500;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
  }

  /* ===================== STAGE ===================== */
  #stage{
    flex:1 1 auto;
    min-height:0;
    position:relative;
    display:flex; align-items:center; justify-content:center;
    overflow:hidden;
    cursor:pointer;
  }

  .cookie-half-wrap{
    position:absolute;
    left:50%; top:50%;
    z-index:2;
    width:var(--cookie-size);
    transform:translate(-50%,-50%) rotate(0deg);
    transform-origin:50% 50%;
    filter:drop-shadow(0 clamp(3px,1vmin,10px) clamp(6px,2vmin,18px) rgba(0,0,0,.25))
           drop-shadow(0 0 clamp(10px,4vmin,34px) color-mix(in srgb, var(--accent) 55%, transparent));
  }
  .cookie-half-wrap svg{ width:100%; height:auto; display:block; overflow:visible; }

  #app.opening #cookie-left-wrap  { animation:cookieLeftOpen   var(--dur-open)  cubic-bezier(.3,.7,.35,1) forwards; }
  #app.opening #cookie-right-wrap { animation:cookieRightOpen  var(--dur-open)  cubic-bezier(.3,.7,.35,1) forwards; }
  #app.open    #cookie-left-wrap  { transform:translate(calc(-50% - var(--gap-final)), -50%) rotate(calc(-1 * var(--crack-deg))); }
  #app.open    #cookie-right-wrap { transform:translate(calc(-50% + var(--gap-final)), -50%) rotate(var(--crack-deg)); }
  #app.closing #cookie-left-wrap  { transform:translate(calc(-50% - var(--gap-final)), -50%) rotate(calc(-1 * var(--crack-deg))); animation:cookieLeftClose var(--dur-close) cubic-bezier(.5,0,.4,1) forwards; }
  #app.closing #cookie-right-wrap { transform:translate(calc(-50% + var(--gap-final)), -50%) rotate(var(--crack-deg));  animation:cookieRightClose var(--dur-close) cubic-bezier(.5,0,.4,1) forwards; }

  /* Phase 1 (0-14%): quick "snap" crack rotation, no movement yet.
     Phase 2 (14-100%): halves translate outward at a constant rotation,
     in lockstep with the paper widening (#scroll uses the same stops). */
  @keyframes cookieLeftOpen{
    0%   { transform:translate(-50%,-50%) rotate(0deg); }
    14%  { transform:translate(-50%,-50%) rotate(calc(-1 * var(--crack-deg))); }
    100% { transform:translate(calc(-50% - var(--gap-final)), -50%) rotate(calc(-1 * var(--crack-deg))); }
  }
  @keyframes cookieRightOpen{
    0%   { transform:translate(-50%,-50%) rotate(0deg); }
    14%  { transform:translate(-50%,-50%) rotate(var(--crack-deg)); }
    100% { transform:translate(calc(-50% + var(--gap-final)), -50%) rotate(var(--crack-deg)); }
  }
  @keyframes cookieLeftClose{
    0%   { transform:translate(calc(-50% - var(--gap-final)), -50%) rotate(calc(-1 * var(--crack-deg))); }
    86%  { transform:translate(-50%,-50%) rotate(calc(-1 * var(--crack-deg))); }
    100% { transform:translate(-50%,-50%) rotate(0deg); }
  }
  @keyframes cookieRightClose{
    0%   { transform:translate(calc(-50% + var(--gap-final)), -50%) rotate(var(--crack-deg)); }
    86%  { transform:translate(-50%,-50%) rotate(var(--crack-deg)); }
    100% { transform:translate(-50%,-50%) rotate(0deg); }
  }

  /* ===================== FORTUNE SCROLL ===================== */
  #scroll{
    position:absolute; left:50%; top:50%;
    z-index:1;
    width:0;
    max-width:min(92vw, var(--paper-w-final));
    opacity:0;
    transform:translate(-50%,-50%);
    pointer-events:none;
  }
  #scroll-inner{
    position:relative;
    width:100%;
    background:linear-gradient(180deg, var(--paper-bg), var(--paper-bg2));
    border-radius:clamp(6px,1.6vmin,14px);
    /* Horizontal padding is capped with a %-of-width value so it always
       shrinks along with the animated width of the parent #scroll instead
       of forcing a fixed minimum ("border-box" content-width can never go
       negative, so a fixed px padding creates a hard floor the box cannot
       shrink below -- using min(px, %) removes that floor entirely). */
    padding:clamp(10px,3.6vmin,26px) min(clamp(14px,4.4vmin,34px), 14%);
    box-shadow:0 clamp(4px,1.6vmin,16px) clamp(10px,3vmin,30px) rgba(0,0,0,.35),
               inset 0 0 0 2px rgba(0,0,0,.05);
    overflow:auto;
    max-height:96vh;
    scrollbar-width:none;      /* Firefox: never show a scrollbar on the paper */
    -ms-overflow-style:none;   /* old Edge/IE */
  }
  #scroll-inner::-webkit-scrollbar{ display:none; width:0; height:0; } /* Chromium/WebKit */
  #scroll-inner::before, #scroll-inner::after{
    content:""; position:absolute; top:0; bottom:0; width:clamp(8px,2.6vmin,20px);
    background:linear-gradient(90deg, rgba(0,0,0,.18), transparent);
    border-radius:inherit;
  }
  #scroll-inner::before{ left:0; }
  #scroll-inner::after{ right:0; transform:scaleX(-1); }

  #message{
    margin:0;
    color:var(--paper-fg);
    font-family:var(--font-roboto-regular);
    font-size:clamp(13px,4.6vmin,28px);
    font-weight:400;
    line-height:1.35;
    text-align:center;
    white-space:pre-wrap;
    opacity:0;
  }

  /* NOTE: .opening and .open are intentionally NOT combined into one shared
     "animation:" selector -- browsers create a fresh Animation (restarting
     currentTime at 0) whenever the set of matched rules for an element
     changes, even if the computed animation value is textually identical.
     Instead .open is a plain static rule holding the exact same end values
     as the .opening keyframe's 100% stop, so the swap is visually seamless. */
  #app.opening #scroll{ animation:scrollOpen var(--dur-open) cubic-bezier(.3,.7,.35,1) forwards; pointer-events:auto; }
  #app.open    #scroll{ width:var(--paper-w-final); opacity:1; pointer-events:auto; }
  #app.closing #scroll{ width:var(--paper-w-final); opacity:1; animation:scrollClose var(--dur-close) cubic-bezier(.5,0,.4,1) forwards; }

  /* width/opacity only -- no scale, height is locked in px by JS before this starts,
     so it never changes ("keeps its vertical scale"), matching the cookie's timing. */
  @keyframes scrollOpen{
    0%   { width:0; opacity:0; }
    14%  { width:0; opacity:0; }
    22%  { width:calc(var(--paper-w-final) * .1); opacity:1; }
    100% { width:var(--paper-w-final); opacity:1; }
  }
  @keyframes scrollClose{
    0%   { width:var(--paper-w-final); opacity:1; }
    78%  { width:calc(var(--paper-w-final) * .1); opacity:1; }
    86%  { width:0; opacity:0; }
    100% { width:0; opacity:0; }
  }

  #app.opening #message{ animation:textIn var(--dur-text) ease-out forwards; animation-delay:calc(var(--dur-open) * .9); }
  #app.open    #message{ opacity:1; transform:translateY(0) scale(1); }
  #app.closing #message{ animation:textOut .22s ease-in forwards; }

  @keyframes textIn{
    0%   { opacity:0; transform:translateY(8px) scale(.94); }
    100% { opacity:1; transform:translateY(0) scale(1); }
  }
  @keyframes textOut{
    0%   { opacity:1; transform:translateY(0) scale(1); }
    100% { opacity:0; transform:translateY(8px) scale(.94); }
  }

  /* ===================== CONFETTI ===================== */
  #confetti-layer{
    position:absolute; inset:0;
    pointer-events:none;
    overflow:visible;
  }
  .confetto{
    position:absolute; left:50%; top:50%;
    width:var(--size); height:var(--size);
    background:var(--color);
    opacity:0;
    border-radius:var(--radius);
    animation:confettiBurst var(--cdur) ease-out forwards;
    animation-delay:var(--cdelay);
  }
  @keyframes confettiBurst{
    0%   { opacity:0; transform:translate(-50%,-50%) rotate(0deg) scale(.4); }
    12%  { opacity:1; }
    100% { opacity:0; transform:translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) rotate(var(--rot)) scale(1); }
  }

  @media (prefers-reduced-motion: reduce){
    #app.opening #cookie-left-wrap, #app.opening #cookie-right-wrap,
    #app.closing #cookie-left-wrap, #app.closing #cookie-right-wrap,
    #app.opening #scroll, #app.closing #scroll,
    #app.opening #message, #app.closing #message{
      animation-duration:.01s !important;
    }
  }
