/* ── Flowly ────────────────────────────────────────────────────────────────
   Visual: a glass board, soft tiles, thick glowing pipes, jewel dots. Day is written
   first and night overrides it; app.js resolves the player's Appearance setting
   (auto, light, dark) against the device and publishes the answer as data-scene, so one
   selector covers both following the device and choosing explicitly.
   Motion: quick and liquid. Pipes follow the finger with no lag; connected pipes
   shimmer as if water runs through; a clear ripples out from the last square.
   Reduced motion keeps color changes and fades only. */
:root {
  /* The neutrals every board rule is written against, so the stage flips in one place:
     --flow-film for translucent chips, --flow-lift for hover edges, --flow-bed for cell fill. */
  --flow-film: #101a3d12; --flow-lift: #101a3d2e; --flow-edge: #101a3d55;
  --flow-bed: #fff; --flow-bed-line: #101a3d1f; --flow-cell: #e7ecfa; --flow-cell-mix: #fff;
  --flow-shine: #fff; --flow-ink-soft: #3e4a72; --flow-shadow: #101a3d29;
  --flow-tile-ink: #101a3d; --flow-star: #9a6400;
  --flow-mode-accent: #0b6a86; --flow-ok: #12813f;
  --flow-daily-bg: linear-gradient(150deg, #f0e2ff, #dcd0f7); --flow-daily-accent: #8a2472;
  --flow-trial-bg: linear-gradient(150deg, #d9f4f2, #c4e8ea); --flow-trial-accent: #0a6b45;
  --flow-card: linear-gradient(150deg, #fff, #eaf0ff);
  --flow-win-bg: linear-gradient(180deg, #fffffff2, #eaf0fff2);
  --flow-nudge-bg: #ffd23f33; --flow-nudge-ink: #6b4a00; --flow-nudge-edge: #c99a0066;
  /* Only the numbers, never a whole hsl(): a property holding var(--hue) would resolve here,
     where --hue is unset, and compute to invalid before it ever reached the tile. */
  --flow-hue-edge-s: 65%; --flow-hue-edge-l: 40%; --flow-hue-edge-a: .55;
  --flow-lvl-s1: 66%; --flow-lvl-l1: 88%; --flow-lvl-s2: 58%; --flow-lvl-l2: 79%;
  /* Pipe colors (FlowlyArt) */
  --fc-red: #ff4d61; --fc-blue: #3f7fff; --fc-yellow: #ffd23f; --fc-green: #2ed47a; --fc-orange: #ff9433; --fc-cyan: #35d8ff;
  --fc-pink: #ff6fd0; --fc-violet: #9d6bff; --fc-lime: #b9f046; --fc-teal: #17b8a0; --fc-bronze: #c07a3e; --fc-snow: #eef2ff;
  --fc-crimson: #c02454; --fc-indigo: #5b5ff2; --fc-gold: #dfae2c; --fc-slate: #8d9abb;
}
html[data-scene="night"] {
  --flow-film: #ffffff10; --flow-lift: #ffffff26; --flow-edge: #ffffff50;
  --flow-bed: #0d1430; --flow-bed-line: #ffffff1c; --flow-cell: #182247; --flow-cell-mix: #121a38;
  --flow-shine: #fff; --flow-ink-soft: #ffffffcc; --flow-shadow: #000a;
  --flow-tile-ink: #eef2ff; --flow-star: #ffd76a;
  --flow-mode-accent: #7ce8ff; --flow-ok: #2ed47a;
  --flow-daily-bg: linear-gradient(150deg, #3a2266, #140c33); --flow-daily-accent: #ffb4e8;
  --flow-trial-bg: linear-gradient(150deg, #0f4a52, #08202a); --flow-trial-accent: #8ff0bb;
  --flow-card: linear-gradient(150deg, #1c2757, #0e1430);
  --flow-win-bg: linear-gradient(180deg, #1f2a55f2, #121a38f2);
  --flow-nudge-bg: #ffd23f1c; --flow-nudge-ink: #ffe89a; --flow-nudge-edge: #ffd23f40;
  --flow-hue-edge-s: 80%; --flow-hue-edge-l: 65%; --flow-hue-edge-a: .6;
  --flow-lvl-s1: 45%; --flow-lvl-l1: 26%; --flow-lvl-s2: 45%; --flow-lvl-l2: 14%;
  --fc-crimson: #e64b7a; --fc-indigo: #7477ff;
}
body:has(.flow-layout) {
  color-scheme: light;
  --background: #eef3ff; --surface: #fff; --elevated: #e2eaff;
  --ink: #101a3d; --muted: #4d5a85; --line: #101a3d24;
  --accent: #8a5a00; --on-accent: #fff6e6; --sea: #0b6a86; --ring: #8a5a00; --error: #b3261e;
  --sand-std: 220ms; --sand-slow: 380ms;
  --sand-ease: var(--ease);
  --sand-ease-pop: var(--ease-pop);
  --flow-ease: var(--ease);
  --win-at: 120ms;
  background:
    radial-gradient(ellipse 70% 50% at 50% -10%, #b9ccff88, transparent 70%),
    radial-gradient(ellipse 60% 40% at 90% 110%, #9fe3f480, transparent 70%),
    var(--background);
}
html[data-scene="night"] body:has(.flow-layout) {
  color-scheme: dark;
  --background: #0a1024; --surface: #151d3b; --elevated: #1f2a52;
  --ink: #eef2ff; --muted: #9aa6cf; --line: #fff2;
  --accent: #ffd23f; --on-accent: #2a1400; --sea: #7ce8ff; --ring: #7ce8ff; --error: #ff9a9e;
  background:
    radial-gradient(ellipse 70% 50% at 50% -10%, #2c3a8a66, transparent 70%),
    radial-gradient(ellipse 60% 40% at 90% 110%, #0f6e8a40, transparent 70%),
    var(--background);
}
body:has(.flow-layout) .masthead { border-bottom-color: var(--line); }
body:has(.flow-layout) nav { background: color-mix(in srgb, var(--background) 90%, transparent); border-color: var(--line); -webkit-backdrop-filter: blur(16px) saturate(1.2); backdrop-filter: blur(16px) saturate(1.2); }
@media (max-width: 767px) { html[data-scene="night"] body:has(.flow-layout) nav { background: #121a38; } }

.flow-layout { --hud-film: var(--flow-film); --hud-eyebrow: var(--sea); }

/* Floats over the board's top edge: in the flow it pushed the board down and the fit shrank it (#237). */
.flow-nudge { position: absolute; z-index: 2; top: 0; left: 50%; translate: -50% -50%; width: max-content; max-width: calc(100% - var(--s4));
  margin: 0; padding: .125rem var(--s3); border-radius: var(--pill); text-align: center; font-size: var(--text-xs); line-height: 1.3;
  pointer-events: none; background: color-mix(in srgb, var(--surface) 88%, var(--flow-nudge-edge)); color: var(--flow-nudge-ink);
  border: 1px solid var(--flow-nudge-edge); box-shadow: 0 .25rem .75rem #0003; animation: fade-in var(--sand-slow) var(--flow-ease) both; }

.flow-stage { position: relative; display: grid; place-items: center; }
.flow-board-wrap { position: relative; isolation: isolate; width: min(100%, var(--fit-h, calc(100dvh - 19rem)), 36rem); min-width: 12rem; aspect-ratio: 1; }
:root[data-focus] .flow-board-wrap { width: min(100%, var(--fit-h, calc(100dvh - 8rem))); }
/* The shadow sits on its own layer behind the board: a filter on the SVG made Safari re-blur the whole board every frame (#36).
   The radius matches .flow-bed (rx .42 in a viewBox of n + .2). */
.flow-board-wrap::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: calc(.42 / (var(--n) + .2) * 100%);
  box-shadow: 0 1.25rem 2.5rem #0009; pointer-events: none; }
.flow-board { display: block; width: 100%; height: 100%; overflow: visible; }
.flow-touch { position: absolute; inset: 0; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
  cursor: pointer; border-radius: 3%; outline: none; }
.flow-touch:focus-visible { box-shadow: 0 0 0 3px var(--ring); }
.flow-finger { position: absolute; left: calc(var(--px, .5) * 100%); top: calc(var(--py, .5) * 100%); width: calc(100% / var(--n) * 1.9); aspect-ratio: 1;
  border-radius: 50%; translate: -50% -50%; pointer-events: none; opacity: 0; scale: .6;
  background: radial-gradient(circle, color-mix(in srgb, var(--finger) 45%, transparent), color-mix(in srgb, var(--finger) 12%, transparent) 60%, transparent 70%);
  transition: opacity 120ms var(--flow-ease), scale 160ms var(--flow-ease); }
.flow-touch.dragging .flow-finger { opacity: 1; scale: 1; }

.flow-bed { fill: var(--flow-bed); stroke: var(--flow-bed-line); stroke-width: .04; }
.flow-cell { fill: var(--flow-cell); transition: fill 140ms var(--flow-ease); }
.flow-cell.lit { fill: color-mix(in srgb, var(--c) 22%, var(--flow-cell-mix)); }
.flow-cursor { fill: none; stroke: var(--ring); stroke-width: .06; }

.flow-pipe, .flow-dot, .flow-mini > * { --flow-rim: color-mix(in srgb, var(--c) 45%, var(--flow-tile-ink)); }
.flow-pipe path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.flow-pipe .pipe-glow { stroke: var(--c); stroke-width: .56; opacity: .38; }
.flow-pipe .pipe-body { stroke: var(--c); stroke-width: .4; }
.flow-pipe .pipe-core { stroke: color-mix(in srgb, var(--c) 45%, var(--flow-shine)); stroke-width: .12; opacity: .55; }
.flow-pipe .pipe-flow { stroke: var(--flow-shine); stroke-width: .1; opacity: .5; stroke-dasharray: .18 1.4; animation: flow-run 1.6s linear infinite; }
.flow-pipe.linked .pipe-glow { opacity: .6; }
.flow-pipe.active .pipe-body { stroke-width: .44; }
.flow-pipe.hinted .pipe-glow { animation: flow-hint 1.2s var(--flow-ease) 2; }
@keyframes flow-run { to { stroke-dashoffset: -1.58; } }
@keyframes flow-hint { 50% { opacity: 1; stroke-width: .9; } }

.flow-dot, .flow-dot circle { transform-box: fill-box; transform-origin: center; }
.flow-dot .dot-ring { fill: none; stroke: var(--c); stroke-width: .05; opacity: 0; transform-box: fill-box; transform-origin: center; }
.flow-dot .dot-body { fill: var(--c); }
.flow-dot .dot-symbol { font: 700 .34px var(--font); fill: #0a1024; fill: oklch(from var(--c) clamp(0, (.6 - l) * 1e3, 1) 0 0); pointer-events: none; }
.flow-dot.linked .dot-ring { opacity: .7; }
.flow-dot.active .dot-ring { opacity: .9; animation: flow-ping 1s var(--flow-ease) infinite; }
.flow-dot.linked .dot-body { animation: flow-pop 320ms var(--sand-ease-pop); transform-box: fill-box; transform-origin: center; }
@keyframes flow-ping { from { transform: scale(.8); opacity: .9; } to { transform: scale(1.35); opacity: 0; } }
@keyframes flow-pop { 40% { transform: scale(1.22); } }
.flow-board .flow-dot { animation: flow-dot-in 360ms var(--sand-ease-pop) calc(var(--i) * 18ms) both; }
@keyframes flow-dot-in { from { opacity: 0; scale: .3; } }
/* Bright pipes vanish on the day board, so they get a deepened rim there. */
html:not([data-scene="night"]) .flow-pipe .pipe-glow { stroke: var(--flow-rim); stroke-width: .5; opacity: 1; filter: none; }
html:not([data-scene="night"]) .flow-dot .dot-body, html:not([data-scene="night"]) .flow-mini circle { stroke: var(--flow-rim); stroke-width: .05; }
html:not([data-scene="night"]) .flow-dot .dot-ring { stroke: var(--flow-rim); }
html:not([data-scene="night"]) .flow-cell.lit.pale { fill: color-mix(in srgb, var(--flow-ink-soft) 12%, var(--flow-cell-mix)); }
.flow-mini circle { fill: var(--c); }
.flow-mini .mini-edge { display: none; stroke: var(--flow-rim); stroke-width: .46; }
html:not([data-scene="night"]) .flow-mini .mini-edge { display: inline; }

/* The clear: tiles light up in a ripple from the last square drawn. */
.flow-stage.won .flow-cell.lit { animation: flow-wave 700ms var(--flow-ease) calc(var(--d) * 36ms) both; }
@keyframes flow-wave { 35% { fill: color-mix(in srgb, var(--c) 70%, var(--flow-shine) 10%); } }
.flow-stage.almost .flow-bed { stroke: color-mix(in srgb, var(--accent) 55%, transparent); }

.flow-burst { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; z-index: 2; }
.flow-burst i { position: absolute; width: 8px; height: 8px; border-radius: 50%; background: var(--c); box-shadow: 0 0 10px var(--c); opacity: 0;
  animation: flow-burst 900ms var(--flow-ease) calc(300ms + var(--d)) both; }
@keyframes flow-burst { 0% { opacity: 1; transform: rotate(var(--a)) translateY(0) scale(.4); } 100% { opacity: 0; transform: rotate(var(--a)) translateY(calc(var(--r) * -1)) scale(1); } }

.flow-win { position: absolute; z-index: 3; inset: auto var(--s4) 12%; margin: auto; max-width: 22rem; display: grid; gap: var(--s3); justify-items: center; text-align: center;
  padding: var(--s8) var(--s6) var(--s6); border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--flow-win-bg); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  box-shadow: 0 1.5rem 4rem var(--flow-shadow), inset 0 1px 0 var(--flow-lift); animation: flow-win 380ms var(--flow-ease) 520ms both; }
@keyframes flow-win {
  from { opacity: 0; transform: translateY(18px) scale(.96); pointer-events: none; }
  to { opacity: 1; transform: none; pointer-events: auto; }
}
.flow-win h2 { margin: 0; font-size: var(--text-2xl); }
.flow-win p { margin: 0; color: var(--muted); }
.flow-win .eyebrow { color: var(--sea); }
.flow-win .win-world { color: var(--flow-mode-accent); font-weight: var(--weight-label); font-size: var(--text-sm); }
.flow-win button, .flow-win .button { width: 100%; justify-content: center; }
.flow-win .win-stars .star.on { animation-delay: calc(700ms + var(--s) * 130ms); }
.flow-win .win-coins { animation-delay: 1100ms; }


.flow-controls { display: flex; justify-content: center; gap: var(--s3); flex-wrap: wrap; }
.flow-controls button { background: var(--flow-film); border-color: var(--line); }
.flow-loading { min-height: 20rem; display: grid; place-content: center; color: var(--muted); }

/* ── Flowly mini board art (follows the app's day/night theme) ── */
.flow-mini { display: block; width: 100%; height: 100%; }
.flow-mini-bed { fill: var(--flow-bed); }
.flow-mini path { fill: none; stroke-width: .36; stroke-linecap: round; stroke-linejoin: round; }
.hub-art.flow-art { background: radial-gradient(ellipse at 50% 30%, #25347a, #0a1024 75%); padding: var(--s4); }
.hub-art.flow-art .flow-mini { width: auto; height: 100%; aspect-ratio: 1; }


  border: 1px solid var(--line); color: var(--ink); text-decoration: none; font-variant-numeric: tabular-nums; }
.flow-bests { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s2); }
.flow-bests li { display: flex; justify-content: space-between; padding: var(--s2) 0; border-bottom: 1px solid var(--line); }

@media (prefers-reduced-motion: reduce) {
  .flow-burst { display: none; }
  .flow-win { animation: flow-fade 200ms ease-out both; }
  @keyframes flow-fade { from { opacity: 0; pointer-events: none; } to { pointer-events: auto; } }
}
@media (max-width: 767px) {
  .flow-board-wrap { width: min(100%, var(--fit-h, calc(100dvh - 24rem))); }
  .flow-controls { flex-wrap: nowrap; gap: var(--s2); }
  .flow-controls button { padding-inline: var(--s4); }
  .flow-win { inset: auto 0 6%; }
}

/* Bonus coin: a small coin rides on both dots of one color until a clean, 3-star connect. */
.flow-coin { pointer-events: none; }
.flow-coin .flow-coin-halo { fill: var(--shine); opacity: .9; }
.flow-coin .flow-coin-face { fill: var(--coin-face); stroke: var(--coin-edge); stroke-width: .03; }
.flow-coin .flow-coin-rim { fill: none; stroke: var(--coin-rim); stroke-width: .02; }
.flow-rank { justify-content: center; }
.flow-rank li { background: color-mix(in srgb, var(--ink) 14%, transparent); }
.flow-rank li.done { background: var(--accent); }
.flow-rank p { color: var(--muted); }
.flow-win .win-rank { color: var(--accent) !important; }

/* The narrowest phones: the title, pet and switches share one row, so everything gives a little. */
@media (max-width: 360px) {
  .flow-controls button { flex: 1 1 0; min-width: 0; justify-content: center; padding-inline: var(--s2); }
}
