/* ================================================================
   MyPedra — sculpted.css
   The "sculpted control surface" material language, ported onto the
   SITE's existing design tokens.

   Deliberately does NOT redefine :root. The app already themes itself
   through --accent / --purple / --cyan with html[data-accent] and
   [data-mode] overrides, so shipping the lab's own :root block would
   have overwritten whichever accent the user picked. Everything here
   derives from tokens the site already owns, which means the sculpted
   surfaces re-tint themselves for free when the theme changes.

   The rules from the lab still hold: one light direction (top-left),
   colour only ever EMITTED from a recess rather than painted on, and
   geometry varied by function so surfaces never read as a card grid.
================================================================ */

:root {
  /* light + shade, derived so they work over any surface token */
  --sc-lt:       rgba(255,255,255,0.055);
  --sc-lt-hi:    rgba(255,255,255,0.10);
  --sc-sh:       rgba(0,0,0,0.50);
  --sc-sh-deep:  rgba(0,0,0,0.70);
  --sc-ease:     cubic-bezier(.22,1,.36,1);
}
html[data-mode="light"] {
  --sc-lt:       rgba(255,255,255,0.9);
  --sc-lt-hi:    rgba(255,255,255,1);
  --sc-sh:       rgba(15,20,30,0.13);
  --sc-sh-deep:  rgba(15,20,30,0.20);
}

/* ── material primitives ─────────────────────────────────────── */
.sc-up {                                   /* raised — things you press */
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--card));
  box-shadow: -5px -5px 13px var(--sc-lt), 7px 9px 20px var(--sc-sh), inset 0 1px 0 var(--sc-lt-hi);
}
.sc-in {                                   /* pressed — readouts, wells */
  background: linear-gradient(154deg, var(--bg2, var(--bg)), var(--card));
  box-shadow: inset 5px 5px 13px var(--sc-sh), inset -3px -3px 11px var(--sc-lt);
}

.sc-trough {
  border-radius: 14px; padding: 15px 17px;
  background: linear-gradient(154deg, var(--bg2, var(--bg)), var(--card));
  box-shadow: inset 5px 5px 13px var(--sc-sh), inset -3px -3px 11px var(--sc-lt);
}
.sc-plinth {
  border-radius: 20px; padding: 20px;
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--card));
  box-shadow: -5px -5px 13px var(--sc-lt), 7px 9px 20px var(--sc-sh), inset 0 1px 0 var(--sc-lt-hi);
  transition: transform 320ms var(--sc-ease), box-shadow 320ms var(--sc-ease);
}
.sc-plinth.lift:hover { transform: translateY(-3px); box-shadow: -7px -7px 17px var(--sc-lt), 12px 18px 36px var(--sc-sh-deep), inset 0 1px 0 var(--sc-lt-hi); }

.sc-rail {
  height: 8px; border-radius: 99px; overflow: hidden;
  background: var(--bg2, var(--bg));
  box-shadow: inset 3px 3px 7px var(--sc-sh), inset -2px -2px 6px var(--sc-lt);
}
.sc-rail > i {
  display: block; height: 100%; border-radius: 99px;
  background: var(--sc-emit, var(--accent));
  box-shadow: 0 0 14px -2px var(--sc-emit, var(--accent));
  transition: width 620ms var(--sc-ease);
}

/* ── DOCK — proximity-magnified primary navigation ───────────── */
.dock {
  display: flex; align-items: flex-end; gap: 10px;
  padding: 10px 14px 12px; border-radius: 22px;
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--card));
  box-shadow: -7px -7px 17px var(--sc-lt), 10px 14px 36px var(--sc-sh-deep), inset 0 1px 0 var(--sc-lt-hi);
  border: 1px solid var(--bdr);
}
.dock-item {
  --lift: 0; --emit: var(--accent);
  position: relative; flex: none;
  width: 44px; height: 44px; border: 0; padding: 0; cursor: pointer;
  border-radius: 50%; text-decoration: none;
  display: grid; place-items: center;
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--bg2, var(--bg)));
  box-shadow:
    calc(-2px - var(--lift) * 3px) calc(-2px - var(--lift) * 3px) calc(7px + var(--lift) * 8px) var(--sc-lt),
    calc( 3px + var(--lift) * 5px) calc( 4px + var(--lift) * 7px) calc(10px + var(--lift) * 16px) var(--sc-sh),
    inset 0 1px 0 var(--sc-lt-hi);
  transform: translateY(calc(var(--lift) * -4px));
  color: var(--t2);
  transition: color 180ms;
}
.dock-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.dock-glyph { display: grid; place-items: center; width: 46%; height: 46%; color: inherit; }
.dock-glyph svg { width: 100%; height: 100%; stroke-width: 2; fill: none; stroke: currentColor; }
.dock-item.on, .dock-item:hover { color: var(--t1); }
.dock-item::before {            /* colour only as escaping light */
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 16px -3px var(--emit);
  opacity: calc(var(--lift) * 0.9);
}
.dock-item.on::before { opacity: 1; }
.dock-item.on { color: var(--t1); }
/* Labels ride the same --lift the magnification uses, so the name of whatever
   you are reaching for surfaces along with its neighbours' and everything else
   stays quiet. The curve is steep on purpose: multiplying lift means the far
   items never reach legibility, so only the two or three under the cursor read
   at once and their labels cannot pile up. Rising slightly as they arrive ties
   them to the button lifting under the same pointer. */
.dock-label {
  position: absolute; bottom: -14px; left: 50%;
  transform: translateX(-50%) translateY(calc((1 - var(--lift)) * 3px));
  font: 700 8px var(--font-body); letter-spacing: 1px; text-transform: uppercase;
  color: var(--t3); white-space: nowrap; pointer-events: none;
  opacity: calc(var(--lift) * 1.9 - 0.45);
}
/* The one you are actually on gets full contrast, not just full opacity. */
.dock-item:hover .dock-label, .dock-item:focus-visible .dock-label { color: var(--t1); }
.dock-tip {
  position: absolute; top: -32px; left: 50%; transform: translateX(-50%) translateY(4px);
  padding: 5px 10px; border-radius: 8px; white-space: nowrap;
  font: 600 11.5px var(--font-body); color: var(--t1);
  background: var(--bg2, var(--bg)); border: 1px solid var(--bdr);
  box-shadow: 0 6px 18px var(--sc-sh-deep);
  opacity: 0; pointer-events: none; transition: opacity 180ms, transform 180ms;
}
.dock-item:hover .dock-tip, .dock-item:focus-visible .dock-tip { opacity: 1; transform: translateX(-50%) translateY(0); }

/* The dock sits in a band of its own between the top bar and the page title —
   floating it at the bottom put it over page content and moved navigation to
   a place nobody was looking, and sitting inside the bar crowded the wordmark.

   It was briefly put ON the title's line. Centred there it painted over every
   long title (Worldwide Leaderboard by 524px), and the cap needed to prevent
   that works out to a flat 232px at any desktop width — narrower than the word
   WORLDWIDE on its own, and a single word wider than its max-width overflows
   rather than wraps, so the collision came back anyway. Right-aligning cleared
   the titles but left the dock stranded against the edge on Home and Settings,
   which have no title beside it.

   Its own band is the version that survives both: centred at every width, and
   nothing to collide with because the views below reserve the height. */
.dock-shell {
  position: fixed; left: 50%; transform: translateX(-50%);
  top: calc(var(--nav-h) + 12px + var(--sat, 0px));
  /* above the navbar (z-index 100) — the bar paints a background, so anything
     below it in the stack is simply invisible even when correctly placed */
  z-index: 110;
  pointer-events: auto;
}
/* The gap has to clear the LABELS, not the icons. Labels are absolutely
   positioned, centred and nowrap, so a word like EXERCISES is wider than the
   38px button it belongs to and bleeds past it on both sides. At the old 8px
   gap that bleed met the neighbour's and read as one run-on word
   ("EXERCISESCALCULATOR"). 20px keeps the widest pair apart. */
.dock-shell .dock { padding: 4px 12px 14px; gap: 20px; border-radius: 16px; }
/* No width/height here on purpose: dock.js drives item size inline from its
   spring (REST 46 → PEAK 74), so any rule here is silently overridden. Change
   the magnification range in dock.js, not in CSS. */
@media (max-width: 900px) { .dock-shell { display: none; } }

/* The dock is fixed, so nothing in flow knows it is there. The views have to
   reserve its band themselves or the page title starts underneath it.

   Height of the reservation: 12px above the pill, the pill's own 66px, then
   16px of air before the title's 24px top margin. Only where the dock is
   actually mounted (has-dock) and actually visible (901px and up) — on a phone
   the staggered menu handles navigation and this band would be dead space. */
@media (min-width: 901px) {
  /* 12px above the pill + its 66px + 4px of air, so the header band that every
     view opens with starts below the dock rather than 7px behind its bottom
     edge. Invisible while the two backgrounds match; not something to leave. */
  body.has-dock { --dock-band: 82px; }
  body.has-dock .view { padding-top: calc(var(--nav-h) + var(--dock-band)); }

  /* Chat sets its own top padding through an ID selector and sizes its column
     off the viewport, so the generic rule above loses to it on specificity and
     the dock landed on top of the chat header. Same band, stated where it can
     win, and the column loses the same height so the composer stays on screen. */
  body.has-dock #view-chat { padding-top: calc(var(--nav-h) + var(--dock-band)); }
  /* --view-pb has to come out of these too. The view's own bottom padding sits
     BELOW this column, so sizing the column to the full remaining viewport
     pushed the page that many pixels past the fold — a scrollbar on a screen
     with nothing to scroll to. */
  body.has-dock .chat-wrap { height: calc(var(--vh) - var(--nav-h) - var(--dock-band) - var(--view-pb)); }
  body.has-dock .chat-gate {
    padding-top: calc(var(--nav-h) + var(--dock-band));
    min-height: calc(var(--vh) - var(--nav-h) - var(--dock-band) - var(--view-pb));
  }
}

/* ── STAGGERED MENU — mobile navigation ──────────────────────── */
.sm-wrap { position: fixed; inset: 0; z-index: 80; pointer-events: none; }
.sm-wrap > * { pointer-events: auto; }
.sm-prelayers, .sm-panel {
  position: absolute; top: 0; bottom: 0; right: 0; width: min(88vw, 420px);
}
.sm-wrap[data-position="left"] .sm-prelayers,
.sm-wrap[data-position="left"] .sm-panel { right: auto; left: 0; }
.sm-prelayers { pointer-events: none; }
.sm-prelayer { position: absolute; inset: 0; opacity: 0.92; }
.sm-panel {
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--bg));
  box-shadow: -24px 0 60px rgba(0,0,0,0.55), inset 1px 0 0 var(--sc-lt);
  padding: calc(88px + var(--sat, 0px)) 28px calc(28px + var(--sab, 0px));
  overflow-y: auto; display: flex; flex-direction: column;
}
.sm-toggle {
  position: fixed; top: calc(14px + var(--sat, 0px)); right: 16px; z-index: 3;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 10px 15px; border: 1px solid var(--bdr); border-radius: 999px; cursor: pointer;
  font: 700 12.5px var(--font-body); letter-spacing: 0.4px; color: var(--t1);
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--card));
  box-shadow: -3px -3px 9px var(--sc-lt), 4px 6px 14px var(--sc-sh), inset 0 1px 0 var(--sc-lt-hi);
}
.sm-toggle-textWrap { height: 1em; overflow: hidden; display: inline-block; }
.sm-toggle-textInner { display: flex; flex-direction: column; transition: transform 420ms var(--sc-ease); }
.sm-toggle-line { height: 1em; line-height: 1; }
.sm-icon { position: relative; width: 13px; height: 13px; transition: transform 620ms var(--sc-ease); }
.sm-icon-line { position: absolute; left: 50%; top: 50%; width: 100%; height: 2px; border-radius: 2px; background: currentColor; transform: translate(-50%,-50%); }
.sm-icon-line-v { transform: translate(-50%,-50%) rotate(90deg); }
.sm-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.sm-itemWrap { overflow: hidden; line-height: 1; }
.sm-item {
  --num-o: 0;
  position: relative; display: block; padding: 9px 2.6em 9px 0;
  font-family: var(--font-display); font-weight: 800; font-size: clamp(27px, 7.6vw, 40px);
  text-transform: uppercase; letter-spacing: -0.5px; line-height: 1;
  color: var(--t1); text-decoration: none; transition: color 180ms;
}
.sm-item:hover, .sm-item.on { color: var(--accent); }
.sm-item::after {
  content: attr(data-index);
  position: absolute; right: 0.4em; top: 50%; transform: translateY(-50%);
  font-family: var(--font-data, monospace); font-size: 12px; font-weight: 500; letter-spacing: 0;
  color: var(--accent); opacity: var(--num-o);
}
.sm-itemLabel { display: inline-block; will-change: transform; transform-origin: 50% 100%; }
.sm-foot { margin-top: auto; padding-top: 24px; font: 400 12.5px var(--font-body); color: var(--t3); }
@media (min-width: 901px) { .sm-wrap { display: none; } }

/* the dock replaces the old link row; keep the bar for brand + account */
@media (min-width: 901px) {
  .navbar .nav-links { display: none !important; }
}

/* ════════════════════════════════════════════════════════════════
   RETROFIT — give the existing app surfaces the sculpted material.
   Done by restyling the classes the app already uses rather than
   rewriting every view's markup: less churn, and any screen added
   later inherits it automatically. Every value below is derived from
   the site's own theme tokens, so switching accent or light mode
   re-tints these surfaces for free.
════════════════════════════════════════════════════════════════ */

/* the dock floats over the page, so app views need room beneath them */
/* The view's bottom padding is a variable because three other rules have to
   subtract it. Written as a literal in each of them, it drifted: the chat
   column was sized to the whole remaining viewport and then had this padding
   added underneath it, so the page ran 12-14px past the fold and every screen
   that should have fitted exactly got a short, pointless scrollbar. */
:root { --view-pb: 0px; }
body.has-dock { --view-pb: 14px; }
@media (max-width: 900px) { body.has-dock { --view-pb: 12px; } }
body.has-dock .view { padding-bottom: var(--view-pb); }

/* The dock claims 142px off the top of every view (navbar + band). Sections
   below it still carried the 64px bottom padding they were given when that
   space was theirs, and with --view-pb underneath that made 78px of stacked
   padding — enough to tip pages whose content otherwise fitted a 900px window
   just past the fold. Measured: workouts overflowed by 31px and the calculator
   by 44px with nothing at the bottom to scroll to.

   Only applied where the dock exists. Without it the original spacing is
   correct, because the 142px was never taken. */
@media (min-width: 901px) {
  body.has-dock .workout-layout,
  body.has-dock .calc-layout,
  body.has-dock .dashboard-section,
  body.has-dock .auth-container { padding-bottom: 20px; }
}

/* raised blocks — things you act on */
.dash-panel,
.idea-card,
.ex-card,
.prem-card,
.auth-card,
.settings-card {
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--card)) !important;
  box-shadow: -5px -5px 13px var(--sc-lt), 7px 9px 20px var(--sc-sh), inset 0 1px 0 var(--sc-lt-hi) !important;
  border: 1px solid var(--bdr);
}
.idea-card, .ex-card, .prem-card {
  transition: transform 260ms var(--sc-ease), box-shadow 260ms var(--sc-ease) !important;
}
.idea-card:hover, .ex-card:hover, .prem-card:hover {
  transform: translateY(-3px) !important;
  box-shadow: -7px -7px 17px var(--sc-lt), 12px 18px 36px var(--sc-sh-deep), inset 0 1px 0 var(--sc-lt-hi) !important;
}

/* pressed wells — readouts and data, the opposite gesture to the above.

   .dstat-rank is excluded rather than merely overridden later: this rule is
   !important, so it beat the tier gradient in styles.css no matter what the
   cascade order was, and the rank card rendered as a plain grey well. The
   comment below always claimed the rank card kept its tier colour; the
   selector just never let it. */
.dstat:not(.dstat-rank),
.dash-ex-row,
.stat-card,
.muscle-rank-item {
  background: linear-gradient(154deg, var(--bg2, var(--bg)), var(--card)) !important;
  box-shadow: inset 5px 5px 13px var(--sc-sh), inset -3px -3px 11px var(--sc-lt) !important;
  border: none !important;
}

/* the rank card is identity, so it keeps its tier light rather than a fill.
   --tier is set inline when the card renders (TIER_COLORS[rank.tier]). */
.dstat-rank {
  position: relative; overflow: hidden;
  background:
    linear-gradient(120deg,
      color-mix(in srgb, var(--tier, var(--accent)) 24%, var(--card)) 0%,
      color-mix(in srgb, var(--tier, var(--accent)) 10%, var(--card)) 55%,
      var(--card) 100%) !important;
  border: 1px solid color-mix(in srgb, var(--tier, var(--accent)) 38%, var(--bdr)) !important;
  box-shadow: inset 5px 5px 13px var(--sc-sh),
              inset -3px -3px 11px var(--sc-lt),
              inset 0 1px 0 color-mix(in srgb, var(--tier, var(--accent)) 26%, transparent),
              0 8px 26px color-mix(in srgb, var(--tier, var(--accent)) 14%, transparent) !important;
}
.dstat-ladder { background: var(--bg2, var(--bg)); box-shadow: inset 3px 3px 7px var(--sc-sh), inset -2px -2px 6px var(--sc-lt); }

/* primary actions read as raised keys */
.btn-primary {
  box-shadow: -3px -3px 10px rgba(var(--accent-rgb), 0.14), 5px 8px 20px var(--sc-sh-deep), inset 0 1px 0 rgba(255,255,255,0.35) !important;
}
.btn-primary:active { box-shadow: inset 4px 4px 10px var(--sc-sh-deep) !important; }

/* The zoom-specific chat overrides that used to live here are gone. They
   divided 100vh by 1.15 and 1.3 by hand, in two media queries, purely because
   this file loads after styles.css and would otherwise win. --vh in styles.css
   now carries the zoom factor, so the rules above inherit the correction and
   there is nothing left to keep in sync. */

/* ══════════════════════════════════════════════════════════════════════════
   PLAN CARDS — sculpted, floating, and reactive to the pointer

   The old cards were `background: var(--card)` with a 1px border, and the
   featured one explicitly set `box-shadow: none`. Three flat rectangles on the
   one screen where the product asks for money.

   Built from the tokens at the top of this file rather than new colours, so
   they re-tint with the accent like every other sculpted surface, and lit from
   the same top-left direction as the dock — a card lit differently from the
   navigation reads as a component borrowed from somewhere else.
   ══════════════════════════════════════════════════════════════════════════ */

.pricing-grid { perspective: 1400px; }

.pricing-card {
  /* deeper curve than --r-xl: at 32px the corner is a shape rather than a
     softened edge, which is what stops the group reading as a table */
  border-radius: 28px;
  /* 26/24 rather than the base 32/28. Eight feature rows plus a 32px ring is
     what tipped an otherwise-fitting pricing page past the fold on a 900px
     laptop screen. */
  padding: 26px 24px;
  background: linear-gradient(154deg, var(--card2, var(--card)), var(--card));
  border: 1px solid var(--bdr);
  box-shadow:
    -6px -6px 16px var(--sc-lt),
     9px 12px 28px var(--sc-sh),
     inset 0 1px 0 var(--sc-lt-hi);
  /* resting lift, so the set floats before anything is touched */
  transform: translateY(-2px);
  transition:
    transform 420ms var(--sc-ease),
    box-shadow 420ms var(--sc-ease),
    border-color 420ms var(--sc-ease),
    filter 420ms var(--sc-ease);
  will-change: transform;
}

/* Colour is emitted from inside the card, never painted onto its edge — the
   same rule the dock follows. */
.pricing-card::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; opacity: 0;
  box-shadow: inset 0 0 38px -12px var(--plan-emit, var(--accent));
  transition: opacity 420ms var(--sc-ease);
}
.pricing-featured { --plan-emit: var(--accent); }
.pricing-premium  { --plan-emit: var(--award, #F59E0B); }
.pricing-featured::before, .pricing-premium::before { opacity: 0.55; }

/* ── The pointer reaction ──────────────────────────────────────────────────
   One card grows, the rest give way. `:has()` lets the grid know one of its
   children is hovered, so the siblings can respond without a line of JS.

   Both halves are needed. Growing the hovered card alone just makes it bigger;
   shrinking the others is what makes it feel like the group is deferring to
   the one you are considering. */
/* :not(:hover) is load-bearing, not tidiness. :has() takes the specificity of
   its argument, so `.pricing-grid:has(.pricing-card:hover) .pricing-card`
   computes to (0,4,0) against the hover rule's (0,3,0) — the shrink won on the
   card being hovered, and every card scaled DOWN together, including the one
   under the pointer. Excluding :hover from the selector means it cannot match
   that card at all, whichever way the specificity falls. */
.pricing-grid:has(.pricing-card:hover) .pricing-card:not(:hover) {
  transform: translateY(0) scale(0.99);
  filter: saturate(0.94);
  box-shadow: -4px -4px 11px var(--sc-lt), 5px 7px 16px var(--sc-sh);
}
.pricing-grid .pricing-card:hover {
  /* small on purpose: the card is already 640px tall, so a few percent is a
     visible shift. 3.5% read as the page lurching. */
  transform: translateY(-4px) scale(1.015);
  filter: none;
  border-color: color-mix(in srgb, var(--plan-emit, var(--accent)) 45%, var(--bdr));
  box-shadow:
    -9px -9px 22px var(--sc-lt),
    16px 24px 52px var(--sc-sh-deep),
    inset 0 1px 0 var(--sc-lt-hi);
}
.pricing-grid .pricing-card:hover::before { opacity: 0.9; }

/* Keyboard users get the same treatment as the mouse — the card is reachable
   by tab through its CTA, so key off focus landing anywhere inside it. */
.pricing-grid .pricing-card:focus-within {
  transform: translateY(-4px) scale(1.015);
  filter: none;
}

/* The badge sat on the border of a flat card. On a raised one it has to sit
   ON the surface, catching the same light. */
.pricing-badge {
  border-radius: 999px; padding: 5px 14px; top: -13px;
  box-shadow: 0 4px 12px var(--sc-sh-deep), inset 0 1px 0 rgba(255,255,255,0.25);
}

/* The price is the one number on the page anyone actually reads. Give it the
   recessed treatment so it reads as stamped into the card. */
.plan-price {
  align-items: baseline;
  text-shadow: 0 1px 0 var(--sc-lt-hi), 0 -1px 1px var(--sc-sh);
}

/* Feature list: a hairline trough rather than a plain stack, so the list has
   an edge to sit against instead of floating in the padding. */
.plan-features {
  margin-top: 4px; padding-top: 16px;
  border-top: 1px solid var(--bdr);
}

@media (max-width: 900px) {
  /* No hover on a touch screen, and a scaled card inside a single column just
     clips against the viewport edge. Keep the material, drop the choreography. */
  .pricing-grid:has(.pricing-card:hover) .pricing-card:not(:hover),
  .pricing-grid .pricing-card:hover,
  .pricing-grid .pricing-card:focus-within {
    transform: translateY(-2px) scale(1); filter: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pricing-card,
  .pricing-grid:has(.pricing-card:hover) .pricing-card:not(:hover),
  .pricing-grid .pricing-card:hover,
  .pricing-grid .pricing-card:focus-within {
    transform: none; transition: box-shadow 200ms linear, border-color 200ms linear;
  }
}
