/* ==========================================================================
   RIVALZ — Liquid Glass
   A third appearance switch, alongside light and dark. NOT a third theme.
   --------------------------------------------------------------------------
   Glass is a MODIFIER on top of whichever theme is running, exactly the way
   Apple does it: iOS 26 has glass in light and in dark. A third palette
   beside the two in rivalz-tokens.css would be a third place to forget at
   every colour change, and the file already says what that costs.

   So the switch is its own attribute, `data-glass="an"` on <html>, and the
   theme keeps deciding warm or cold. Two combinations, both written out:
   dark glass (the default) and light glass ([data-theme='light']).

   THIS FILE LOADS LAST, AND THAT IS LOAD-BEARING. `:root[data-glass='an']`
   and `:root[data-theme='dark']` have the same specificity (0,2,0), so order
   decides — the same trap the phone override of .hub__tile--heute fell into.
   Loaded before rivalz-tokens.css or styles.css this file would be inert in
   exactly the places it matters most.

   WHAT MAKES GLASS READ AS GLASS, and why each piece is here:

     1. Something BEHIND it. Translucency over a flat page colour is just a
        different flat colour. So the page ground becomes the hero photo,
        fixed and blurred, under a veil that bounds how bright it can get —
        which is what makes the contrast below measurable at all.
     2. Blur plus SATURATION. The blur alone gives frosted plastic; the
        colours behind have to bleed through vividly, which is saturate().
     3. A specular rim. One bright inner line along the top edge, one dark
        one along the bottom. That single detail is the difference between
        "translucent box" and "pane of glass".
     4. ONE film, and one only. A pane is the film; everything inside it is a
        tint. Two films multiply — see section 3, where that rule lives and
        where the measurement for it stands.

   CONTRAST. Measured against the real photograph rather than estimated — the
   estimate was wrong, and in the direction that matters. Every pixel of the
   blurred hero image was composited through veil, wash and pane, and the
   WORST point of the whole picture is what stands here:

                       dark glass        light glass
     text                7.5 : 1           15.9 : 1
     muted text          5.1 : 1            6.8 : 1
     brand as text       6.4 : 1            6.0 : 1
     pane against page   1.36               1.14

   The pane/page figures are the interesting ones: 1.36 and 1.14 against the
   opaque themes' 1.09 and 1.15. A card on glass separates BETTER than a card
   on a flat surface, because the blur is a second cue the flat ones never
   had.

   Anyone touching the veil, the wash or the film measures again. The three
   trade against each other and none of them is free.

   AND THE VEIL IN PARTICULAR HAS BEEN TRIED. It is the obvious knob — 0.88
   leaves 12 % of the photograph, so the ground below the stage reads as a
   flat dark colour and the glass has little to show. Lowering it was measured
   across the whole viewport rather than argued about:

     veil   text   muted   luminance spread of the ground
     0.88   8.24   5.56    1.43
     0.80   7.25   4.91    1.50
     0.72   6.32   4.28    1.72
     0.68   5.75   3.90    1.90

   A fifth of the text contrast buys five hundredths of picture. The reason is
   that the veil is near-black: dropping its alpha lets the photograph's
   BRIGHTNESS through, and brightness is the one thing a light film over light
   type cannot spend. Colour is free and already there — the wash puts it back
   without luminance, and the ground measures 0.41 mean saturation as it
   stands. The veil stays at 0.88. Anyone who moves it repeats this table.

   GLASS IS THE DEFAULT since 13 September 2026. The switch stays: the boot
   script in index.html asks for a stored "aus", not for a stored "an", so a
   visitor who has never set anything gets glass and one who switched it off
   keeps it off. */

/* ==========================================================================
   1 · The recipe
   ========================================================================== */

:root[data-glass='an'] {
  /* THE PANE IS A LIGHT FILM, NOT A DARK ONE, and that was the correction the
     first build needed. Dark glass at 0.52 over a dark ground measured 1.02
     against the page — the card had stopped being a card. Glass in a dark
     theme lifts: a thin white film plus the blur, so the pane reads ABOVE the
     page, the way it does in iOS. Measured afterwards, pane against ground:
     1.27 in dark, 1.29 in light — better separation than the opaque themes
     manage (1.09 / 1.15), because the blur adds a second cue the flat
     surfaces never had.

     --glas-fond is the recessed fill INSIDE a pane and --glas-stufe is one
     level in: tints, not second panes. Two panes stacked would add their
     alpha and go to mud, which is what the rule at the end of section 3 is
     for — and the tints are what it hands out instead. Both are BLACK in the
     dark theme and warm-dark in the light one; the direction is measured, and
     the measurement is written where they are used. */
  --glas-blur:     24px;
  --glas-saett:    180%;
  --glas-flaeche:  rgba(255, 255, 255, 0.13);
  --glas-hoch:     rgba(255, 255, 255, 0.18);
  --glas-fond:     rgba(0, 0, 0, 0.24);
  --glas-stufe:    rgba(0, 0, 0, 0.12);
  /* Der Dimmer hinter einem Dialog. Siehe die Regel bei den Huellen. */
  --glas-dimm:     rgba(0, 0, 0, 0.58);
  /* THE RIM IS WHAT MAKES A PANE A PANE, and 0.16 was too faint to be one.
     Measured against the composited ground rather than judged: a white
     hairline at 0.16 reads 1.58 against its own pane — a line you have to
     look for. At 0.34 it is 2.55, and against the ground 3.70. The opaque
     dark theme runs its borders at 1.28; glass needs more, because the rim
     is the ONLY hard edge a translucent surface has. A fill has a colour
     boundary, a pane has a line and nothing else. */
  --glas-rand:     rgba(255, 255, 255, 0.34);
  --glas-rand-hell: rgba(255, 255, 255, 0.52);

  /* THE LIT EDGE, AND IT IS DIRECTIONAL. Two corrections in one.

     The black line is gone. It sat at the bottom and was meant to read as the
     pane casting into itself — which is how a RAISED SOLID behaves. A pane
     over a dark ground has nothing to cast onto; the black measured 1.31
     against the pane and 1.11 against the ground, so it did not draw an edge,
     it ate one.

     And the rim is no longer the same all the way round. A uniform bright
     line is a drawn outline; glass has a lit side, because light comes from
     somewhere. Four edges, four values, measured against the pane:

       top    0.62  ->  4.81      the lip where light enters
       left   0.22  ->  1.87
       right  0.10  ->  1.33
       bottom 0.10  ->  1.33      plus the uniform --glas-rand at 2.55

     Written as four one-pixel insets rather than a gradient, and that is the
     only way that works: border-image would give a real gradient but ignores
     border-radius and would square every corner. Offset insets follow the
     radius. */
  --glas-glanz:
    inset 0  1px 0 rgba(255, 255, 255, 0.62),
    inset  1px 0 0 rgba(255, 255, 255, 0.22),
    inset -1px 0 0 rgba(255, 255, 255, 0.10),
    inset 0 -1px 0 rgba(255, 255, 255, 0.10);

  /* TIGHT, NOT HAZY. 0 12px 34px at 0.42 was a cloud under every card, and a
     cloud is the opposite of clean — it blurs the very edge the rim just
     sharpened. A pane this thin casts a short shadow; the separation comes
     from the rim, the shadow only says "above". */
  --glas-schatten: 0 4px 16px -6px rgba(0, 0, 0, 0.55);

  /* The veil over the page photo. This number IS the contrast budget for
     every pane on the page: it bounds how bright the ground behind a pane can
     get, and a thin film has no other defence. Lower it and the text on every
     pane in the app gets darker backing — measure again, do not estimate.

     The colour wash on top of it is the other half. A veil alone turns the
     photo to grey-black and the glass has nothing to show; the brand mesh
     puts hue back WITHOUT putting luminance back, which is exactly what a
     film needs behind it. */
  --glas-schleier: rgba(24, 32, 28, 0.86);

  /* DEEP hues, not the signature ones, and that is the measurement talking.
     The brand lime at 0.22 over a near-black veil lifted the ground far more
     than it looked like it would — muted text fell to 2.96, well under AA.
     A saturated colour is simply much brighter than near-black, so in a dark
     theme the ground cannot be both dark and brightly coloured. lime-900,
     a deep sky and a deep gold carry the same hue at a fraction of the
     luminance: 0.42 alpha of those costs less than 0.22 of the bright ones
     and shows more colour. */
  --glas-wash:
    radial-gradient(62% 48% at 12% 8%,  rgba(4, 73, 42, 0.42), transparent 70%),
    radial-gradient(54% 46% at 88% 14%, rgba(7, 89, 133, 0.42), transparent 70%),
    radial-gradient(66% 56% at 50% 96%, rgba(107, 74, 3, 0.42), transparent 72%);
  --glas-grundblur: 54px;

  /* MUTED TEXT IS LIGHTER ON GLASS, and this is the one place where glass
     touches the type scale. #97A49D was measured against a near-black card;
     on a lifted pane over a coloured ground it reads 3.27 and fails. The
     answer is not less colour, it is the reversal the header already makes
     over the photo (--color-fg-muted: #A7B3AC there) — when the surface
     changes, the type token changes with it. Measured: 5.11 and 3.55. */
  --glas-muted:  #C3CBC6;
  --glas-subtle: #A9B0AC;
}

:root[data-glass='an'][data-theme='light'] {
  --glas-flaeche:  rgba(255, 255, 255, 0.68);
  --glas-hoch:     rgba(255, 255, 255, 0.82);
  --glas-fond:     rgba(38, 33, 25, 0.12);
  --glas-stufe:    rgba(38, 33, 25, 0.07);
  --glas-dimm:     rgba(38, 33, 25, 0.32);
  /* THE RIM FLIPS, and this is the finding that explains why light glass
     looked soft. A white hairline on a near-white pane is not a hairline:
     measured, white 0.60 reads 1.10 against its own pane and white 0.85 only
     1.15. There was no edge — the panes ended by fading out.

     A dark one works, and lands exactly where the opaque light theme already
     puts its borders (1.56 against a card): warm dark at 0.22 measures 1.55.
     Warm rather than neutral for the same reason the shadows are warm here —
     a grey line on warm paper reads as dirt. */
  --glas-rand:     rgba(38, 33, 25, 0.22);
  --glas-rand-hell: rgba(38, 33, 25, 0.34);

  /* Inside the dark rim sits a bright lip — the classic glass edge: a line
     that cuts, a highlight that lifts. It is worth only 1.15 against the pane
     on its own, which is why it is a highlight and not the edge; the rim
     above does that job now. The bottom keeps a warm shade: here the pane
     really does sit on something brighter than itself. */
  --glas-glanz:
    inset 0  1px 0 rgba(255, 255, 255, 0.85),
    inset  1px 0 0 rgba(255, 255, 255, 0.45),
    inset -1px 0 0 rgba(38, 33, 25, 0.05),
    inset 0 -1px 0 rgba(38, 33, 25, 0.07);
  --glas-schatten: 0 4px 14px -6px rgba(38, 33, 25, 0.22);

  --glas-schleier: rgba(243, 239, 230, 0.86);

  /* The other way round here: on a bright ground the saturated colours are
     DARKER than the veil, so they cost nothing and can stay the signature
     tones. Measured at 0.16: muted text 6.81. */
  --glas-wash:
    radial-gradient(62% 48% at 12% 8%,  rgba(0, 168, 90, 0.16), transparent 70%),
    radial-gradient(54% 46% at 88% 14%, rgba(2, 132, 199, 0.16), transparent 70%),
    radial-gradient(66% 56% at 50% 96%, rgba(200, 138, 5, 0.16), transparent 72%);

  /* Nothing to raise: dark type on a light pane keeps its numbers. */
  --glas-muted:  var(--paper-600);
  --glas-subtle: var(--paper-500);
}

/* ==========================================================================
   2 · Something to look through
   The photo is already there for the stage (--hero-bild, one file per theme).
   Here it becomes the ground for the WHOLE page, so the glass has depth
   wherever it floats — including inside a game, where the stage is gone.
   ========================================================================== */

:root[data-glass='an'] { background-color: var(--color-bg); }

/* Body goes transparent so the fixed layer below is visible through it. The
   page colour moved up to <html> in the line above, or a reload would flash
   the photo against nothing. */
:root[data-glass='an'] body,
:root[data-glass='an'] body.im-spiel,
:root[data-glass='an'] #game-view,
:root[data-glass='an'] .view { background-color: transparent; }

:root[data-glass='an'] body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image: var(--hero-bild, url('../assets/hero-bg.jpg'));
  background-size: cover;
  background-position: center 22%;
  /* scale() because blur() eats its own edges: without it a soft transparent
     border runs all the way round the viewport. */
  filter: blur(var(--glas-grundblur)) saturate(115%);
  transform: scale(1.15);
  pointer-events: none;
}

/* The veil, as its own layer rather than mixed into the filter — it has to
   sit ON the blurred photo, not be blurred with it. */
:root[data-glass='an'] body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--glas-wash), var(--glas-schleier);
  pointer-events: none;
}

/* THE STAGE KEEPS ITS OWN SHARP PHOTO. That picture is the brand, and a
   blurred stadium is no stadium — so glass does not touch it. Exactly ONE
   stop of its scrim changes: the last one was an opaque var(--color-bg),
   which would lay a solid band straight across the page at the very line
   where the fixed ground takes over. It ends in the veil instead and the two
   meet at the same colour, so the seam disappears.

   Every other stop is copied verbatim from rivalz-layout.css. That
   duplication is deliberate and it is the smaller evil: the alternative is a
   second variable threaded through a gradient that has been measured stop by
   stop for the legibility of the wordmark. Anyone changing the scrim there
   changes it here. */
:root[data-glass='an'] .stage__backdrop::after {
  background: linear-gradient(to bottom,
    rgba(15, 22, 19, 0.40) 0%,
    rgba(15, 22, 19, 0.12) 18%,
    rgba(15, 22, 19, 0.20) 32%,
    rgba(24, 32, 28, 0.70) 46%,
    rgba(24, 32, 28, 0.86) 62%,
    rgba(24, 32, 28, 0.88) 82%,
    var(--glas-schleier) 100%);
}
:root[data-glass='an'][data-theme='light'] .stage__backdrop::after {
  background: linear-gradient(to bottom,
    rgba(243, 239, 230, 0.52) 0%,
    rgba(243, 239, 230, 0.22) 24%,
    rgba(243, 239, 230, 0.16) 48%,
    rgba(243, 239, 230, 0.50) 76%,
    rgba(243, 239, 230, 0.88) 92%,
    var(--glas-schleier) 100%);
}

/* ---------- Die Naht unter der Buehne ------------------------------------

   Der Schleier am Ende des Verlaufs trifft die Farbe des Grundes genau — und
   trotzdem stand dort eine harte Kante quer ueber den Bildschirm. Gemeldet
   mit Bild.

   DER SCHLEIER WAR NIE DAS PROBLEM, das BILD war es. Ueber der Kante liegt
   das SCHARFE Foto der Buehne, darunter dasselbe Foto VERWISCHT als Grund
   der Seite. Zwei verschiedene Bilder in derselben Farbe stossen aneinander;
   eine Farbangleichung kann daran nichts aendern, weil der Unterschied die
   Zeichnung ist, nicht der Ton. Ohne Glas gibt es die Kante deshalb auch
   nicht — dort ist unter der Buehne eine glatte Flaeche.

   Also wird das scharfe Bild ausgeblendet, statt abgeschnitten: Nach unten
   loest es sich auf, und der verwischte Grund kommt darunter hervor. Das ist
   eine echte Ueberblendung zwischen den zwei Fassungen desselben Fotos.

   SIE BRAUCHT ANLAUF, und den gibt es auf der Buehne nicht: Gemessen endet
   ihr Inhalt bei 93 % der Bildhoehe, es bleiben 50 px. Eine Ausblendung
   darin waere so kurz, dass sie selbst wie eine Kante aussieht — und laenger
   angesetzt liefe sie in die Kacheln.

   Deshalb wird der KLIPPRAHMEN nach unten verlaengert. `.stage__bg` traegt
   das overflow:hidden; 110 px mehr geben der Ausblendung Platz unterhalb der
   Buehne, wo nichts steht ausser dem Abstand und dem Laufband. Das Band ist
   durchscheinend, das auslaufende Foto dahinter ist dort Absicht: Es fuehrt
   die Buehne weiter, statt sie abzuschneiden.

   z-index: -1 steht schon an .stage__bg — das verlaengerte Stueck bleibt
   also hinter allem, was darunter folgt. */
:root[data-glass='an'] .stage__bg { bottom: -110px; }
:root[data-glass='an'] .stage__backdrop {
  /* In PIXELN vom unteren Rand, nicht in Prozent: Die Buehne ist auf einem
     Telefon halb so hoch wie auf einem Rechner, und eine Prozentangabe waere
     dort eine ganz andere Strecke. 140 px beginnen 30 px ueber der
     Buehnenkante — also unterhalb des Inhalts, der 50 px vorher endet. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 140px), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 140px), transparent 100%);
}

/* ==========================================================================
   3 · The panes
   --------------------------------------------------------------------------
   Deliberately the CONTAINERS, not every surface. Apple puts glass on the
   floating layer — bars, sheets, controls, cards — and leaves what sits
   inside them alone. Everything nested inherits the parent's frost through
   its own translucency and needs no pane of its own; see the third rule,
   which takes it away again where panes do end up stacked. That rule is why
   the list may be generous: `:is()` collapses the cross product into one
   selector, so "no pane inside a pane" costs one line instead of n².

   THE BLUR IS SPLIT OFF FROM THE FILM, and that is a measurement, not tidiness.
   38 elements on the landing page carried a backdrop-filter, which is a real
   bill on a mid-range phone — and for almost all of them it bought NOTHING.
   Checked rather than assumed: a catalogue card was asked what lies behind it
   and the answer was zero elements. What is behind a stationary pane is the
   page ground, and the page ground is ALREADY blurred at 54px. Compared side
   by side with the blur removed, the cards are indistinguishable.

   So blur goes only where something sharp can pass behind a pane: the fixed
   tab bar, a dialog, a toast. Everything else keeps saturate(), which is the
   half you can actually see — it is what makes the colours behind the film
   carry.

   THE COUPLING THIS CREATES, written down because it is invisible: the
   stationary panes rely on --glas-grundblur doing the blurring for them.
   Drop the fixed photo or set that to 0 and they will show sharp content
   through. The blur did not move by accident; it moved because the ground
   already does it.
   ========================================================================== */

/* The film — every pane, floating or not. */
:root[data-glass='an'] :is(
  .card, .game-card, .filter, .statband__item, .step, .ctaband,
  .marquee, .set-row, .spielleiste,
  #game-view .card, .cp-card, .cp-archive, .cp-week, .cp-hint-shop,
  .cmp-out, .cmp-duo-seat, .cmp-bilanz-kasten, .cmp-kette-row,
  .kb-tafel, .kb-karte, .kb-kombos, .kb-kasse,
  .liga-karte, .liga-duell, .liga-zeile, .liga-fordern,
  .rate-akte, .rate-reihe, .m11-kopf, .rank-list, .erf-karte,
  .impo-karte, .quiz-antwort, .kar-kennzahl, .kar-tabellenrahmen,
  .herkunft-karte, .spielinfo-karte, .avatar-karte, .kal, .rm-karte,
  .profile-stat-box, .profile-best, .spiel-archivband, .archivtag, .sportkachel,
  .tabbar, .modal, .toast
) {
  background-color: var(--glas-flaeche);
  border-color: var(--glas-rand);
  box-shadow: var(--glas-glanz), var(--glas-schatten);

  /* INSIDE A PANE, A SURFACE IS A TINT — and it goes AWAY from the page,
     not towards it. This is the rule the class list above cannot express,
     because the things it applies to have no name in common: a letter cell,
     a mode button, a text field, a table row, a shop chip. They ask for
     --card or --panel like everything else, and section 4 answered with the
     film. So three of them inside a pane meant three films, and white
     multiplies: measured over the ten games, 33 such stacks, up to 0.44
     total white. Muted text on the ranking rows read 2.59, on their buttons
     2.08 — under AA in a game that had been fine a level up.

     The tokens are therefore re-bound HERE, on the pane, and inheritance
     carries them down. No list, no cross product, and the next surface
     somebody adds is right without being named.

     THE DIRECTION IS THE MEASUREMENT, and it is not what it looks like.
     A pane lifts because it is a light film over a dark ground; the reflex
     is that a surface on top of it lifts again. It cannot: the text is
     light too, so every further film eats the contrast that carries it.
     Away from the text is free — and better than free. Measured on the
     brightest ground behind a pane:

                                    dark            light
       pane                      T 8.21 M 5.56   T 16.32 M 7.00
       one step                  T 9.42 M 6.38   T 14.21 M 6.10
       three steps nested        T 11.64 M 7.89  T 11.08 M 4.75
       the recess (--glas-fond)  T 10.71 M 7.26  T 12.96 M 5.56

     The step is 1.14 in both themes, against 1.08 dark and 1.29 light in
     the opaque ones — the same quiet move, now in one direction for both.
     The worst case anywhere is light, three deep, muted at 4.75. */
  --card:                 var(--glas-stufe);
  --panel:                var(--glas-stufe);
  --color-surface:        var(--glas-stufe);
  --color-surface-raised: var(--glas-stufe);
  --color-surface-hover:  var(--glas-stufe);
  --color-bg-inset:       var(--glas-fond);
}

/* The one pane that paints itself from --card rather than from the rule
   above, because styles.css reaches it through an id: (1,1,0) beats the
   (0,3,0) of :root[data-glass] :is(...). Without this line .game-card would
   read the tint it just declared for its own children and the main surface
   of every single game would lose its film. */
:root[data-glass='an'] #game-view .game-card {
  background-color: var(--glas-flaeche);
  border-color: var(--glas-rand);
}

/* Saturation for the stationary ones. NOT on .spielleiste — see below. */
:root[data-glass='an'] :is(
  .card, .game-card, .filter, .statband__item, .step, .ctaband, .marquee, .set-row,
  #game-view .card, .cp-card, .cp-archive, .cp-week, .cp-hint-shop,
  .cmp-out, .cmp-duo-seat, .cmp-bilanz-kasten, .cmp-kette-row,
  .kb-tafel, .kb-karte, .kb-kombos, .kb-kasse,
  .liga-karte, .liga-duell, .liga-zeile, .liga-fordern,
  .rate-akte, .rate-reihe, .m11-kopf, .rank-list, .erf-karte,
  .impo-karte, .quiz-antwort, .kar-kennzahl, .kar-tabellenrahmen,
  .herkunft-karte, .spielinfo-karte, .avatar-karte, .kal, .rm-karte,
  .profile-stat-box, .profile-best, .spiel-archivband, .archivtag, .sportkachel
) {
  -webkit-backdrop-filter: saturate(var(--glas-saett));
  backdrop-filter: saturate(var(--glas-saett));
}

/* And the full pane for the floating layer, where content really does pass
   behind. .tabbar is position:fixed, .modal and .toast lie over the page. */
:root[data-glass='an'] :is(.tabbar, .modal, .toast) {
  -webkit-backdrop-filter: blur(var(--glas-blur)) saturate(var(--glas-saett));
  backdrop-filter: blur(var(--glas-blur)) saturate(var(--glas-saett));
}

/* NO backdrop-filter of any kind on .spielleiste, and none on .header — and
   this is a rule from rivalz-layout.css, not a preference. Both are
   position:sticky, and the comment at .header records what that costs:
   Chromium paints the ENTIRE DOCUMENT black whenever the page loads already
   scrolled, and declaring blur(0) up front does not help — the property has
   to be absent. The fixed .tabbar is not affected and keeps its glass, which
   is exactly the split that comment already describes.

   The pills INSIDE the sticky header are a different matter: they are
   children, not the sticky box itself, and they have carried backdrop-filter
   since the light-mode rebuild. */

/* No pane inside a pane. A second backdrop-filter over an already frosted
   surface blurs nothing new — the pane behind it is flat already — and only
   stacks alpha until the whole thing turns to mud. What is left is the tint,
   which is what an inner facet should be. */
:root[data-glass='an'] :is(
  .card, .game-card, .filter, .statband__item, .step, .ctaband,
  .marquee, .set-row, .spielleiste,
  #game-view .card, .cp-card, .cp-archive, .cp-week, .cp-hint-shop,
  .cmp-out, .cmp-duo-seat, .cmp-bilanz-kasten, .cmp-kette-row,
  .kb-tafel, .kb-karte, .kb-kombos, .kb-kasse,
  .liga-karte, .liga-duell, .liga-zeile, .liga-fordern,
  .rate-akte, .rate-reihe, .m11-kopf, .rank-list, .erf-karte,
  .impo-karte, .quiz-antwort, .kar-kennzahl, .kar-tabellenrahmen,
  .herkunft-karte, .spielinfo-karte, .avatar-karte, .kal, .rm-karte,
  .profile-stat-box, .profile-best, .spiel-archivband, .archivtag, .sportkachel,
  .tabbar, .modal, .toast
) :is(
  .card, .game-card, .filter, .statband__item, .step, .ctaband,
  .marquee, .set-row, .spielleiste,
  #game-view .card, .cp-card, .cp-archive, .cp-week, .cp-hint-shop,
  .cmp-out, .cmp-duo-seat, .cmp-bilanz-kasten, .cmp-kette-row,
  .kb-tafel, .kb-karte, .kb-kombos, .kb-kasse,
  .liga-karte, .liga-duell, .liga-zeile, .liga-fordern,
  .rate-akte, .rate-reihe, .m11-kopf, .rank-list, .erf-karte,
  .impo-karte, .quiz-antwort, .kar-kennzahl, .kar-tabellenrahmen,
  .herkunft-karte, .spielinfo-karte, .avatar-karte, .kal, .rm-karte,
  .profile-stat-box, .profile-best, .spiel-archivband, .archivtag, .sportkachel,
  .tabbar, .modal, .toast
) {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  /* One step per level, the same step every other surface inside a pane
     takes — it used to be --glas-fond here and --glas-fond is the RECESS,
     a deeper thing than "one level in". Whether a surface happens to carry
     a name from the list above must not decide how deep it sits. It keeps
     its rim, which is what still marks it as a pane rather than a fill. */
  background-color: var(--glas-stufe);
  box-shadow: var(--glas-glanz);
}

/* ---- Die Kachel ist EINE Scheibe, nicht zwei Hälften --------------------
   A catalogue tile was reading as two things stacked: an opaque black picture
   box on top, a glass body underneath, and a hard line where they met. That
   line is the single most unclean thing on the page — a pane does not change
   material halfway down.

   .cover carries `background: var(--c2)` — the scene's own base colour, set
   per game as an inline custom property (#060907 for fifteen of sixteen
   tiles, #000 for one). Made translucent it stops being a lid and becomes
   part of the pane: the drawing floats on the same glass as the text below
   it, and the seam is gone.

   WHAT THAT COSTS THE DRAWING, measured on the brightest ground a tile can
   sit on rather than guessed — and THE ANSWER IS NOT THE SAME IN BOTH THEMES,
   which is the whole reason there are two numbers here. The base is dark in
   both; what changes is what shows through it. In the dark theme that is a
   dark pane, so the base stays dark and the drawing barely notices. In the
   light theme it is a pane at luminance 0.89, and the same alpha turns the
   picture box into mid grey.

   Contrast of the scene's strokes against their own base:

     dark     opaque   0.75   0.65   0.60   0.45
       lime    11.9    10.6   10.0    9.7    8.6
       gold    13.7    12.2   11.5   11.1    9.9

     light    opaque   0.92   0.85   0.75   0.60
       lime    11.9    10.2    8.4    5.9    3.4
       gold    13.7    11.8    9.6    6.8    3.9

   Light at 0.6 would have put the brand lime at 3.4 on the artwork of every
   tile in the catalogue — the seam softened and the picture flattened with
   it. 0.85 there, 0.6 here: both land the drawing above 8, which is where it
   was designed to live. The faint grey the scenes use for depth drops from
   2.5 to 2.0 in the dark theme, and that one is supposed to be barely there.

   color-mix() rather than a fixed rgba, so each tile keeps ITS OWN base
   colour instead of all of them getting one. Where color-mix is missing the
   declaration is dropped and the opaque original applies — which is the old
   look, not a broken one. */
:root[data-glass='an'] .cover {
  background: color-mix(in srgb, var(--c2, #060907) 60%, transparent);
}
:root[data-glass='an'][data-theme='light'] .cover {
  background: color-mix(in srgb, var(--c2, #060907) 85%, transparent);
}

/* Und der Schleier darüber endete in Fast-Schwarz (0.95), also genau an der
   Nahtstelle wieder undurchsichtig. Er darf bleiben — die Abzeichen auf dem
   Bild brauchen ihn — aber er läuft jetzt in die Scheibe aus statt in eine
   schwarze Kante. */
:root[data-glass='an'] .cover::after {
  background: linear-gradient(to top,
    rgba(4, 7, 6, 0.62) 0%, rgba(4, 7, 6, 0.40) 44%, transparent 80%);
}
:root[data-glass='an'][data-theme='light'] .cover::after {
  background: linear-gradient(to top,
    rgba(4, 7, 6, 0.50) 0%, rgba(4, 7, 6, 0.30) 44%, transparent 80%);
}

/* ==========================================================================
   4 · The tokens the rest of the app already uses
   --------------------------------------------------------------------------
   Everything not in the list above still asks for --color-surface or --card
   and gets a translucent answer, so it frosts through whatever pane it sits
   on. One redefinition here reaches the roughly 320 rules that use them.
   ========================================================================== */

:root[data-glass='an'] {
  --color-surface:        var(--glas-flaeche);
  --color-surface-raised: var(--glas-hoch);
  --color-surface-hover:  var(--glas-hoch);
  --color-bg-subtle:      transparent;
  --color-bg-inset:       var(--glas-fond);
  --color-border:         var(--glas-rand);
  --color-border-strong:  var(--glas-rand-hell);

  /* Siehe --glas-muted: die Typografie folgt der Flaeche, auf der sie liegt. */
  --color-fg-muted:       var(--glas-muted);
  --color-fg-subtle:      var(--glas-subtle);

  --glass-bg:     var(--glas-flaeche);
  --glass-border: var(--glas-rand);

  /* The game palette in styles.css. Same names, translucent values — the
     comment there says the names stayed and only the values were swapped
     when the app went dark, and this is the third time that holds. */
  --card:  var(--glas-flaeche);
  --panel: var(--glas-hoch);
  --line:  var(--glas-rand);
  --muted: var(--glas-muted);
}

/* The mesh behind the sections would sit between the photo and the glass and
   grey the picture out. The photo is the depth now. */
:root[data-glass='an'] { --grad-mesh: none; }

/* WHAT ALREADY FLOATS ON THE PHOTO IS LEFT ALONE. The header's pills and the
   hub tiles have been glass since the light-mode rebuild — dark glass with
   light type in the dark theme, the other way round in the light one — and
   they sit on the stage's SHARP photo, which the veil does not cover. The
   light film measured for the veiled ground would be unreadable there: grey
   type on an open sunset sky. So they are not in the list above, and the
   rules in rivalz-layout.css keep working untouched.

   What does change is the scrolled state. Those rules hang off
   .header:not(.is-stuck), because once the bar detached it used to carry the
   page colour — white in the light theme, and dark glass on white were the
   "forgotten grey lumps" the comment there describes. In glass mode there is
   no page colour to fall back to: the photo runs the whole way down, so the
   bar is over the picture at every scroll position and keeps the treatment it
   has at the top. The values are copied from that rule rather than derived,
   which is three numbers in one place; the alternative was a media-query-like
   split of a rule that reads clearly as it stands. */
:root[data-glass='an'] .header.is-stuck {
  background-color: transparent;
  --color-fg-muted: #A7B3AC;
}
:root[data-glass='an'] .header.is-stuck .navpill,
:root[data-glass='an'] .header.is-stuck .langswitch,
:root[data-glass='an'] .header.is-stuck .iconbtn {
  background: rgba(15, 22, 19, 0.55);
  border-color: rgba(255, 255, 255, 0.14);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);
}
:root[data-glass='an'][data-theme='light'] .header.is-stuck { --color-fg-muted: var(--paper-600); }
:root[data-glass='an'][data-theme='light'] .header.is-stuck .navpill,
:root[data-glass='an'][data-theme='light'] .header.is-stuck .langswitch,
:root[data-glass='an'][data-theme='light'] .header.is-stuck .iconbtn {
  background: rgba(255, 255, 255, 0.70);
  border-color: rgba(38, 33, 25, 0.12);
}

/* A DIALOG BLURS THE PAGE, AND IT IS THE OVERLAY THAT DOES IT — not the card
   inside it. This is the one place where the split in section 3 ("blur only
   where something sharp can pass behind a pane") has to be read the other way
   round: behind a dialog the whole page passes, sharp, and it does not scroll
   past — it just sits there being readable.

   That is what it looked like: the avatar editor showed the profile through
   itself, name, level and friends list and all. The card is 12 % white and
   the scrim 66 % black, so a third of the page came through, and a third of
   white text on a dark page is still white text.

   Putting the blur on the CARD would have been the smaller change and the
   wrong one: every dialog card would need naming, and a card is not the only
   thing over the scrim. The overlay is the layer that means "behind this is
   out of reach", so it is the layer that takes the page out of focus. The
   scrim then only has to darken, which it already did.

   All four of them, and .modal-overlay makes five. They were four hand-picked
   values before — see the z-index note in styles.css, which is the second
   half of this same bug. */
:root[data-glass='an'] :is(
  .modal-overlay, .avatar-overlay, .herkunft-overlay,
  .spielinfo-overlay, .rm-flaeche
) {
  -webkit-backdrop-filter: blur(var(--glas-blur)) saturate(120%);
  backdrop-filter: blur(var(--glas-blur)) saturate(120%);
}

/* AND THE DIMMER FLIPS WITH THE THEME, which the five raw values could not.
   They were 0.50, 0.60, 0.62, 0.62 and 0.66 of black — five hand-picked
   numbers for one thing, and all five written for the dark theme. Under a
   translucent LIGHT card a two-thirds black dimmer does not dim the page, it
   greys the dialog: measured, the card came out at 198,198,196 and its labels
   at 4.71 — the worst number in the whole feature, and on a sheet that is
   supposed to be paper.

   In a light theme the page is dimmed with a light hand and the blur does the
   separating. Measured over the dimmer, card against dimmer / label on the
   card / a label one level inside it:

     0.20   1.61 / 6.62 / 5.80      0.40   2.25 / 5.91 / 5.20
     0.28   1.83 / 6.33 / 5.56      0.50   2.72 / 5.57 / 4.91
     0.32   1.95 / 6.19 / 5.43      0.66   3.83 / 5.06 / 4.47

   A darker dimmer buys separation and pays for it in the type on the sheet.
   0.32 is the middle, and the separation it gives up is carried by the rim,
   the shadow and the blurred mush behind — three cues the flat scrim never
   had. Dark keeps its two thirds: there the card is a light film and the
   dimmer works with it rather than against it. */
:root[data-glass='an'] :is(
  .modal-overlay, .avatar-overlay, .herkunft-overlay,
  .spielinfo-overlay, .rm-flaeche
) { background-color: var(--glas-dimm); }

/* ==========================================================================
   5 · The switch itself
   --------------------------------------------------------------------------
   The tile is ALWAYS rendered in glass, in every mode — it is the one
   control whose job is to show what it does. A switch that only looks like
   its effect once the effect is on tells you nothing before you press it.
   ========================================================================== */

.glasbtn {
  position: relative;
  width: 44px;
  height: 34px;
  border-radius: 12px;
  display: inline-grid;
  place-items: center;
  overflow: hidden;
  flex: none;
  color: var(--color-fg-muted);
  border: 1px solid rgba(255, 255, 255, 0.22);
  background:
    linear-gradient(135deg,
      rgba(125, 216, 255, 0.30) 0%,
      rgba(255, 255, 255, 0.16) 38%,
      rgba(var(--marke-rgb), 0.24) 74%,
      rgba(255, 197, 61, 0.22) 100%);
  -webkit-backdrop-filter: blur(10px) saturate(180%);
  backdrop-filter: blur(10px) saturate(180%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -1px 0 rgba(0, 0, 0, 0.18),
    0 2px 8px rgba(0, 0, 0, 0.22);
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

/* The sheen: one diagonal highlight sliding across the tile. It is what a
   still picture of glass cannot have and a control can. */
.glasbtn::after {
  content: '';
  position: absolute;
  inset: -40% -120%;
  background: linear-gradient(72deg,
    transparent 42%, rgba(255, 255, 255, 0.55) 50%, transparent 58%);
  transform: translateX(-38%);
  transition: transform var(--dur-slower) var(--ease-out);
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine) {
  .glasbtn:hover { border-color: rgba(255, 255, 255, 0.42); }
  .glasbtn:hover::after { transform: translateX(38%); }
}
.glasbtn:active { transform: scale(0.93); }

.glasbtn__icon {
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
}

/* On — a lime ring plus a lit rim, the same "selected" vocabulary the mode
   buttons use. Off it is a preview; on it is a state. */
.glasbtn[aria-pressed='true'] {
  border-color: var(--color-primary);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(0, 0, 0, 0.18),
    0 0 0 1px rgba(var(--marke-rgb), 0.45),
    0 4px 14px rgba(var(--marke-rgb), 0.28);
}

/* In the header the tile lies on the photo like the icon buttons beside it,
   so its glyph follows the same reversal they do. */
:root[data-theme='light'] .glasbtn { color: var(--paper-800); }
:root[data-theme='light'] .glasbtn__icon { filter: none; }
.header:not(.is-stuck) .glasbtn { color: var(--ink-50); }
:root[data-theme='light'] .header:not(.is-stuck) .glasbtn { color: var(--paper-900); }

/* The same tile in the settings dialog, where it sits in a row of text
   buttons and has to carry a word. */
.glasbtn--breit {
  width: auto;
  height: 32px;
  padding-inline: 0.85rem;
  gap: 0.45rem;
  grid-auto-flow: column;
  font-size: var(--text-xs);
  font-weight: 750;
  letter-spacing: var(--tracking-wide);
}

/* ==========================================================================
   6 · When glass cannot or should not be drawn
   ========================================================================== */

/* Without backdrop-filter the translucency shows the photo unblurred, and
   text over a stadium crowd is unreadable. Opaque surfaces instead — the
   page keeps its photo, the panes go solid, and nothing is lost but the
   frost. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  :root[data-glass='an'] {
    --glas-flaeche: var(--color-bg-subtle, #151D19);
    --glas-hoch:    #202A25;
  }
  :root[data-glass='an'][data-theme='light'] {
    --glas-flaeche: #FFFFFF;
    --glas-hoch:    #FFFFFF;
  }
}

/* An explicit request, and it is about transparency rather than taste: the
   veil and the panes go opaque, the photo stays. */
@media (prefers-reduced-transparency: reduce) {
  :root[data-glass='an'] {
    --glas-blur: 0px;
    --glas-schleier: rgba(15, 22, 19, 0.96);
    --glas-flaeche: rgba(17, 24, 21, 0.96);
    --glas-hoch:    rgba(23, 32, 25, 0.96);
  }
  :root[data-glass='an'][data-theme='light'] {
    --glas-schleier: rgba(243, 239, 230, 0.97);
    --glas-flaeche: rgba(255, 255, 255, 0.97);
    --glas-hoch:    rgba(255, 255, 255, 0.97);
  }
  .glasbtn::after { display: none; }
}

/* DIE LIGA-LISTEN SIND EINE SCHEIBE, NICHT FUENF (28.09.2026).
   Tabelle und Duelle stehen seit dem Umbau als EINE Flaeche mit Haarlinien
   dazwischen, wie in einer Fussball-App. Die Liste oben macht aber jede
   .liga-zeile und jedes .liga-duell zur eigenen Scheibe mit Kante und Glanz —
   im Glas stand die Tabelle damit wieder als Stapel einzelner Karten da. Hier
   wird der Behaelter die Scheibe, und die Zeilen darin sind flach. */
:root[data-glass='an'] #game-view :is(.liga-duelle, .liga-tabelle--form, .liga-tabelle--tage) {
  background-color: var(--glas-flaeche);
  border-color: var(--glas-rand);
  box-shadow: var(--glas-glanz), var(--glas-schatten);
}
:root[data-glass='an'] #game-view :is(.liga-duelle, .liga-tabelle--form, .liga-tabelle--tage) > :is(.liga-duell, .liga-zeile) {
  background-color: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-top-color: var(--glas-rand);
  border-right-color: transparent;
  border-bottom-color: transparent;
}
:root[data-glass='an'] #game-view .liga-duelle > .liga-duell { border-left-color: transparent; }
:root[data-glass='an'] #game-view .liga-duelle > .liga-duell.dran { border-left-color: var(--violet-text); }
:root[data-glass='an'] #game-view .liga-duelle > .liga-duell.gewonnen { border-left-color: var(--correct, #17A65A); }
:root[data-glass='an'] #game-view .liga-duelle > .liga-duell.verloren { border-left-color: var(--rot-text, #FF6B85); }
:root[data-glass='an'] #game-view :is(.liga-tabelle--form, .liga-tabelle--tage) > .liga-zeile.ich { background-color: rgba(var(--marke-rgb), 0.12); }

/* DIE BEDIENREIHE IN DER KOPFLEISTE AM TELEFON (28.09.2026, Ansage des
   Eigentuemers): so hoch wie der Sport-Chip und die Begruessung darunter
   (32 px) statt 44 bis 52. Das Logo bleibt, wie es ist. Die sichtbaren Flaechen
   werden kleiner, die Trefferflaechen nicht: ein unsichtbares ::after legt je
   Knopf wieder 44 px Hoehe darum. Die Reihe steht rechtsbuendig an derselben
   Kante wie der Chip, ohne die Trennlinie links — bei vier kleinen Knoepfen
   neben dem Logo trennte sie nichts mehr. Hier und nicht in layout.css, weil
   .glasbtn erst in dieser Datei entsteht. */
@media (max-width: 560px) {
  .header .header__actions { gap: 8px; padding-left: 0; border-left: 0; }
  .header .langswitch { padding: 2px; height: 32px; align-items: center; }
  .header .langswitch__btn {
    position: relative; min-height: 26px; min-width: 32px; height: 26px;
    padding-inline: 0.45rem; font-size: 0.66rem;
  }
  .header .iconbtn { position: relative; width: 32px; height: 32px; }
  .header .iconbtn svg { width: 17px; height: 17px; }
  .header .glasbtn { width: 38px; height: 32px; border-radius: 10px; }
  .header .langswitch__btn::after,
  .header .iconbtn::after { content: ""; position: absolute; inset: -9px -4px; }
}
