@import url('https://fonts.googleapis.com/css2?family=Archivo:wght@500;600;800&family=Public+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

/* ===========================================================================
   FaucetBoss v0.1.0

   The device this interface is built on is the status rail: a coloured left
   edge that states what something is doing right now. Ready, waiting, empty,
   locked. From v0.3 every faucet on the board carries one, so the same rail is
   used here for account state — a user learns one vocabulary, not two.

   Numbers are always set in mono. Anything a user might count, compare or
   screenshot is data, and data is monospaced.
   ========================================================================= */

:root {
  --ink:        #12151c;
  --ink-lift:   #171b24;
  --panel:      #1b202b;
  --panel-lift: #222836;
  --line:       #2c3342;
  --line-soft:  #232937;

  --paper:      #e8e6e1;
  --paper-dim:  #b3b8c4;
  --muted:      #7f889b;

  --ready:      #f2a93b;
  --ready-deep: #c8801d;
  --cool:       #4f7da8;
  --dry:        #a8654f;
  --good:       #5aa87b;
  --bad:        #c25a5a;

  --display: 'Archivo', system-ui, sans-serif;
  --body:    'Public Sans', system-ui, sans-serif;
  --mono:    'IBM Plex Mono', ui-monospace, monospace;

  --rail: 3px;
  --r:    4px;

  --step-0: 0.9375rem;
  --step-1: 1.0625rem;
  --step-2: 1.375rem;
  --step-3: 1.875rem;
  --step-4: 2.5rem;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--body);
  font-size: var(--step-0);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ready); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--ready);
  outline-offset: 2px;
}

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 0.5rem;
}
h1 { font-size: var(--step-3); }
h2 { font-size: var(--step-2); }
h3 { font-size: var(--step-1); font-weight: 600; }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

/* --- Structure ---------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding: 0 1rem;
}
.wrap--narrow { max-width: 27rem; }
.wrap--mid    { max-width: 42rem; }

main { padding: 1.75rem 0 4rem; }

/* --- Masthead ----------------------------------------------------------- */

.masthead {
  border-bottom: 1px solid var(--line);
  background: var(--ink-lift);
  position: sticky;
  top: 0;
  z-index: 20;
}
.masthead__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 3.5rem;
  flex-wrap: wrap;
}
.brand {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.03em;
  color: var(--paper);
  margin-right: auto;
}
.brand:hover { text-decoration: none; color: var(--ready); }
.brand span { color: var(--ready); }

.nav {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  flex-wrap: wrap;
}
.nav a {
  color: var(--paper-dim);
  padding: 0.4rem 0.65rem;
  border-radius: var(--r);
  font-weight: 500;
  font-size: 0.9375rem;
}
.nav a:hover { background: var(--panel); color: var(--paper); text-decoration: none; }
.nav a.is-current { color: var(--ready); }

/* Balance in the masthead — mono, because it is data. */
.balance-chip {
  font-family: var(--mono);
  font-size: 0.875rem;
  font-weight: 500;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: var(--rail) solid var(--ready);
  border-radius: var(--r);
  padding: 0.3rem 0.6rem;
  color: var(--paper);
  white-space: nowrap;
}
.balance-chip small {
  color: var(--muted);
  font-size: 0.8125rem;
  margin-left: 0.35rem;
}

/* --- The status rail ---------------------------------------------------- */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: var(--rail) solid var(--line);
  border-radius: var(--r);
  padding: 1.15rem 1.25rem;
  margin-bottom: 1rem;
}
.panel--ready  { border-left-color: var(--ready); }
.panel--cool   { border-left-color: var(--cool); }
.panel--dry    { border-left-color: var(--dry); }
.panel--good   { border-left-color: var(--good); }
.panel--bad    { border-left-color: var(--bad); }
.panel--quiet  { background: var(--ink-lift); }

.panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}
.panel__head h2, .panel__head h3 { margin: 0; }

/* An eyebrow states what kind of thing follows. It is not decoration; if it
   would only repeat the heading, it is left out. */
.eyebrow {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: 0.35rem;
}

/* --- Forms -------------------------------------------------------------- */

.field { margin-bottom: 1rem; }
.field label {
  display: block;
  font-weight: 600;
  font-size: 0.875rem;
  margin-bottom: 0.3rem;
  color: var(--paper);
}
.field .hint {
  display: block;
  font-size: 0.8125rem;
  color: var(--muted);
  margin-top: 0.3rem;
}

input[type=text], input[type=email], input[type=password], input[type=number],
select, textarea {
  width: 100%;
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--paper);
  font-family: var(--body);
  font-size: var(--step-0);
  padding: 0.6rem 0.7rem;
}
input[inputmode=numeric], input.mono, textarea.mono, select.mono { font-family: var(--mono); }

input:focus, select:focus, textarea:focus {
  border-color: var(--ready);
  outline: none;
  box-shadow: 0 0 0 3px rgba(242, 169, 59, 0.16);
}
input[aria-invalid=true] { border-color: var(--bad); }

textarea { min-height: 6rem; resize: vertical; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  background: var(--ready);
  color: #17130a;
  border: 1px solid var(--ready);
  border-radius: var(--r);
  font-family: var(--display);
  font-weight: 600;
  font-size: var(--step-0);
  letter-spacing: -0.01em;
  padding: 0.6rem 1.1rem;
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { background: var(--ready-deep); border-color: var(--ready-deep); text-decoration: none; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn--block { width: 100%; }
.btn--quiet {
  background: transparent;
  color: var(--paper);
  border-color: var(--line);
}
.btn--quiet:hover { background: var(--panel-lift); border-color: var(--muted); }
.btn--danger { background: var(--bad); border-color: var(--bad); color: #fff; }
.btn--danger:hover { background: #a94b4b; border-color: #a94b4b; }
.btn--small { padding: 0.35rem 0.7rem; font-size: 0.8125rem; }

.form-actions {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 1.25rem;
}

/* --- Messages ----------------------------------------------------------- */

.msg {
  border: 1px solid var(--line);
  border-left: var(--rail) solid var(--muted);
  border-radius: var(--r);
  background: var(--panel);
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  font-size: 0.9375rem;
}
.msg--success { border-left-color: var(--good); }
.msg--error   { border-left-color: var(--bad); }
.msg--warning { border-left-color: var(--ready); }
.msg--info    { border-left-color: var(--cool); }

/* --- Data --------------------------------------------------------------- */

.mono { font-family: var(--mono); }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.stat {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: var(--rail) solid var(--line);
  border-radius: var(--r);
  padding: 0.8rem 0.9rem;
}
.stat__label {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: 0.25rem;
}
.stat__value {
  font-family: var(--mono);
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--paper);
  line-height: 1.2;
  word-break: break-all;
}
.stat__sub { font-size: 0.8125rem; color: var(--muted); }

.kv {
  display: grid;
  grid-template-columns: minmax(7rem, auto) 1fr;
  gap: 0.45rem 1rem;
  font-size: 0.9375rem;
}
.kv dt { color: var(--muted); }
.kv dd { margin: 0; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
table.data th, table.data td {
  text-align: left;
  padding: 0.55rem 0.6rem;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}
table.data th {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  white-space: nowrap;
}
table.data td.num, table.data th.num { text-align: right; font-family: var(--mono); }
table.data tbody tr:hover { background: var(--panel-lift); }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.tag {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.15rem 0.4rem;
  border-radius: 2px;
  border: 1px solid var(--line);
  color: var(--paper-dim);
  white-space: nowrap;
}
.tag--ready { border-color: var(--ready); color: var(--ready); }
.tag--good  { border-color: var(--good);  color: var(--good); }
.tag--bad   { border-color: var(--bad);   color: var(--bad); }
.tag--cool  { border-color: var(--cool);  color: var(--cool); }
.tag--dry   { border-color: var(--dry);   color: var(--dry); }

.empty {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--muted);
}
.empty p { margin-bottom: 1rem; }

/* --- Landing ------------------------------------------------------------ */

/* Vertical padding only. A shorthand here sets the horizontal padding to zero,
   and .hero is also a .wrap on the landing page — so the shorthand overwrote the
   wrap's 1rem gutter and the headline ran into the left edge of the window. */
.hero {
  padding-top: 3rem;
  padding-bottom: 2rem;
}
.hero h1 {
  font-size: clamp(2rem, 8vw, var(--step-4));
  max-width: 18ch;
}
.hero .lede {
  font-size: var(--step-1);
  color: var(--paper-dim);
  max-width: 46ch;
}
.hero .form-actions { margin-top: 1.75rem; }

/* --- Utility ------------------------------------------------------------ */

.muted     { color: var(--muted); }
.small     { font-size: 0.8125rem; }
.stack > * + * { margin-top: 1rem; }
.row-between {
  display: flex; justify-content: space-between;
  align-items: center; gap: 0.75rem; flex-wrap: wrap;
}
.text-center { text-align: center; }
.mt-2 { margin-top: 1.5rem; }

.footer {
  border-top: 1px solid var(--line);
  padding: 1.25rem 0;
  color: var(--muted);
  font-size: 0.8125rem;
}
.footer a { color: var(--paper-dim); }

.shell-plain { display: grid; place-items: center; min-height: 100vh; }
.notice { text-align: center; padding: 2rem; }

/* --- Admin -------------------------------------------------------------- */

.admin-bar {
  background: var(--ink-lift);
  border-bottom: 1px solid var(--line);
}
.admin-bar__inner {
  display: flex; align-items: center; gap: 0.2rem;
  flex-wrap: wrap; min-height: 2.75rem;
}
.admin-bar a {
  color: var(--paper-dim);
  padding: 0.35rem 0.6rem;
  border-radius: var(--r);
  font-size: 0.875rem;
}
.admin-bar a:hover { background: var(--panel); color: var(--paper); text-decoration: none; }
.admin-bar a.is-current { color: var(--ready); background: var(--panel); }
.admin-bar .spacer { margin-left: auto; }

.settings-group + .settings-group { margin-top: 1.5rem; }

@media (max-width: 40rem) {
  main { padding-top: 1.25rem; }
  .panel { padding: 1rem; }
  .kv { grid-template-columns: 1fr; gap: 0.15rem 0; }
  .kv dd { margin-bottom: 0.6rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ===========================================================================
   Faucet cards (v0.2)

   Each faucet is styled from its own seed, so almost everything visual here is
   set inline from PHP. What stays in the stylesheet is the shape: size, spacing
   and the states a card can be in. The status rail from v0.1 carries over —
   ready, cooling, dry, locked — so users learn one vocabulary, not two.
   ========================================================================= */

.fgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0.9rem;
  margin-bottom: 1.5rem;
}
.fgrid--single { grid-template-columns: minmax(0, 22rem); }

.fcard {
  position: relative;
  border-radius: var(--r);
  overflow: hidden;
  background-size: cover;
  background-position: center;
  border: 1px solid var(--line);
  min-height: 13.5rem;
}
.fcard--compact { min-height: 9rem; }

.fcard__inner {
  position: relative;   /* anchors the floor gradient below */
  height: 100%;
  min-height: inherit;
  /* Arcade cabinet: marquee at the top, the score under it, the control at the
     bottom, and as little dead air between them as the content allows. The old
     layout centred a small block and left the rest of the card empty. */
  padding: 0.9rem 0.75rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  justify-content: space-between;
  align-items: center;
  text-align: center;
}

.fcard__title {
  margin: 0;

  /* Sized per faucet from the name — see faucet_text_scale(). A fixed size
     cannot serve both "Idle Mill" and "Overclocked Dynamo": whatever suits the
     long one leaves the short one swimming. */
  font-size: 1.35rem;

  line-height: 0.98;
  letter-spacing: -0.01em;

  /* A hard shadow plus a soft glow, so a title reads on any of the generated
     backgrounds without needing a plate behind it. */
  text-shadow:
    0 2px 0 rgba(0, 0, 0, 0.55),
    0 0 22px rgba(0, 0, 0, 0.45);

  word-break: break-word;
  hyphens: none;
  width: 100%;
}
.fcard--compact .fcard__title { font-size: 1.1rem; }

.fcard__pay {
  margin: 0;
  font-family: var(--mono);

  /* Also sized per faucet. This is the score on the machine. */
  font-size: 0.9375rem;

  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: #fff;
  text-shadow:
    0 2px 0 rgba(0, 0, 0, 0.5),
    0 0 16px rgba(0, 0, 0, 0.4);
}
.fcard__meta {
  margin: 0;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.82);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
}

.fcard__btn {
  margin-top: 0.5rem;
  display: inline-block;
  padding: 0.35rem 1rem;
  border-radius: 3px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 0.875rem;
  color: #14100a;

  /* A default background so the class is self-sufficient. Each faucet overrides
     this with its own accent inline, but when a countdown finished the browser
     built a replacement link with the class and no inline colour — and with no
     background here it rendered as dark text on the card, looking like the
     button had vanished. A class named "btn" should look like one on its own. */
  background: var(--ready);
}

/* Board states. A dry or locked card stays visible but reads as unavailable —
   a faucet you cannot claim yet is a reason to come back, not clutter. */
.fcard--dry .fcard__inner,
.fcard--locked .fcard__inner { filter: grayscale(0.75); opacity: 0.72; }
.fcard--dry .fcard__btn,
.fcard--locked .fcard__btn {
  background: var(--line) !important;
  color: var(--muted);
}

/* Claim page and board states (v0.3) */
.fcard--tall { min-height: 16rem; }
.fcard__title--big { font-size: 2rem; }
.fcard__btn--go {
  border: 0;
  cursor: pointer;
  font-size: 1rem;
  padding: 0.55rem 1.6rem;
}
.fcard__btn--wait { background: rgba(255,255,255,0.14) !important; color: rgba(255,255,255,0.75); }
.fcard--cooling .fcard__inner { opacity: 0.9; }

/* Progress meters (v0.4) */
.meter {
  height: 7px;
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
}
.meter__fill {
  display: block;
  height: 100%;
  background: var(--ready);
  transition: width 0.3s ease;
}
.meter--xp .meter__fill { background: var(--cool); }

/* ===========================================================================
   Curve designer (v0.4.1)

   Controls that describe a shape, with the result rendered underneath. The
   earlier version of this screen was a grid of number boxes wide enough that
   two columns fell off the right edge unnoticed — hence the fixed grid width
   here and the narrower inputs in the fold-away editor.
   ========================================================================= */

.ctrl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1.1rem 1.5rem;
}

.ctrl label {
  display: block;
  font-weight: 600;
  font-size: 0.875rem;
  margin-bottom: 0.4rem;
}
.ctrl output {
  display: block;
  font-size: 0.8125rem;
  color: var(--ready);
  margin-top: 0.3rem;
}
.ctrl .hint {
  display: block;
  font-size: 0.75rem;
  color: var(--muted);
  margin-top: 0.25rem;
}

input[type=range] {
  width: 100%;
  appearance: none;
  height: 3px;
  border-radius: 2px;
  background: var(--line);
  outline-offset: 6px;
}
input[type=range]::-webkit-slider-thumb {
  appearance: none;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: var(--ready);
  border: 2px solid var(--ink);
  cursor: pointer;
}
input[type=range]::-moz-range-thumb {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: var(--ready);
  border: 2px solid var(--ink);
  cursor: pointer;
}

.inline-num {
  width: 3.4rem;
  padding: 0.1rem 0.3rem;
  font-size: 0.75rem;
  display: inline-block;
}

.grid-num {
  width: 5.2rem;
  padding: 0.2rem 0.3rem;
  text-align: right;
  font-size: 0.8125rem;
}

.curve-chart {
  width: 100%;
  height: 140px;
  display: block;
  margin-bottom: 1rem;
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

details > summary { list-style: revert; }
details[open] > summary { margin-bottom: 0.5rem; }

/* ===========================================================================
   Captcha (v0.5.1)

   Tap targets are deliberately large: this has to be solvable on a cheap phone,
   one-handed, by someone who is not reading English carefully.
   ========================================================================= */

.captcha__prompt {
  font-size: 0.9375rem;
  margin-bottom: 0.75rem;
}
.captcha__tiles {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.captcha__tile {
  background: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 0.5rem;
  cursor: pointer;
  line-height: 0;
  min-width: 60px;
  min-height: 60px;
  display: grid;
  place-items: center;
}
.captcha__tile:hover { border-color: var(--muted); }
.captcha__tile.is-picked {
  border-color: var(--ready);
  box-shadow: 0 0 0 2px rgba(242, 169, 59, 0.28);
}
.captcha__error { color: var(--bad); font-size: 0.8125rem; margin-top: 0.5rem; }

/* The card's status label while a timer or captcha is pending. Deliberately not
   a button: the one real claim button lives at the end of the panel below, so
   there is never more than one thing to press. */
.fcard__btn--wait.is-ready {
  background: rgba(90, 168, 123, 0.22) !important;
  color: #cfe9da;
}

/* Arcade sizing (v0.9.12) ------------------------------------------------- */

.fcard__meta {
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-size: 0.6875rem;
  opacity: 0.82;
}

.fcard__btn {
  font-size: 0.9375rem;
  padding: 0.45rem 1.35rem;
  letter-spacing: 0.01em;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}
.fcard__btn--go { font-size: 1rem; padding: 0.5rem 1.6rem; }

/* A darkened floor under the cabinet so the button and meta always read,
   whatever the generated background is doing behind them. */
.fcard__inner::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 45%;
  background: linear-gradient(to top, rgba(6, 9, 14, 0.55), transparent);
  pointer-events: none;
  z-index: 0;
}
.fcard__inner > * { position: relative; z-index: 1; }

/* Landing page faucet preview: the real card, without the claim action. */
.fcard--peek { min-height: 9.5rem; cursor: default; }
.fcard--peek .fcard__inner { padding-bottom: 1.1rem; }

.hero h1 { max-width: 20ch; }

/* ===========================================================================
   Ad slots (v0.9.3)

   Network tags arrive with their own fixed dimensions — a leaderboard is 728
   pixels wide regardless of where it is put. Dropped into a narrow column it
   overflowed to the right on desktop and ran clean off the screen on a phone.

   The slot therefore does three things: centres the tag, scales anything that
   can be scaled down to fit, and keeps whatever still will not fit inside the
   slot rather than letting it stretch the page.
   ========================================================================= */

.ad-slot {
  margin: 1.1rem 0;
  text-align: center;
  max-width: 100%;

  /* A tag that genuinely cannot shrink — a fixed-size iframe — scrolls within
     its own slot. The page itself never gains a horizontal scrollbar. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Images scale properly, which covers most banner and referral creatives. */
.ad-slot img {
  max-width: 100%;
  height: auto;
  display: inline-block;
  vertical-align: middle;
}

/* Iframes and script-injected wrappers cannot reflow their contents, but they
   can at least be stopped from widening the document. */
.ad-slot iframe,
.ad-slot ins,
.ad-slot object,
.ad-slot embed,
.ad-slot > div,
.ad-slot > a {
  max-width: 100%;
}

/* Nothing in an ad slot may push the page wider than the viewport. */
.ad-slot * { box-sizing: border-box; }

body { overflow-x: hidden; }

/* Settings (v1.1.2) — one section at a time, with search across all of them. */
.settings-nav { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.75rem; }
.is-hidden { display: none !important; }

.settings-group .hint details summary {
  cursor: pointer;
  list-style: none;
  color: var(--muted);
}
.settings-group .hint details summary::-webkit-details-marker { display: none; }
.settings-group .hint details summary:hover { color: var(--ink-2); }
.settings-group .hint details[open] summary { display: none; }

.settings-save { position: sticky; bottom: 0; padding: 0.9rem 0; background: var(--bg); }

/* ===========================================================================
   Timer dial and stages (v1.2.0)

   A ring that empties rather than a bar that fills. The number in the middle is
   the thing people watch, so it is large and the ring is the supporting detail.
   Coloured from the faucet's own accent so the wait belongs to the machine you
   are standing at.
   ========================================================================= */

.dial {
  position: relative;
  width: 132px;
  height: 132px;
  margin: 0.4rem auto 0;
}
.dial svg { transform: rotate(-90deg); display: block; }

.dial__track {
  fill: none;
  stroke: rgba(255, 255, 255, 0.09);
  stroke-width: 8;
}
.dial__sweep {
  fill: none;
  stroke: var(--dial-accent, var(--ready));
  stroke-width: 8;
  stroke-linecap: round;
  transition: stroke-dashoffset 0.95s linear;
}

.dial__inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  pointer-events: none;
}
.dial__num {
  font-family: var(--display);
  font-size: 2.35rem;
  font-weight: 700;
  line-height: 1;
  color: var(--ink-1);
}
.dial__unit {
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Stage pips: how far through, at a glance. */
.stagerow {
  display: flex;
  gap: 0.35rem;
  justify-content: center;
  margin: 0.5rem 0 0.2rem;
}
.stagepip {
  width: 30px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.12);
}
.stagepip.is-done { background: var(--good); }
.stagepip.is-now  { background: var(--ready); }

/* ===========================================================================
   Ticker, rain and hidden faucets (v1.3.0)
   ========================================================================= */

.ticker {
  position: relative;
  min-height: 2.4rem;
  display: flex;
  align-items: center;
  padding: 0.55rem 0.9rem;
  margin-bottom: 0.9rem;
  border-left: 3px solid var(--ready);
  border-radius: var(--r);
  background: rgba(255, 255, 255, 0.03);
  font-size: 0.9375rem;
}
.ticker__item {
  position: absolute;
  left: 0.9rem;
  right: 0.9rem;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.45s ease, transform 0.45s ease;
  pointer-events: none;
}
.ticker__item.is-live { opacity: 1; transform: none; pointer-events: auto; }

.fgrid--one { grid-template-columns: minmax(0, 22rem); justify-content: center; }
.hidden-find { animation: hidden-arrive 0.5s ease; }
@keyframes hidden-arrive {
  from { opacity: 0; transform: translateY(-6px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}

/* Rain: a short shower over the whole board, then it clears. */
.rain-overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 40;
  overflow: hidden;
  opacity: 1;
  transition: opacity 2.5s ease;
}
.rain-overlay.is-clearing { opacity: 0; }

.rain-drop {
  position: absolute;
  top: -12%;
  width: 1px;
  height: 46px;
  background: linear-gradient(to bottom, rgba(142, 202, 230, 0), rgba(142, 202, 230, 0.85));
  animation: rain-fall linear infinite;
}
@keyframes rain-fall {
  to { transform: translateY(115vh); }
}

.modal {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(6, 9, 14, 0.72);
  z-index: 50;
}
.modal.is-open { display: flex; }
.modal__box { max-width: 26rem; width: 100%; margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .rain-drop { animation: none; opacity: 0 !important; }
  .ticker__item { transition: none; }
}

/* ===========================================================================
   Upgraded values (v1.6.3)

   A number that changed because somebody paid for it has to look like it
   changed. "12m" with a quiet note beside it reads as the faucet's own figure;
   the old value struck through in red next to the new one in green reads as a
   discount, which is what it is.
   ========================================================================= */

.was {
  font-family: var(--mono);
  color: #ff6b6b;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  margin-right: 0.45rem;
  opacity: 0.85;
}

.now {
  font-family: var(--mono);
  color: #4ade80;
  font-weight: 700;
}

.upgrade-why {
  margin-top: 0.15rem;
  font-size: 0.75rem;
  letter-spacing: 0.01em;
}

/* ===========================================================================
   Collapsed provider rows (v1.10.0)

   Nine shortlink providers with every edit form open is a page nobody can scan.
   Collapsed, the list is the thing you see; the form is one click away and a
   failing provider opens itself.
   ========================================================================= */

.prov { padding: 0; }
.prov > *:not(summary) { padding: 0 1rem; }
.prov > *:last-child { padding-bottom: 1rem; }

.prov__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 1rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.prov__head::-webkit-details-marker { display: none; }
.prov__head:hover { background: rgba(255, 255, 255, 0.03); }

.prov__name {
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.0625rem;
}
.prov__name::before {
  content: '▸';
  display: inline-block;
  margin-right: 0.5rem;
  color: var(--muted);
  transition: transform 0.15s ease;
}
.prov[open] .prov__name::before { transform: rotate(90deg); }

.prov__stats { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
