/* ============================================================================
   ARCADE SKIN
   ----------------------------------------------------------------------------
   Everything here is scoped to [data-skin="arcade"]. Nothing in this file can
   affect the Calm skin, and the two never need to know about each other.

   THE DESIGN BRIEF was "a video game interface designed by Nintendo". That is
   a real, specific look, and it is not "cartoon stickers everywhere". What
   actually makes first-party Nintendo UI feel the way it does:

     1. HARD SHADOWS, NOT SOFT ONES. A 4px offset with zero blur reads as a
        printed sticker or a moulded plastic button. Gaussian blur reads as
        Material Design.
     2. THICK, DARK OUTLINES. Every element is drawn, not merely tinted. This
        is what survives being scaled down to a 5" screen held at arm's length
        across a room.
     3. GEOMETRY WITH NO SMALL RADII. Either fully round or generously
        rounded. Nothing in between; a 4px radius looks like an accident.
     4. SATURATED PRIMARIES ON A BRIGHT GROUND, with the colour doing the
        work and the outline holding it together.
     5. EVERYTHING REACTS. Nothing is inert: buttons depress into their own
        shadow, panels lift, numbers pop.

   WHAT DOES NOT CHANGE: the information architecture, the type scale, the
   touch targets, and the contrast guarantees. Skinning the app is allowed to
   change how it feels. It is not allowed to make the numbers harder to read —
   `bin/check-contrast.php` runs against this file's tokens too.

   The dark variant is not an inversion. Arcade dark is a lit cabinet in a
   dark room: the panels stay bright objects, the GROUND goes near-black, and
   the outlines invert from ink to glow.
   ========================================================================== */

@layer tokens {

  :root[data-skin="arcade"] {
    /* ------------------------------------------------------------ surfaces --
       Light: a warm paper ground with white panels on top.
       Dark:  a near-black cabinet with panels that still read as objects. */
    --surface-0: light-dark(oklch(96.5% 0.022  85), oklch(13%   0.020 265));
    --surface-1: light-dark(oklch(100%  0       0), oklch(21%   0.026 265));
    --surface-2: light-dark(oklch(95%   0.030  85), oklch(26.5% 0.030 265));
    --surface-3: light-dark(oklch(91%   0.045  80), oklch(32%   0.034 265));

    --surface-chrome: light-dark(oklch(100% 0 0 / 0.94), oklch(16% 0.022 265 / 0.94));
    --scrim:          light-dark(oklch(28% 0.06 265 / 0.42), oklch(0% 0 0 / 0.66));

    /* ---------------------------------------------------------------- ink --
       The outline colour. This is the single most load-bearing value in the
       skin: it is the border on every panel, button and chip, and it is what
       makes the whole thing read as drawn rather than as a gradient. */
    --ink: light-dark(oklch(24% 0.045 265), oklch(76% 0.055 265));

    /* --------------------------------------------------------------- text --
       Solved against surface-0/1/2 in both modes, same as the Calm skin. */
    --text-primary:   light-dark(oklch(22%   0.040 265), oklch(97%   0.008 260));
    --text-secondary: light-dark(oklch(42%   0.038 265), oklch(78%   0.020 262));
    --text-tertiary:  light-dark(oklch(50%   0.035 265), oklch(66%   0.024 264));
    --text-on-accent: light-dark(oklch(100%  0     0  ), oklch(14%   0.020 265));

    --border-subtle: light-dark(oklch(24% 0.045 265 / 0.16), oklch(76% 0.055 265 / 0.22));
    --border-strong: light-dark(oklch(24% 0.045 265), oklch(76% 0.055 265));

    /* ------------------------------------------------------------- accent --
       A confident game-UI blue-violet. Brighter and more saturated than Calm,
       which is the point, but still solved for AA as body text. */
    --accent:        light-dark(oklch(52%   0.235 272), oklch(76%   0.170 274));
    --accent-hover:  light-dark(oklch(46%   0.240 272), oklch(82%   0.160 274));
    --accent-subtle: light-dark(oklch(93%   0.070 272), oklch(33%   0.090 272));
    --accent-ring:   light-dark(oklch(52% 0.235 272 / 0.34), oklch(76% 0.170 274 / 0.40));

    /* ----------------------------------------------------------- semantic --
       Louder than Calm across the board. Same contract: each foreground is
       solved against surface-1 AND its own -subtle background. */
    --success:        light-dark(oklch(50%   0.180 148), oklch(78%   0.165 152));
    --success-subtle: light-dark(oklch(94.5% 0.070 148), oklch(30%   0.080 150));
    --warn:           light-dark(oklch(52%   0.170  62), oklch(83%   0.160  75));
    --warn-subtle:    light-dark(oklch(95%   0.085  70), oklch(32%   0.080  68));
    --danger:         light-dark(oklch(53%   0.225  25), oklch(74%   0.180  25));
    --danger-subtle:  light-dark(oklch(94.5% 0.060  25), oklch(31%   0.090  25));
    --info:           light-dark(oklch(50%   0.165 235), oklch(78%   0.145 235));
    --info-subtle:    light-dark(oklch(94.5% 0.062 235), oklch(30%   0.078 235));

    /* ------------------------------------------- event category colours --
       Re-solved for this skin rather than inherited. Louder than Calm, and
       still a CATEGORICAL palette: any two badges may sit side by side and
       must be tellable apart, including under colour-vision deficiency.

       Search output, not taste. Verified all-pairs with the dataviz
       validator in BOTH modes:
         light  worst CVD ΔE 8.3 (deutan) · worst normal 16.5 · all >= 3:1
         dark   worst CVD ΔE 8.7 (deutan) · worst normal 18.1 · all >= 3:1

       Work sits at L 0.62 in both modes for a reason: at the 0.70/0.68 it
       started at, light mode failed the 3:1 contrast floor against white and
       dark mode fell outside the lightness band. Do not brighten it back.
       Badges also pair colour with a text label, so identity is never
       colour-alone. Re-run the validator after any change. */
    --cat-sport:    light-dark(oklch(62% 0.170 158), oklch(64% 0.150 158));
    --cat-work:     light-dark(oklch(62% 0.175 258), oklch(62% 0.190 258));
    --cat-personal: light-dark(oklch(48% 0.215   2), oklch(54% 0.210   2));
    --cat-family:   light-dark(oklch(56% 0.150  58), oklch(59% 0.145  58));

    --ring-track: light-dark(oklch(89% 0.030 80), oklch(30% 0.030 265));

    /* ------------------------------------------------------------- shape --
       Nothing between "pill" and "generous". A small radius reads as an
       accident in this language. */
    --radius-sm:  0.75rem;
    --radius-md:  1rem;
    --radius-lg:  1.25rem;
    --radius-xl:  1.5rem;
    --radius-2xl: 2rem;
    --radius-sheet: 2rem;

    /* --------------------------------------------------------- elevation --
       Hard offsets, zero blur. THIS IS THE WHOLE SKIN. Swap these for
       blurred shadows and it stops being a game interface immediately.

       Dark mode keeps the hard offset but tints it toward the accent, so a
       panel reads as backlit rather than as casting a shadow in the dark.

       --shadow-ink is a PLAIN COLOUR set by a media query, not a
       light-dark(). Chromium resolves light-dark() against the wrong branch
       once it is substituted through two levels of var() — here that is
       --elev-* -> --shadow-ink -> box-shadow — so every panel in light mode
       got the dark glow. A single-level use resolves correctly, which is why
       .streak-badge looked right and .card did not: exactly the sort of bug
       that is invisible until you diff two elements' computed styles.

       A media query is the correct tool now anyway: light vs dark is purely
       system-driven, so there is no manual override for it to disagree with. */
    --shadow-ink: oklch(24% 0.045 265 / 0.92);
    --hud-notch:  oklch(24% 0.045 265 / 0.28);

    --elev-1: 0 3px 0 0 var(--shadow-ink);
    --elev-2: 0 4px 0 0 var(--shadow-ink);
    --elev-3: 0 6px 0 0 var(--shadow-ink);
    --elev-sheet: 0 -4px 0 0 var(--shadow-ink);

    /* -------------------------------------------------------- typography --
       Same stack and scale — a game skin is not an excuse for a novelty face
       or for smaller text — but heavier, because weight is how this language
       carries emphasis. */
    --weight-normal: 500;
    --weight-medium: 600;
    --weight-semi:   700;
    --weight-bold:   800;

    --tracking-tight: -0.01em;
    --tracking-wide:  0.06em;

    /* ------------------------------------------------------------ motion --
       Bouncier. The spring is the Calm curve with more overshoot. */
    --ease-spring: linear(
      0, 0.009, 0.035, 0.078, 0.141, 0.225, 0.331, 0.456, 0.596, 0.74, 0.875,
      0.99, 1.078, 1.136, 1.166, 1.17, 1.155, 1.126, 1.09, 1.054, 1.023, 1.001,
      0.988, 0.983, 0.985, 0.991, 0.998, 1.003, 1.005, 1.004, 1.001, 1
    );

    /* Border width, referenced everywhere rather than repeated. */
    --line: 2.5px;
  }

  @media (prefers-color-scheme: dark) {
    :root[data-skin="arcade"] {
      --shadow-ink: oklch(60% 0.120 272 / 0.55);
      --hud-notch:  oklch(0% 0 0 / 0.42);
    }
  }
}

@layer components {

  /* ================================================================ PANELS ===
     Every card becomes a moulded object: thick outline, hard shadow, and it
     depresses into that shadow when pressed. */

  [data-skin="arcade"] .card {
    border: var(--line) solid var(--border-strong);
    box-shadow: var(--elev-2);
    transition: transform var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
  }

  /* A press is a real 4px displacement onto the shadow, not a colour change.
     This is what makes the panels feel like plastic. */
  [data-skin="arcade"] .btn:active,
  [data-skin="arcade"] .quicklog__chip:active,
  [data-skin="arcade"] .milestone:active,
  [data-skin="arcade"] .scale__step:active {
    transform: translateY(4px);
    box-shadow: 0 0 0 0 var(--shadow-ink);
  }

  [data-skin="arcade"] .btn {
    border: var(--line) solid var(--border-strong);
    box-shadow: var(--elev-1);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    transition: transform var(--dur-instant) var(--ease-out),
                box-shadow var(--dur-instant) var(--ease-out),
                background-color var(--dur-fast) var(--ease-out);
  }

  [data-skin="arcade"] .btn--primary { box-shadow: var(--elev-2); }

  [data-skin="arcade"] .btn--ghost {
    border-color: transparent;
    box-shadow: none;
  }

  [data-skin="arcade"] .btn--ghost:active { transform: scale(0.94); box-shadow: none; }

  /* Card titles become HUD labels. */
  [data-skin="arcade"] .card__title {
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: var(--weight-bold);
  }

  [data-skin="arcade"] .card__count {
    border: 2px solid var(--border-strong);
    font-weight: var(--weight-bold);
  }

  /* =================================================================== HUD ===
     The player card. Arcade only — it is inserted by the Today module and is
     `display: none` in Calm, so the markup costs nothing there.

     It reports LEVEL and XP derived from things actually done (days logged,
     habits ticked, wins closed, sessions trained). Nothing here is a
     participation trophy: the numbers are the same ones the rest of the app
     shows, wearing a different hat. */

  .hud { display: none; }

  [data-skin="arcade"] .hud {
    display: flex;
    align-items: center;
    gap: var(--space-3);

    padding: var(--space-3);
    margin-block-end: var(--space-4);

    background: linear-gradient(
      135deg,
      light-dark(oklch(97% 0.05 272), oklch(26% 0.06 272)),
      var(--surface-1)
    );
    border: var(--line) solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--elev-1);
  }

  .hud__badge {
    display: grid;
    place-items: center;
    flex: none;

    inline-size: 3rem;
    block-size: 3rem;

    color: var(--text-on-accent);
    background: var(--accent);
    border: var(--line) solid var(--border-strong);
    border-radius: var(--radius-full);
    box-shadow: 0 2px 0 0 var(--shadow-ink);
  }

  .hud__level {
    font-size: var(--text-lg);
    font-weight: var(--weight-bold);
    line-height: 1;
  }

  .hud__body { flex: 1; min-width: 0; display: grid; gap: 5px; }

  .hud__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
  }

  .hud__title {
    font-size: var(--text-2xs);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-secondary);
  }

  .hud__xp {
    font-size: var(--text-2xs);
    font-weight: var(--weight-bold);
    color: var(--text-tertiary);
  }

  /* The bar itself is .up-next__bar from play.css — shared with the milestone
     progress bar so the two can never drift. Arcade only adds the notches
     that make it read as an energy gauge, drawn as a repeating gradient over
     the top rather than as twenty elements. */
  .hud__bar {
    position: relative;
    block-size: 0.9rem;
  }

  .hud__bar::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    background: repeating-linear-gradient(
      90deg,
      transparent 0 calc(10% - 2px),
      var(--hud-notch) calc(10% - 2px) 10%
    );
  }

  /* ================================================================= HERO ===
     Louder ground, bigger buddy, chunkier rings. */

  [data-skin="arcade"] .hero {
    background:
      radial-gradient(120% 130% at 100% 0%,
        light-dark(oklch(94% 0.075 60), oklch(28% 0.06 300)) 0%, transparent 58%),
      radial-gradient(110% 140% at 0% 0%, var(--accent-subtle) 0%, transparent 60%),
      var(--surface-1);
  }

  [data-skin="arcade"] .hero__greeting {
    letter-spacing: var(--tracking-tight);
    text-shadow: 0 2px 0 var(--border-subtle);
  }

  [data-skin="arcade"] .buddy {
    inline-size: 4rem;
    block-size: 4rem;
  }

  [data-skin="arcade"] .buddy__body { stroke-width: 2.6; }
  [data-skin="arcade"] .buddy__lid,
  [data-skin="arcade"] .buddy__mouth { stroke-width: 2.8; }

  [data-skin="arcade"] .hero-ring__track { stroke: var(--ring-track); }
  [data-skin="arcade"] .hero-ring__arc { stroke-width: 9; }

  [data-skin="arcade"] .hero-ring__value {
    font-size: var(--text-lg);
    font-weight: var(--weight-bold);
  }

  [data-skin="arcade"] .hero-ring__label {
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
  }

  /* A closed ring gets a proper halo ring rather than a soft glow. */
  [data-skin="arcade"] .hero-ring.is-done .hero-ring__dial::after {
    inset: -5px;
    background: none;
    border: 2.5px solid currentColor;
    opacity: 0.75;
  }

  /* The streak stops being a quiet pill and becomes a combo counter. */
  [data-skin="arcade"] .streak-badge {
    padding: var(--space-1) var(--space-3);
    color: var(--text-on-accent);
    background: var(--warn);
    border: 2px solid var(--border-strong);
    box-shadow: 0 2px 0 0 var(--shadow-ink);
    font-weight: var(--weight-bold);
    font-size: var(--text-base);
  }

  /* ============================================================== CHIPS =====
     Quick-log chips become cartridge buttons. */

  [data-skin="arcade"] .quicklog__chip {
    border: var(--line) solid var(--border-strong);
    box-shadow: 0 3px 0 0 var(--shadow-ink);
    transition: transform var(--dur-instant) var(--ease-out),
                box-shadow var(--dur-instant) var(--ease-out),
                background-color var(--dur-fast) var(--ease-out);
  }

  [data-skin="arcade"] .quicklog__chip.is-logged {
    background: var(--success-subtle);
    border-color: var(--success);
  }

  [data-skin="arcade"] .quicklog__label,
  [data-skin="arcade"] .stat-tile__label {
    font-weight: var(--weight-bold);
  }

  [data-skin="arcade"] .quicklog__value {
    font-size: var(--text-lg);
    font-weight: var(--weight-bold);
  }

  /* ============================================================== TAB BAR ===
     A controller, not a toolbar. */

  [data-skin="arcade"] .tabbar {
    border-top: var(--line) solid var(--border-strong);
  }

  [data-skin="arcade"] .tabbar__tab.is-active {
    color: var(--accent);
  }

  [data-skin="arcade"] .tabbar__tab.is-active span {
    font-weight: var(--weight-bold);
  }

  [data-skin="arcade"] .tabbar__add {
    border: var(--line) solid var(--border-strong);
    box-shadow: 0 4px 0 0 var(--shadow-ink);
  }

  [data-skin="arcade"] .tabbar__add:active {
    transform: translate(-50%, 4px);
    box-shadow: 0 0 0 0 var(--shadow-ink);
  }

  /* ========================================================== CHECK ROWS ====
     The single most-touched control. It should feel like flipping a switch. */

  [data-skin="arcade"] .check-row__box {
    border-width: var(--line);
    border-radius: var(--radius-sm);
  }

  [data-skin="arcade"] .check-row.is-done .check-row__box {
    box-shadow: 0 2px 0 0 var(--shadow-ink);
  }

  /* =============================================================== SHELF ====
     Milestone discs become medals with a rim. */

  [data-skin="arcade"] .milestone__disc,
  [data-skin="arcade"] .milestone-detail__disc,
  [data-skin="arcade"] .up-next__disc {
    border-width: var(--line);
    border-color: var(--border-strong);
    box-shadow: 0 3px 0 0 var(--shadow-ink);
  }

  [data-skin="arcade"] .milestone:not(.is-earned) .milestone__disc {
    opacity: 1;
    color: var(--text-tertiary);
    background: var(--surface-2);
    box-shadow: none;
    border-style: dashed;
  }

  [data-skin="arcade"] .milestone__name {
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    letter-spacing: 0.02em;
  }

  [data-skin="arcade"] .shelf__meter,
  [data-skin="arcade"] .up-next__bar {
    border: 2px solid var(--border-strong);
    block-size: 0.8rem;
  }

  [data-skin="arcade"] .up-next {
    border-width: var(--line);
    border-color: var(--border-strong);
    box-shadow: var(--elev-1);
  }

  /* ======================================================== CONSISTENCY =====
     The grid becomes pixels. Square, gridded, no soft corners. */

  [data-skin="arcade"] .grid-cell {
    border-radius: 2px;
  }

  [data-skin="arcade"] .grid-cell.is-today {
    outline-width: 2.5px;
    outline-color: var(--accent);
  }

  /* ============================================================ SHEETS ======*/

  [data-skin="arcade"] .sheet__panel {
    border: var(--line) solid var(--border-strong);
    border-block-end: none;
  }

  [data-skin="arcade"] .sheet__title {
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
  }

  /* ========================================================= CELEBRATION ====*/

  [data-skin="arcade"] .celebrate__card {
    border: var(--line) solid var(--border-strong);
    box-shadow: var(--elev-3);
  }

  [data-skin="arcade"] .celebrate__medal {
    border: var(--line) solid var(--border-strong);
    box-shadow: 0 3px 0 0 var(--shadow-ink);
  }

  [data-skin="arcade"] .celebrate__title {
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
  }

  [data-skin="arcade"] .record-pop {
    border: var(--line) solid var(--border-strong);
    box-shadow: var(--elev-3);
  }

  /* Confetti in a game skin is square, not rectangular-with-rounded-corners. */
  [data-skin="arcade"] .celebrate__piece {
    inline-size: 10px;
    block-size: 10px;
    border-radius: 0;
  }

  /* ============================================================== TOASTS ====*/

  [data-skin="arcade"] .toast {
    border: var(--line) solid var(--border-strong);
    box-shadow: var(--elev-2);
    font-weight: var(--weight-semi);
  }

  /* ============================================================== INPUTS ====*/

  [data-skin="arcade"] .input,
  [data-skin="arcade"] .skin-picker,
  [data-skin="arcade"] .stat-tile {
    border: var(--line) solid var(--border-strong);
  }

  [data-skin="arcade"] .stat-tile { box-shadow: 0 3px 0 0 var(--shadow-ink); }

  /* ============================================================ SCANLINE ====
     One texture, at 3% opacity, fixed over the whole app.

     This is the only purely decorative thing in the skin, and it is kept
     nearly invisible on purpose: at any strength you would consciously notice
     it becomes a filter over your own health data, which is obnoxious. At 3%
     it does what a paper grain does — you cannot see it, but the surface
     stops looking like a browser. */

  [data-skin="arcade"] body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    opacity: 0.03;
    background: repeating-linear-gradient(
      0deg,
      light-dark(oklch(24% 0.045 265), oklch(100% 0 0)) 0 1px,
      transparent 1px 3px
    );
  }

  @media (prefers-reduced-motion: reduce) {
    [data-skin="arcade"] body::after { display: none; }
  }
}
