/* ==========================================================================
   The Next Coin Club — Component Library
   Custom icons, tiles, charts, rings, avatar stacks, media.
   Loads after app.css.
   ========================================================================== */

/* --- Icons --------------------------------------------------------------- */
.ic{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.6;
    stroke-linecap:round;stroke-linejoin:round;display:block;flex-shrink:0}
.ic.sm{width:17px;height:17px;stroke-width:1.8}
.ic.lg{width:26px;height:26px;stroke-width:1.5}

/* --- Icon tile grid (the mockup's nav tiles) ----------------------------- */
.tiles{display:grid;grid-template-columns:repeat(6,1fr);gap:10px}
.tile{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;
      padding:18px 8px;border-radius:var(--r-md);background:var(--sunk);border:1px solid transparent;
      color:var(--dim);cursor:pointer;overflow:hidden;isolation:isolate;
      transition:transform var(--t-base) var(--spring),background var(--t-base),color var(--t-base),border-color var(--t-base)}
.tile:hover{background:var(--raised);border-color:var(--hair);color:var(--text);transform:translateY(-2px);box-shadow:var(--sh-sm)}
.tile:active{transform:scale(.97)}
.tile span{font-size:10.5px;letter-spacing:.06em;font-weight:500;text-align:center;line-height:1.2}
.tile.on{background:var(--btn-bg);color:var(--btn-fg);border-color:var(--btn-bg);box-shadow:var(--sh-sm)}
.tile.on:hover{color:var(--btn-fg)}
@media(max-width:760px){.tiles{grid-template-columns:repeat(3,1fr)}}

/* --- Icon chip (icon in a rounded square, inline) ------------------------ */
.chip{width:40px;height:40px;border-radius:12px;background:var(--sunk);border:1px solid var(--hair);
      display:flex;align-items:center;justify-content:center;color:var(--text);flex-shrink:0}
.chip.solid{background:var(--btn-bg);color:var(--btn-fg);border-color:var(--btn-bg)}
.chip.lg{width:52px;height:52px;border-radius:15px}

/* --- Area chart ---------------------------------------------------------- */
.chart{position:relative;width:100%}
.chart svg{width:100%;height:auto;display:block;overflow:visible}
.chart .gridline{stroke:var(--hair);stroke-width:1}
.chart .axis{fill:var(--mute);font-size:9.5px;font-family:var(--sans)}
.chart .line{fill:none;stroke:var(--text);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:1000;stroke-dashoffset:1000;animation:draw 1.8s var(--ease) forwards}
@keyframes draw{to{stroke-dashoffset:0}}
.chart .area{opacity:0;animation:fadein .9s var(--ease) .7s forwards}
@keyframes fadein{to{opacity:1}}
.chart .pt{fill:var(--raised);stroke:var(--text);stroke-width:2.5}
.chart .tip{fill:var(--btn-bg)}
.chart .tiptext{fill:var(--btn-fg);font-size:10.5px;font-weight:600;font-family:var(--sans)}
@media (prefers-reduced-motion:reduce){
  .chart .line{animation:none;stroke-dashoffset:0}.chart .area{animation:none;opacity:1}
}

/* --- Progress ring ------------------------------------------------------- */
.ring{position:relative;display:inline-flex;align-items:center;justify-content:center}
.ring svg{transform:rotate(-90deg);display:block}
.ring .track{stroke:var(--hair);fill:none}
.ring .fill{stroke:var(--text);fill:none;stroke-linecap:round;
  transition:stroke-dashoffset 1.2s var(--ease)}
.ring .val{position:absolute;font-size:13px;font-weight:600;letter-spacing:-.02em}

/* --- Avatar stack -------------------------------------------------------- */
.avstack{display:flex;align-items:center}
.avstack .a{width:30px;height:30px;border-radius:50%;border:2px solid var(--raised);margin-left:-9px;
            background:var(--sunk);display:flex;align-items:center;justify-content:center;
            font-size:11px;font-weight:600;color:var(--dim);overflow:hidden}
.avstack .a:first-child{margin-left:0}
.avstack .more{margin-left:8px;font-size:12px;color:var(--mute);border:1px solid var(--hair);
               border-radius:var(--r-pill);padding:4px 9px}

/* --- Carousel dots ------------------------------------------------------- */
.dots{display:flex;gap:6px;justify-content:center;margin-top:16px}
.dots i{width:6px;height:6px;border-radius:50%;background:var(--hair2);transition:all var(--t-base)}
.dots i.on{background:var(--text);width:18px;border-radius:var(--r-pill)}

/* --- Media / hero art ---------------------------------------------------- */
.media{position:relative;border-radius:var(--r-lg);overflow:hidden;background:var(--sunk);
       border:1px solid var(--hair);box-shadow:var(--sh-md)}
.media img{width:100%;height:100%;object-fit:cover;display:block}
.media.tall{aspect-ratio:4/5}
.media.wide{aspect-ratio:16/10}
.media .cap{position:absolute;left:0;right:0;bottom:0;padding:22px;
  background:linear-gradient(to top,rgba(0,0,0,.82),transparent);color:#fff}
.media .cap h4{font-family:var(--serif);font-size:21px;font-weight:400;letter-spacing:-.012em}
.media .cap p{font-size:13.5px;opacity:.82;margin-top:5px}
/* placeholder when no art supplied */
.media.ph{display:flex;align-items:center;justify-content:center;flex-direction:column;gap:10px;
  color:var(--mute);text-align:center;padding:30px;min-height:220px;
  background:radial-gradient(ellipse at 50% 0%,var(--glow),transparent 70%),var(--sunk)}
.media.ph .t{font-size:13px;max-width:230px;line-height:1.55}

/* --- Feature card with icon --------------------------------------------- */
.fcard{padding:26px}
.fcard .chip{margin-bottom:16px}
.fcard h3{font-size:17px;font-weight:600;letter-spacing:-.012em;margin-bottom:8px}
.fcard p{color:var(--dim);font-size:14.5px;line-height:1.6}

/* --- Stat block ---------------------------------------------------------- */
.stat .lbl{color:var(--mute);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;font-weight:600}
.stat .big{font-size:clamp(28px,4vw,38px);font-weight:600;letter-spacing:-.03em;line-height:1.1;margin-top:8px}
.stat .delta{display:inline-flex;align-items:center;gap:5px;font-size:12.5px;font-weight:500;
  color:var(--ok);background:var(--ok-bg);border:1px solid var(--ok-bd);border-radius:var(--r-pill);
  padding:3px 9px;margin-top:9px}

/* --- Floating centre action (mockup's tab-bar logo button) ---------------
   DO NOT set `position` on .tabs here. app.css pins the bar with
   position:fixed, and because this file loads afterwards at equal
   specificity, any position declared here silently wins and drops the tab
   bar into normal flow at the very bottom of the document — you then only
   see it after scrolling to the end of the page, instead of it staying
   locked above the content like a native app.

   The floating button does not need it. Its containing block is .center,
   which establishes its own stacking context on the next line. */
.tabs .center{position:relative;flex:1;display:flex;justify-content:center}
.tabs .center .fab{position:absolute;top:-24px;width:52px;height:52px;border-radius:50%;
  background:var(--btn-bg);color:var(--btn-fg);display:flex;align-items:center;justify-content:center;
  box-shadow:var(--sh-md);border:3px solid var(--bg);
  transition:transform var(--t-base) var(--spring)}
.tabs .center .fab:active{transform:scale(.93)}
.tabs .center .fab svg{width:26px;height:26px}


/* ==========================================================================
   REFINEMENTS
   --------------------------------------------------------------------------
   Elevation-aware upgrades to the components above. Every value reads from
   the e0–e4 / --inset-* scale defined in effects.css, with the original
   app.css shadow as the var() fallback — so this section is a no-op
   improvement if effects.css is not loaded, and a coherent physical
   material system when it is. Nothing here changes geometry, so no existing
   layout can shift.
   ========================================================================== */

/* --- Icons: optical weight ------------------------------------------------
   Stroke weight should hold constant APPARENT density as icons scale. A
   1.6px stroke on a 22px icon and the same 1.6px on a 26px icon are not the
   same drawing — the large one reads lighter. app.css already steps the
   values; this adds the missing piece: on dark grounds a light stroke
   blooms and reads heavier, so we shave it back. */
[data-theme="dark"] .ic{stroke-width:1.5}
[data-theme="dark"] .ic.sm{stroke-width:1.7}
[data-theme="dark"] .ic.lg{stroke-width:1.4}
.ic{transition:stroke-width var(--t-base) var(--ease)}

/* --- Tiles: press physics + specular -------------------------------------
   The tile was scaling on :active with the same easing it used to rise,
   which makes the press feel mushy. Split the timing: fast compression,
   sprung release. The specular sweep gives the tile a lit face so the grid
   reads as a row of physical keys rather than flat swatches. */
.tile{
  transition:transform var(--t-release,.42s) var(--press-out,var(--spring)),
             background var(--t-base),color var(--t-base),
             border-color var(--t-base),box-shadow var(--t-base) var(--ease);
}
/* NOTE on stacking: .tile sets `isolation:isolate`, which creates a
   stacking context — so a `z-index:-1` pseudo-element would paint BEHIND
   the tile's own background and never be seen. The glow therefore sits at
   z-index 0 (above the background, below content) and the tile's children
   are lifted to z-index 1. */
.tile::after{
  content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:0;
  background:radial-gradient(120px circle at 50% 0%,
    color-mix(in srgb,var(--text) 7%,transparent),transparent 70%);
  opacity:0;transition:opacity var(--t-base) var(--ease);
}
.tile>*{position:relative;z-index:1}
.tile:hover{box-shadow:var(--e1,var(--sh-sm))}
.tile:hover::after{opacity:1}
.tile:active{
  transform:scale(.965);
  box-shadow:var(--e0,none);
  transition-duration:var(--t-press,.11s);
  transition-timing-function:var(--press-in,var(--ease));
}
.tile.on::after{opacity:0}
.tile.on:hover{box-shadow:var(--e2,var(--sh-md))}
/* Focus must be visible on the dark solid `.on` state too. */
.tile:focus-visible{outline-offset:2px}
.tile.on:focus-visible{box-shadow:var(--e2,var(--sh-md)),
  inset 0 0 0 1.5px color-mix(in srgb,var(--btn-fg) 55%,transparent)}

/* --- Chips: material correctness -----------------------------------------
   A chip is a recessed well holding an icon, so it takes an inner shadow,
   not a drop shadow. The solid variant is the inverse — a raised key — so
   it takes elevation plus a top rim. */
.chip{box-shadow:var(--inset-1,none);transition:box-shadow var(--t-base) var(--ease),
      transform var(--t-base) var(--ease)}
.chip.solid{box-shadow:var(--e1,var(--sh-sm))}
/* Inside a feature card, the chip rises with the card — a small parallax
   that makes the card feel like it has depth rather than being a picture
   of a card. */
.fcard:hover .chip{transform:translateY(-2px)}
.fcard .chip{transition:transform var(--t-slow) var(--ease),box-shadow var(--t-base) var(--ease)}

/* --- Chart ---------------------------------------------------------------
   `overflow:visible` on the svg let the terminal point and any tooltip
   escape the plot box, which is correct — but it also meant the crosshair
   utilities in effects.css had no positioning context inside the plot area.
   `.chart` was already relative; this just guarantees the SVG establishes
   the same coordinate space the crosshair percentages assume. */
.chart{isolation:isolate}
.chart svg{color:var(--text)}          /* anchor currentColor for gradient stops */
.chart .gridline{stroke:var(--hair);shape-rendering:crispEdges}
.chart .pt{filter:drop-shadow(0 1px 2px rgba(0,0,0,.18))}
/* Axis labels should never compete with the data. */
.chart .axis{font-variant-numeric:tabular-nums;letter-spacing:.02em}

/* --- Ring: draw-on + numeric discipline ---------------------------------- */
.ring .track{stroke-linecap:round;opacity:.85}
.ring .fill{transition:stroke-dashoffset 1.2s var(--ease),stroke var(--t-base)}
.ring .val{font-variant-numeric:tabular-nums slashed-zero}

/* --- Avatar stack: fan on hover ------------------------------------------
   Overlapped avatars hide identity. On hover the stack relaxes its overlap
   so every face becomes visible. Uses margin (the property that creates the
   overlap) rather than transform, because transforms would slide the faces
   out of the group's bounding box and clip against neighbouring content.
   Cheap: this is a handful of elements, once, on hover. */
.avstack .a{transition:margin-left var(--t-slow) var(--ease),
            border-color var(--t-base),transform var(--t-base) var(--ease)}
.avstack:hover .a{margin-left:-4px}
.avstack:hover .a:first-child{margin-left:0}
.avstack .a:hover{transform:translateY(-2px);z-index:1;position:relative}

/* --- Carousel dots: honest transitions ------------------------------------
   `transition:all` on a dot means the browser watches ~200 properties for
   change on every frame. Name the two that actually animate. */
.dots i{transition:width var(--t-base) var(--ease),background var(--t-base)}

/* --- Media: contained motion ---------------------------------------------
   A slow scale on the image inside a fixed frame is the one photographic
   effect that reads as editorial rather than as a web page. Kept to 1.03
   and 700ms — any more and it becomes a real-estate listing. The caption
   gradient gains a second, softer stop so the fade has no visible edge. */
.media img{transition:transform .7s var(--ease)}
.media:hover img{transform:scale(1.03)}
.media .cap{background:linear-gradient(to top,
  rgba(0,0,0,.86) 0%,rgba(0,0,0,.55) 42%,rgba(0,0,0,.18) 72%,transparent 100%)}
.media.ph{box-shadow:var(--inset-1,none)}
@media (prefers-reduced-motion:reduce){
  .media:hover img{transform:none}
  .avstack:hover .a{margin-left:-9px}
  .avstack:hover .a:first-child{margin-left:0}
  .fcard:hover .chip{transform:none}
  .tile:active{transform:none}
}

/* --- Stat: figures deserve their own typography --------------------------
   Big numbers set with proportional figures wobble as they update. Tabular
   + slashed zero + tightened tracking makes a changing figure hold its
   position, which is the difference between a dashboard and a slideshow. */
.stat .big{font-variant-numeric:tabular-nums slashed-zero;font-feature-settings:'tnum' 1,'zero' 1}
.stat .delta{font-variant-numeric:tabular-nums}
.stat .lbl{font-feature-settings:'ss01' 1}

/* --- Feature card --------------------------------------------------------
   Headings inside cards were inheriting the sans stack at 17px/600, which
   is correct — but the measure was unconstrained, so a long title could run
   the full width of a wide card and break the vertical rhythm. */
.fcard h3{max-width:26ch;text-wrap:balance}
.fcard p{max-width:44ch;text-wrap:pretty}

/* --- FAB: press physics + rim ---------------------------------------------
   The floating action button is the highest object in the member shell, so
   it gets the top of the elevation scale and a light rim that separates it
   from the frosted tab bar behind it. */
.tabs .center .fab{
  box-shadow:var(--e3,var(--sh-md));
  transition:transform var(--t-release,.42s) var(--press-out,var(--spring)),
             box-shadow var(--t-base) var(--ease);
}
.tabs .center .fab:active{
  transform:scale(.93);
  box-shadow:var(--e1,var(--sh-sm));
  transition-duration:var(--t-press,.11s);
  transition-timing-function:var(--press-in,var(--ease));
}
@media (prefers-reduced-motion:reduce){ .tabs .center .fab:active{transform:none} }

/* ── Points ───────────────────────────────────────────────────────────────
   Namespaced ptx- because .pt and .prow already exist in this codebase and
   collided. Everything here uses existing theme tokens, so it follows light
   and dark without a second definition. */
.ptx-row{display:flex;align-items:center;gap:12px;padding:10px 0;
  border-bottom:1px solid var(--hair);font-size:14px}
.ptx-row:last-child{border-bottom:0}
.ptx-k{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ptx-t{color:var(--mute);font-size:12px;flex-shrink:0}
.ptx-d{font-variant-numeric:tabular-nums;font-weight:600;flex-shrink:0;min-width:52px;text-align:right}
.ptx-d.up{color:var(--ok,var(--text))}
.ptx-d.down{color:var(--mute)}
.ptx-mine{background:var(--sunk);margin:0 -10px;padding-left:10px;padding-right:10px;border-radius:8px}
.ptx-muted{color:var(--mute);font-size:13px}
.ptx-flash{display:inline-block;margin-left:9px;font-size:12.5px;color:var(--ok,var(--text));
  animation:ptxfade .25s ease-out}
.ptx-flash.ptx-bad{color:var(--bad,var(--mute))}
@keyframes ptxfade{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.ptx-flash{animation:none}}

/* Badges — rendered from my_badges(), never hardcoded. Named bdgx to avoid
   the existing .bdg rules, which assumed a decorative icon chip that the
   real badges do not have. */
.bdgx{padding:16px 14px;border-radius:var(--r-md);border:1px solid var(--hair);
  background:var(--raised);display:flex;flex-direction:column;gap:6px}
.bdgx.locked{opacity:.5}
.bdgx b{font-size:13.5px;font-weight:600;line-height:1.3}
.bdgx span{color:var(--dim);font-size:11.5px;line-height:1.45}
.bdgx i{font-style:normal;font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  font-weight:600;margin-top:auto;padding-top:4px}
.bdgx-got{color:var(--ok,var(--text))}
.bdgx-todo{color:var(--mute)}
