/* Snusee — design tokens. The single source of truth for colour, shape,
 * elevation, spacing and motion. Extracted from REFERENCE IMAGE.png.
 *
 * No component stylesheet may hardcode a colour, radius or duration. If a
 * value is needed and not here, it gets added here first.
 *
 * ============================================================================
 * V4: FILLS AND INKS ARE NOW DIFFERENT THINGS
 * ============================================================================
 *
 * Every pastel in this file was originally used for both -- the same #EE8AA6
 * painted a button and set the text on it. That is why the app measured the
 * way it did: white on the primary gradient came out at 1.86:1 against a
 * 4.5:1 requirement, secondary text at 2.84:1, and three of the four timer
 * digits failed even the relaxed large-text bar. It was also why the whole
 * app read slightly foggy no matter how much light was added to the surfaces:
 * every accent sat in one narrow lightness band, so nothing had anything to
 * be darker than.
 *
 * The fix is a split, not a repaint. THE PASTEL FILLS ARE UNCHANGED --
 * --pink, --mint, --peach, --lavender, --sky and the craving scale are byte
 * for byte what they were. What changed is that anything carrying TEXT or
 * encoding DATA now uses a matching ink one to three steps deeper:
 *
 *   fill              ink (text on that fill / on a light surface)
 *   --pink            --pink-ink, --pink-strong
 *   --lavender        --lavender-ink
 *   --mint            --mint-ink
 *   --peach           --peach-ink
 *   --scale-1..5      --on-scale
 *
 * Every ratio in the comments below was measured against the surface named,
 * not estimated. Do not lighten an ink without re-measuring it.
 *
 * ============================================================================
 * V4: TWO THEMES
 * ============================================================================
 *
 * The stated primary moment for this app is somebody opening it at 2am on day
 * three. Until V4 that person got a full-brightness cream screen in a dark
 * bedroom. There is now a dark set.
 *
 * It is built as DUSK, not as an inversion: the ground is a deep warm plum
 * rather than a neutral black, the pastels stay pastel, and the sea becomes
 * night water with the wake still warm. Inverting a palette this warm produces
 * a cold blue-grey app that shares nothing with the light one.
 *
 * Three states, and all three are handled:
 *   1. bare :root                                   -> light (the default)
 *   2. @media (prefers-color-scheme: dark)          -> dark, unless the user
 *      guarded as :root:not([data-theme="light"])      explicitly chose light
 *   3. :root[data-theme="dark"]                     -> dark, whatever the OS says
 *
 * data-theme is stamped SERVER-SIDE by index.php from the `snusee_theme`
 * cookie. It cannot be done with an inline script: the CSP is script-src
 * 'self' with no 'unsafe-inline', and a deferred module runs after first
 * paint, which would flash a white screen at exactly the person the dark
 * theme exists for.
 *
 * NEVER define a colour only inside the dark blocks. Components read tokens;
 * a token that exists in one theme only renders one theme's text on the
 * other theme's ground.
 */

:root {
  color-scheme: light;

  /* ---- Surfaces ---------------------------------------------------- */
  --cream:      #FDF4E9;
  --cream-deep: #F7E8D8;
  --card:       #FFFCF7;
  --card-sunk:  #FBF2E8;
  --white:      #FFFFFF;

  /* ---- Brand fills -------------------------------------------------- */
  /* Decorative only. Nothing that has to be READ sits on these unaided --
   * see the ink block below. */
  --pink:       #F7A8BC;
  --pink-deep:  #EE8AA6;
  --pink-wash:  #FDEBF0;

  /* ---- Accents: one per timer tile, reused across badges/milestones -- */
  --lavender:   #C9B8E8;
  --mint:       #A8DBC5;
  --peach:      #FFD1A9;
  --sky:        #B8D9F0;

  --lavender-wash: #F0EAFA;
  --mint-wash:     #E6F4EE;
  --peach-wash:    #FFF0E0;
  --sky-wash:      #EAF3FB;

  /* ---- Text: warm brown-grey. Never pure black. --------------------- */
  /* --ink       6.32:1 on --card
   * --ink-soft  4.80:1 or better on EVERY surface in this file (the worst
   *             case is --lavender-wash). It was #A89296 at 2.84:1, which is
   *             the colour almost every secondary string in the app used.
   * --ink-quiet 4.77:1 on --card-sunk. This is what text that used to be
   *             --ink-faint should use.
   * --ink-faint 1.83:1 and therefore DECORATION ONLY -- hairlines, the
   *             not-started marker fill, disabled iconography. If you are
   *             about to set it on a string, you want --ink-quiet. */
  --ink:       #6B5A5E;
  --ink-soft:  #776266;
  --ink-quiet: #7A676A;
  --ink-faint: #C9BAB8;

  --on-pink:   #FFFFFF;
  /* Text and glyphs sitting on the craving scale. 4.55:1 at the worst step
   * (--scale-5), 7.54:1 at the best. The scale itself is untouched. */
  --on-scale:  #4A3A3E;

  /* ---- Brand inks --------------------------------------------------- */
  /* --pink-ink     accent TEXT: links, the active tab, phone numbers, the
   *                hero eyebrow. 5.29:1 on --card, 4.72:1 at its worst
   *                (--pink-wash). Was --pink-deep at 2.33:1.
   * --btn-a/--btn-b the primary button's fill. White on --btn-a is 5.41:1 and
   *                on --btn-b 7.02:1; the old gradient measured 1.86:1 and
   *                2.38:1. These two are FIXED ACROSS BOTH THEMES -- a deep
   *                rose with white on it works on cream and on plum, and the
   *                primary action should not change identity with the OS.
   * --pink-strong  the days digit: 4.95:1 on --pink-wash. */
  --pink-ink:    #AC4868;
  --btn-a:       #AC4868;
  --btn-b:       #94395A;
  --pink-strong: #A8446A;

  /* Digits on a tinted tile. Measured on their own wash:
   * lavender 5.11 · mint 4.57 · peach 4.83. Previously 3.26 / 2.25 / 2.30. */
  --lavender-ink: #6B57A0;
  --mint-ink:     #2F7A5C;
  --peach-ink:    #9C5A18;

  /* ---- State ------------------------------------------------------- */
  /* There is no red token. Not an oversight -- see the scale below. */
  --locked:     #D9D2CE;
  --locked-bg:  #F2EDE9;
  /* Locked badge names were --ink-faint on --locked-bg: 1.61:1, the lowest
   * number in the entire app. 4.88:1 now. A thing you have not earned yet is
   * still a thing you are allowed to read. */
  --locked-ink: #736366;
  --gold:       #F0C674;

  /* ---- Craving intensity: green -> yellow -> peach -> pink ---------- */
  /* Never reaches red. "Veľmi silná" is pink. A person logging their
   * worst moment must not be shown an error colour for telling the truth.
   *
   * V4 left these EXACTLY as they were and darkened the glyph on top
   * (--on-scale) instead. Deepening the ramp itself would have moved the top
   * of it toward red, which is the one thing it must not do. */
  --scale-1: #A8D8A0;
  --scale-2: #CBE0A0;
  --scale-3: #F5D76E;
  --scale-4: #F5A96B;
  --scale-5: #F08C9E;

  /* ---- Sea (V2: the voyage) ---------------------------------------- */
  /* Sits inside the existing palette rather than beside it: the sea is the
   * sky token pushed a little deeper, so the map still reads as the same
   * app and not as a game bolted onto it. */
  --sea:        #B6DCF3;
  --sea-deep:   #8CC3E4;
  --sea-far:    #DCEEFA;
  --sea-foam:   #FFFFFF;
  --sea-route:  #FFFFFF;
  --wake:       #FFF0D2;

  /* V3: the sea had one flat vertical gradient stretched over a 4000px map,
   * which at that height is a single unchanging blue -- the screenshot that
   * started this looked like coloured paper, not water. Water needs three
   * things and no more: depth that repeats, crests that catch light, and
   * sunlight moving across it.
   *
   * --sea-band is the depth, repeated every --sea-band-h rather than stretched,
   * so the eye gets a horizon rhythm however far you scroll. --sea-swell is the
   * crest and trough pair. --sea-glint is sparse foam. The last two ride a
   * transform-animated layer, so the drift is GPU work and not a repaint of a
   * four-thousand-pixel background. */
  --sea-crest:  rgba(255, 255, 255, .22);
  --sea-trough: rgba(108, 168, 205, .10);

  /* The band MUST start and end on the same colour. It repeats, so any
   * difference between 0% and 100% is a hard horizontal seam every 340px --
   * which is what the first attempt looked like, a stack of blue strips. */
  --sea-band-h: 340px;
  --sea-band: linear-gradient(180deg,
      var(--sea)      0%,
      var(--sea-far) 16%,
      var(--sea)     52%,
      var(--sea-deep) 84%,
      var(--sea)    100%);

  /* Two crest lines of unequal spacing per cycle, not one evenly repeated:
   * an even repeat reads as corduroy, and real swell does not have a period
   * you can count.
   *
   * V4 widened the whole cycle from 67px to 96px and softened the crest
   * opacity. At the old spacing, on a 390px phone, the repeat was tight
   * enough that the eye resolved it as ruled paper rather than as water --
   * the exact failure the unequal spacing was meant to avoid, reintroduced by
   * frequency instead of by rhythm. */
  --sea-swell: repeating-linear-gradient(176.5deg,
      rgba(255, 255, 255, 0)   0px,  rgba(255, 255, 255, 0)   21px,
      var(--sea-crest)        21px,  var(--sea-crest)         23px,
      rgba(255, 255, 255, 0)  23px,  rgba(255, 255, 255, 0)   42px,
      var(--sea-trough)       42px,  var(--sea-trough)        45px,
      rgba(255, 255, 255, 0)  45px,  rgba(255, 255, 255, 0)   63px,
      var(--sea-crest)        63px,  var(--sea-crest)       64.5px,
      rgba(255, 255, 255, 0) 64.5px, rgba(255, 255, 255, 0)   96px);

  --sea-glint: radial-gradient(circle at 22% 26%,
      rgba(255, 255, 255, .55) 0 1.6px, rgba(255, 255, 255, 0) 2.6px);

  --sea-sun: radial-gradient(130% 62% at 74% -8%,
      rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0) 62%);

  /* ---- Charts (V2: statistics) ------------------------------------- */
  /* Chosen by running the palette validator against the card surface
   * (#FFFCF7), not by eye. The display pastels are too light and too low in
   * chroma to encode data -- --mint at L .85 reads as grey next to a bar --
   * so these are deeper steps of the SAME hues, used ONLY inside charts.
   *
   * --chart-bar is the single-series colour. Hours, weekdays, triggers and
   * attempts are all one series each, so every bar in a chart is the same
   * colour and identity comes from its label. Colouring bars by rank would
   * repaint them whenever the ranking changed.
   *
   * --chart-good / --chart-bad are the only categorical pair in the app
   * (odolal vs zlyhanie). Every use still ships a visible text label and a
   * number -- never colour alone -- but V4 deepened all three so they also
   * clear 3:1 against the card as graphical objects. They were 2.85, 2.68
   * and 2.90; they are now 5.05, 5.28 and 4.05.
   *
   * Still no red: --chart-bad is the peach hue the craving scale already ends
   * on, several steps deeper. */
  --chart-bar:  #C9557A;
  --chart-good: #2F7A5C;
  --chart-bad:  #9C5A18;
  --chart-grid: #EFE4DA;

  /* ---- Symptom timeline (V3: the health section) -------------------- */
  /* Reuses the craving scale's hues one step deeper, for the same reason the
   * chart tokens exist: the display pastels do not survive being a 10px bar.
   * The scale still stops before red -- a symptom at its worst is a thing the
   * body is doing on schedule, not an error.
   *
   * V4 deepened every step so the track clears 3:1 against the card as a
   * graphical object (WCAG 1.4.11): ahead 3.05 · rise 3.10 · peak 3.18 ·
   * fall 3.46 · done 3.26. The phase word and the meta sentence still carry
   * the meaning in text, so the bar is supplementary -- but a supplementary
   * cue nobody can see is not a cue. */
  --sym-ahead: #9E8E90;
  --sym-rise:  #BE861E;
  --sym-peak:  #E0687E;
  --sym-fall:  #4F9670;
  --sym-done:  #4E9B79;

  /* ---- Gradients --------------------------------------------------- */
  /* The primary action. Deep rose, white label, identical in both themes. */
  --grad-primary:  linear-gradient(180deg, var(--btn-a) 0%, var(--btn-b) 100%);
  --grad-page:     linear-gradient(180deg, var(--cream) 0%, var(--cream-deep) 100%);
  --grad-progress: linear-gradient(90deg, var(--pink) 0%, var(--peach) 100%);
  --grad-sea:      linear-gradient(180deg, var(--sea-far) 0%, var(--sea) 28%, var(--sea-deep) 100%);

  /* V3. Every card used a single flat fill, which is why the whole app read
   * as paper cut-outs: with no lighting at all a rounded rectangle has no
   * volume, and adding a bigger drop shadow only makes it a flatter card that
   * floats higher. The gradient is the light falling ACROSS the card; the
   * inset highlight in --shadow-edge is the lit top rim. */
  /* The page, with light on it. A flat cream wash gives a cream card nothing
   * to be lighter than; these three blooms are what the cards sit on. Shared
   * by .motif and the SOS takeover, which covers the motif entirely and would
   * otherwise be the one flat screen in the app. */
  --grad-page-lit:
    radial-gradient(52% 34% at 12% 4%,   var(--pink-wash), transparent 70%),
    radial-gradient(46% 30% at 92% 32%,  var(--lavender-wash), transparent 72%),
    radial-gradient(60% 36% at 50% 104%, var(--peach-wash), transparent 74%),
    var(--grad-page);

  --grad-card:  linear-gradient(168deg, var(--white) 0%, var(--card) 44%, var(--card-sunk) 100%);
  --grad-hero:  linear-gradient(150deg, var(--pink-wash) 0%, var(--card) 52%, var(--lavender-wash) 100%);
  --grad-sunk:  linear-gradient(180deg, var(--card-sunk) 0%, var(--card) 100%);

  /* ---- Shape ------------------------------------------------------- */
  --radius-card:  28px;
  --radius-tile:  20px;
  --radius-input: 16px;
  --radius-chip:  999px;
  --radius-btn:   999px;

  /* ---- Elevation: pink-tinted, never grey --------------------------- */
  --shadow-soft:  0 8px 24px rgba(214, 164, 178, .18);
  --shadow-lift:  0 4px 12px rgba(214, 164, 178, .12);
  --shadow-btn:   0 6px 16px rgba(148, 57, 90, .30);
  --shadow-press: 0 2px 6px  rgba(214, 164, 178, .20);
  --shadow-inset: inset 0 2px 5px rgba(190, 150, 160, .10);

  /* V3 inner light. --shadow-edge is the pair every raised surface wears: a
   * lit top rim and a hairline ring, both inset. The ring replaces the border
   * a card would otherwise need -- a real border shifts layout by a pixel and
   * has to be subtracted from the padding, an inset ring does neither.
   *
   * --shadow-well is the opposite: a surface the eye should read as CUT INTO
   * the card rather than sitting on it -- progress tracks, inputs, the symptom
   * timelines. Anything holding a value gets the well, anything holding
   * content gets the edge. */
  --shadow-edge:  inset 0 1px 0 rgba(255, 255, 255, .92),
                  inset 0 0 0 1px rgba(214, 164, 178, .13);
  --shadow-well:  inset 0 2px 6px rgba(178, 138, 150, .18),
                  inset 0 -1px 0 rgba(255, 255, 255, .70);
  --shadow-deep:  0 14px 34px rgba(200, 148, 164, .20),
                  0 2px 6px rgba(200, 148, 164, .10);
  /* Sea labels float over water, not over a card, so they carry a cooler
   * shadow -- a pink one over blue reads as a colour mistake. */
  --shadow-label: 0 4px 12px rgba(84, 132, 166, .26),
                  inset 0 1px 0 rgba(255, 255, 255, .95);

  /* The app column's own edge, only drawn once the viewport is wider than the
   * column (see app.css). On a phone there is no edge to draw. */
  --shadow-column: 0 0 0 1px rgba(214, 164, 178, .16),
                   0 24px 60px rgba(180, 140, 152, .16);

  /* ---- Spacing: 4px base ------------------------------------------- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px;

  --screen-pad: 20px;
  --card-pad:   20px;
  --card-gap:   16px;
  --tabbar-h:   66px;

  /* The app is a phone app. On anything wider it is a phone-width column,
   * centred, rather than a set of 1400px-wide lozenges. Every fixed element
   * -- the tab bar, the toast, the offline strip, the sheet, the SOS
   * takeover -- aligns to this same width. */
  --app-max:    480px;

  /* ---- Type -------------------------------------------------------- */
  --font-display: 'Baloo 2', system-ui, -apple-system, sans-serif;
  --font-body:    'Nunito', system-ui, -apple-system, sans-serif;

  /* ---- Motion ------------------------------------------------------ */
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --ease-soft:   cubic-bezier(.4, 0, .2, 1);
  --dur-fast: 140ms;
  --dur-base: 240ms;
  --dur-slow: 420ms;

  /* ---- Layers ------------------------------------------------------ */
  --z-motif: 0;
  --z-content: 1;
  --z-tabbar: 40;
  --z-sheet: 60;
  --z-takeover: 80;
}

/* ==========================================================================
 * DARK — dusk, not inversion
 * ==========================================================================
 *
 * Written once and applied from two selectors. Keep them identical; the only
 * difference is which of "the OS said so" and "the user said so" is being
 * answered. Everything below is a token REDEFINITION -- no component rules
 * live in here, deliberately, so there is exactly one place to look when a
 * colour is wrong in one theme.
 */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    /* Ground: deep warm plum. A neutral #111 under these pastels reads as a
     * different, colder product. */
    --cream:      #17131A;
    --cream-deep: #120F16;
    --card:       #221C27;
    --card-sunk:  #1A1520;
    /* --white is the "lifted" step in --grad-card and the tab bar, not the
     * colour white. Sea foam and the route keep their own tokens. */
    --white:      #2C2532;

    /* Fills stay pastel; the washes become tinted darks. */
    --pink:       #F0A0B8;
    --pink-deep:  #E88AA8;
    --pink-wash:  #33202A;

    --lavender:   #C2AFE6;
    --mint:       #92D3B7;
    --peach:      #F2C08F;
    --sky:        #A6CFEC;

    --lavender-wash: #262135;
    --mint-wash:     #172A24;
    --peach-wash:    #2E2317;
    --sky-wash:      #17242E;

    /* Inks flip. 13.36 · 7.31 · 5.26 against --card. */
    --ink:       #EDE4E9;
    --ink-soft:  #B7A8AF;
    --ink-quiet: #9C8D94;
    --ink-faint: #6E6067;

    --on-pink:   #FFFFFF;
    /* The craving scale is still light in dark mode -- five bright dots are
     * the point of it -- so the glyph on top stays dark. */
    --on-scale:  #4A3A3E;

    /* Accent text lifts; the button keeps its light-mode identity. 8.71:1. */
    --pink-ink:    #F3A6BE;
    --pink-strong: #F3A6BE;

    --lavender-ink: #BFAEEE;
    --mint-ink:     #7FD3AE;
    --peach-ink:    #E7A96A;

    --locked:     #4A4048;
    --locked-bg:  #221D22;
    --locked-ink: #948690;
    --gold:       #F0C674;

    /* Night water. The wake stays warm -- it is the one thing on that screen
     * that is about the user rather than about the sea. */
    --sea:        #1F3A50;
    --sea-deep:   #16293A;
    --sea-far:    #2C516D;
    --sea-foam:   #D6EAF7;
    --sea-route:  #D6EAF7;
    --wake:       #F2D9A6;

    --sea-crest:  rgba(214, 234, 247, .14);
    --sea-trough: rgba(6, 18, 28, .22);

    --sea-glint: radial-gradient(circle at 22% 26%,
        rgba(226, 240, 250, .40) 0 1.6px, rgba(226, 240, 250, 0) 2.6px);

    --sea-sun: radial-gradient(130% 62% at 74% -8%,
        rgba(198, 224, 242, .20) 0%, rgba(198, 224, 242, 0) 62%);

    /* Charts lift to clear the dark card: 6.34 · 8.50 · 7.39. */
    --chart-bar:  #E8809D;
    --chart-good: #6ECBA3;
    --chart-bad:  #E0A059;
    --chart-grid: #362D38;

    --sym-ahead: #7E7078;
    --sym-rise:  #E0A857;
    --sym-peak:  #F08497;
    --sym-fall:  #78C79E;
    --sym-done:  #66BC94;

    /* Elevation in the dark is a black drop plus a lit rim. A pink-tinted
     * shadow on a plum ground is invisible, so the rim does the work of
     * separating a card from what is behind it. */
    --shadow-soft:  0 10px 28px rgba(0, 0, 0, .46);
    --shadow-lift:  0 4px 14px rgba(0, 0, 0, .38);
    --shadow-btn:   0 6px 18px rgba(0, 0, 0, .50);
    --shadow-press: 0 2px 6px  rgba(0, 0, 0, .42);
    --shadow-inset: inset 0 2px 5px rgba(0, 0, 0, .34);

    --shadow-edge:  inset 0 1px 0 rgba(255, 255, 255, .07),
                    inset 0 0 0 1px rgba(255, 255, 255, .075);
    --shadow-well:  inset 0 2px 7px rgba(0, 0, 0, .50),
                    inset 0 -1px 0 rgba(255, 255, 255, .05);
    --shadow-deep:  0 18px 44px rgba(0, 0, 0, .58),
                    0 2px 8px rgba(0, 0, 0, .40);
    --shadow-label: 0 6px 16px rgba(0, 0, 0, .48),
                    inset 0 1px 0 rgba(255, 255, 255, .10);
    --shadow-column: 0 0 0 1px rgba(255, 255, 255, .06),
                     0 24px 60px rgba(0, 0, 0, .55);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --cream:      #17131A;
  --cream-deep: #120F16;
  --card:       #221C27;
  --card-sunk:  #1A1520;
  --white:      #2C2532;

  --pink:       #F0A0B8;
  --pink-deep:  #E88AA8;
  --pink-wash:  #33202A;

  --lavender:   #C2AFE6;
  --mint:       #92D3B7;
  --peach:      #F2C08F;
  --sky:        #A6CFEC;

  --lavender-wash: #262135;
  --mint-wash:     #172A24;
  --peach-wash:    #2E2317;
  --sky-wash:      #17242E;

  --ink:       #EDE4E9;
  --ink-soft:  #B7A8AF;
  --ink-quiet: #9C8D94;
  --ink-faint: #6E6067;

  --on-pink:   #FFFFFF;
  --on-scale:  #4A3A3E;

  --pink-ink:    #F3A6BE;
  --pink-strong: #F3A6BE;

  --lavender-ink: #BFAEEE;
  --mint-ink:     #7FD3AE;
  --peach-ink:    #E7A96A;

  --locked:     #4A4048;
  --locked-bg:  #221D22;
  --locked-ink: #948690;
  --gold:       #F0C674;

  --sea:        #1F3A50;
  --sea-deep:   #16293A;
  --sea-far:    #2C516D;
  --sea-foam:   #D6EAF7;
  --sea-route:  #D6EAF7;
  --wake:       #F2D9A6;

  --sea-crest:  rgba(214, 234, 247, .14);
  --sea-trough: rgba(6, 18, 28, .22);

  --sea-glint: radial-gradient(circle at 22% 26%,
      rgba(226, 240, 250, .40) 0 1.6px, rgba(226, 240, 250, 0) 2.6px);

  --sea-sun: radial-gradient(130% 62% at 74% -8%,
      rgba(198, 224, 242, .20) 0%, rgba(198, 224, 242, 0) 62%);

  --chart-bar:  #E8809D;
  --chart-good: #6ECBA3;
  --chart-bad:  #E0A059;
  --chart-grid: #362D38;

  --sym-ahead: #7E7078;
  --sym-rise:  #E0A857;
  --sym-peak:  #F08497;
  --sym-fall:  #78C79E;
  --sym-done:  #66BC94;

  --shadow-soft:  0 10px 28px rgba(0, 0, 0, .46);
  --shadow-lift:  0 4px 14px rgba(0, 0, 0, .38);
  --shadow-btn:   0 6px 18px rgba(0, 0, 0, .50);
  --shadow-press: 0 2px 6px  rgba(0, 0, 0, .42);
  --shadow-inset: inset 0 2px 5px rgba(0, 0, 0, .34);

  --shadow-edge:  inset 0 1px 0 rgba(255, 255, 255, .07),
                  inset 0 0 0 1px rgba(255, 255, 255, .075);
  --shadow-well:  inset 0 2px 7px rgba(0, 0, 0, .50),
                  inset 0 -1px 0 rgba(255, 255, 255, .05);
  --shadow-deep:  0 18px 44px rgba(0, 0, 0, .58),
                  0 2px 8px rgba(0, 0, 0, .40);
  --shadow-label: 0 6px 16px rgba(0, 0, 0, .48),
                  inset 0 1px 0 rgba(255, 255, 255, .10);
  --shadow-column: 0 0 0 1px rgba(255, 255, 255, .06),
                   0 24px 60px rgba(0, 0, 0, .55);
}

/* Motion is decoration everywhere except the SOS breathing guide, which
 * keeps a working non-animated fallback (its phase label and countdown still
 * update). Nothing here is load-bearing. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
