/* ===================================================================
   Button Variations — exploration page
   Each variant is self-contained for easy comparison/extraction.
   =================================================================== */

/* ===== Reset + tokens (subset of main site) =====
   Body bg/color use var(--bg)/var(--fg) so the theme toggle on
   index.html (and the same on components.html when added) can flip
   them. The vars themselves are defined in styles.css's :root /
   [data-theme="light"] blocks. The `:root` block below is a FALLBACK
   for cases where buttons.css is loaded WITHOUT styles.css — it
   leaves --bg / --fg alone so styles.css's theme rules win when both
   are loaded together. */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg, #1c1c1c);
  color: var(--fg, #ebebeb);
  font-family: "Inter", ui-sans-serif, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
}
a { color: inherit; text-decoration: none; }

:root {
  --accent: #ff4a08;
  --accent-soft: #ff9966;
  --white: #fff;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ===== Page chrome ===== */
.page-header {
  text-align: center;
  padding: 64px 24px 48px;
  max-width: 720px;
  margin: 0 auto;
  position: relative;
}
.back-link {
  position: absolute;
  top: 24px;
  left: 24px;
  font-size: 13px;
  color: rgba(235, 235, 235, 0.6);
  transition: color .2s ease;
}
.back-link:hover { color: var(--fg); }

.page-header h1 {
  font-size: clamp(32px, 4vw, 56px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0 0 16px;
}
.page-header p {
  font-size: 16px;
  color: rgba(235, 235, 235, 0.6);
  margin: 0;
  line-height: 1.5;
}

/* ===== Tabs (Components page) ===== */
.tabs {
  display: inline-flex;
  gap: 4px;
  margin: 32px auto 0;
  padding: 4px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 999px;
}
.tab {
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 8px 18px;
  border: none;
  background: transparent;
  color: rgba(235, 235, 235, 0.55);
  border-radius: 999px;
  cursor: pointer;
  transition: color .25s ease, background .25s ease;
}
.tab:hover { color: var(--fg); }
.tab.is-active {
  color: var(--bg);
  background: var(--fg);
}

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

/* ===== Effect picker (moved here from styles.css since it now lives
   exclusively on the components page) ===== */
.effect-picker {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}
.effect-picker--inline {
  margin: 32px auto 0;
}
.effect-picker-label {
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(235, 235, 235, 0.5);
  margin-right: 4px;
}
.effect-chip {
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 6px 12px;
  border: 1px solid rgba(235, 235, 235, 0.18);
  border-radius: 999px;
  background: transparent;
  color: rgba(235, 235, 235, 0.55);
  cursor: pointer;
  transition: color .25s ease, border-color .25s ease, background .25s ease, transform .25s var(--ease-out);
}
.effect-chip:hover {
  color: var(--fg);
  border-color: rgba(235, 235, 235, 0.4);
  transform: translateY(-1px);
}
.effect-chip.is-active {
  color: var(--accent);
  border-color: rgba(255, 74, 8, 0.7);
  background: rgba(255, 74, 8, 0.08);
}

/* ===== Text-effects tab content ===== */
.effects-stage {
  max-width: 1100px;
  margin: 48px auto 96px;
  padding: 0 24px;
  text-align: center;
}
.effects-eyebrow {
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(235, 235, 235, 0.45);
  margin: 0 0 16px;
}
.effects-preview {
  /* Inline-block + width:auto so the hero-title-wrap is sized to its
     text content rather than the full page width — keeps the shader
     canvas tight. Overrides `width: 100%` from styles.css's
     `.hero-title-wrap` rule. */
  display: inline-block;
  width: auto;
  text-align: left;
}
/* Shrink the production .hero-title typography so the preview fits the
   panel without scrolling. styles.css's clamp() goes up to ~9vw — we
   cap it here. */
.effects-stage .hero-title {
  font-size: clamp(28px, 5.5vw, 72px);
  line-height: 1.04;
}
.effects-hint {
  font-size: 13px;
  color: rgba(235, 235, 235, 0.55);
  max-width: 640px;
  margin: 28px auto 0;
  line-height: 1.55;
}
.effects-hint code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  background: rgba(255, 255, 255, 0.06);
  padding: 1px 6px;
  border-radius: 4px;
  color: rgba(235, 235, 235, 0.85);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 20px;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 24px 96px;
}

.card {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 8px;
  padding: 48px 20px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  min-height: 220px;
}
.card-preview {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 80px;
}
.card-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-align: center;
  color: var(--fg);
  margin: 0;
}
.card-note {
  font-size: 12px;
  text-align: center;
  color: rgba(235, 235, 235, 0.55);
  line-height: 1.4;
  margin: 0;
  max-width: 280px;
}
.card-note code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  background: rgba(255, 255, 255, 0.06);
  padding: 1px 4px;
  border-radius: 3px;
}

/* ===== Common button base =====
   Scoped to `.btn[class*="bv-"]` so this only applies to buttons that
   ALSO carry a variant class. This way, when buttons.css is loaded into
   index.html as well as components.html, the production .btn (in styles.css)
   isn't clobbered for buttons that don't have a chosen variant. */
.btn[class*="bv-"] {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.14px;
  line-height: 1;
  color: var(--fg);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
  text-decoration: none;
  transition:
    background  .35s var(--ease-out),
    color       .35s var(--ease-out),
    box-shadow  .45s var(--ease-out),
    border-color .35s var(--ease-out);
}
.btn-label {
  position: relative;
  z-index: 2;
}

/* ===== Shared keyframes ===== */
@keyframes shape-drift {
  0% {
    transform: translate(-50%, -50%) scale(1) rotate(0deg);
    border-radius: 50%;
  }
  14% {
    transform: translate(-28%, -65%) scale(1.15) rotate(50deg);
    border-radius: 38% 62% 65% 35% / 55% 40% 60% 45%;
  }
  28% {
    transform: translate(-70%, -45%) scale(0.95) rotate(110deg);
    border-radius: 65% 35% 40% 60% / 40% 60% 55% 45%;
  }
  42% {
    transform: translate(-32%, -55%) scale(1.1) rotate(170deg);
    border-radius: 55% 45% 30% 70% / 65% 50% 50% 35%;
  }
  57% {
    transform: translate(-62%, -28%) scale(1.0) rotate(220deg);
    border-radius: 35% 65% 55% 45% / 45% 55% 45% 55%;
  }
  71% {
    transform: translate(-48%, -75%) scale(1.2) rotate(280deg);
    border-radius: 60% 40% 45% 55% / 35% 60% 40% 65%;
  }
  85% {
    transform: translate(-42%, -40%) scale(1.05) rotate(330deg);
    border-radius: 45% 55% 60% 40% / 50% 50% 60% 40%;
  }
  100% {
    transform: translate(-50%, -50%) scale(1) rotate(360deg);
    border-radius: 50%;
  }
}

@keyframes shape-drift-2 {
  0%   { transform: translate(-50%, -50%) scale(1)   rotate(0deg);   border-radius: 50%; }
  20%  { transform: translate(-70%, -35%) scale(0.95) rotate(-60deg); border-radius: 55% 45% 60% 40%; }
  40%  { transform: translate(-30%, -75%) scale(1.1) rotate(-130deg); border-radius: 40% 60% 35% 65%; }
  60%  { transform: translate(-65%, -55%) scale(1.05) rotate(-200deg); border-radius: 60% 40% 50% 50%; }
  80%  { transform: translate(-35%, -30%) scale(0.9) rotate(-280deg); border-radius: 45% 55% 65% 35%; }
  100% { transform: translate(-50%, -50%) scale(1)   rotate(-360deg); border-radius: 50%; }
}

/* ============================================================
   ============================================================
   MAGNETIC SHADER CTAs  —  V267–V275
   The 266 catalog variants that used to live here (bv-01 → bv-266
   — six "groups" of liquid-glass / lava / dithering / glass-lava /
   show-off / shaped / glitch / skeu studies) were removed when the
   production design landed on the magnetic CTA family below. Git
   history (commit before the cleanup) preserves them for reference.
   The same WebGL magnetic shader that runs on the hero text,
   applied to three different "surfaces" of a button. Each
   variant hosts a per-instance Three.js shader (see the
   `setupMagneticButton` factory in components.html's inline
   script). The .btn-shader-canvas extends 20px past every
   button edge so the displacement has buffer room — the
   button's `overflow: hidden` clips the buffer back to the
   rounded shape.
     V267  Distort the background only (gradient + noise)
     V268  Distort the label text only (CSS solid bg)
     V269  Distort the entire button as one composite
   ============================================================
   ============================================================ */

.btn.bv-267, .btn.bv-268, .btn.bv-269 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  border-radius: 4px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.16px;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  border: none;
  isolation: isolate; /* keeps the canvas z-index scoped per-button */
}

/* Per-instance canvas overlay. JS sets `style.width`, `style.height`,
   `style.top`, `style.left` in explicit pixels after measuring the
   button — using `width: calc(100% + 40px)` here triggered a layout
   loop with the inline-flex button on some browsers (button grew
   unboundedly). Starting at 0×0 keeps the canvas invisible (and
   inert in layout) until the JS sets the real size. */
.btn-shader-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  display: block;
}

/* ----- V267: background distort. Canvas paints the orange
        gradient + noise that warps near the cursor. The label
        sits on top, fully static, so the text stays crisp. The
        solid CSS background is a fallback that's visible for
        the few frames before JS sizes the canvas — the canvas's
        gradient covers it identically once it's alive. */
.btn.bv-267 {
  background: var(--accent);
  color: #1c1c1c;
}
.btn.bv-267 .btn-shader-canvas { z-index: 0; }
.btn.bv-267 .btn-label { position: relative; z-index: 1; }
.btn.bv-267:hover {
  box-shadow: 0 10px 24px -8px rgba(255, 74, 8, 0.5);
}

/* ----- V268: text distort. CSS owns the solid background.
        At idle the HTML label is shown directly (pixel-perfect
        subpixel-AA text from the browser), and the canvas
        overlay is invisible. On hover the swap happens: HTML
        label goes transparent, canvas fades in and runs the
        magnetic distortion. The canvas is always rendering
        underneath, but `opacity: 0` keeps it off-screen until
        we actually want the effect. */
.btn.bv-268 {
  background: var(--accent);
  box-shadow: 0 6px 18px -8px rgba(255, 74, 8, 0.4);
}
.btn.bv-268 .btn-shader-canvas {
  z-index: 1;
  opacity: 0;
  transition: opacity .12s var(--ease-out);
}
.btn.bv-268:hover .btn-shader-canvas { opacity: 1; }
.btn.bv-268 .btn-label {
  position: relative;
  z-index: 0;
  color: #1c1c1c;
  transition: color .12s var(--ease-out);
}
/* `:not(:only-child)` guards against the production case where
   settings.js applies the variant class but doesn't inject the
   canvas sibling. With no canvas, the label is the only child, the
   rule doesn't match, and the text stays visible on hover (the
   button degrades cleanly to a static look). */
.btn.bv-268:hover .btn-label:not(:only-child) { color: transparent; }
.btn.bv-268:hover {
  box-shadow: 0 12px 28px -8px rgba(255, 74, 8, 0.55);
}

/* ----- V269: distort everything. Both bg and text are rendered
        into the canvas; once the canvas is sized, its solid
        gradient fill covers both the CSS background and the
        underlying label. CSS bg + label color stay as fallbacks
        so the button is still legible during the few frames
        before the JS sets up the shader. */
.btn.bv-269 {
  background: var(--accent);
  color: #1c1c1c;
}
.btn.bv-269 .btn-shader-canvas { z-index: 1; }
.btn.bv-269 .btn-label {
  position: relative;
  z-index: 0;
}
.btn.bv-269:hover {
  box-shadow: 0 12px 28px -8px rgba(255, 74, 8, 0.55);
}

/* ============================================================
   ============================================================
   SKEUO + MAGNETIC TEXT CTAs  —  V270–V272
   The magnetic-text canvas from V268, but sitting on V255's
   subtle skeuomorphic base (top-down gradient + 1px inner top
   highlight + soft warm drop shadow). Each variant has a
   different polished BOX hover treatment while the label
   continues to warp toward the cursor via the canvas shader.
     V270  Soft lift + scale + warmer gradient shift
     V271  Lift + outer ring halo
     V272  Bigger lift + layered drop shadow (most dramatic)
   ============================================================
   ============================================================ */

.btn.bv-270, .btn.bv-271, .btn.bv-272 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  border-radius: 4px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.16px;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  border: none;
  isolation: isolate;

  /* V255-style skeuo base — subtle gradient, inner top highlight,
     soft warm drop shadow. The label color is transparent so the
     canvas shader can draw the (distorted) text on top. */
  background: linear-gradient(to bottom, #ff5a1a, #ff4a08);
  color: transparent;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    0 2px 6px -2px rgba(255, 74, 8, 0.35);

  /* Smooth hover-out as well as hover-in — gives the box a more
     premium "settle" rather than snapping. */
  transition:
    transform   .35s var(--ease-out),
    background  .35s var(--ease-out),
    box-shadow  .45s var(--ease-out);
}

/* Idle: HTML label is shown directly (pixel-perfect subpixel-AA
   text from the browser), canvas overlay is invisible. On hover
   the swap happens — label fades to transparent, canvas fades in
   and runs the magnetic distortion. The canvas is rendering in
   the background the whole time, but `opacity: 0` keeps it
   off-screen until we actually want the effect.

   This is the only reliable way to get text-rendering crispness
   on par with HTML — canvas 2D uses grayscale AA only (no
   subpixel AA) and the shader's bilinear sampler smears edges
   further. */
.btn.bv-270 .btn-shader-canvas,
.btn.bv-271 .btn-shader-canvas,
.btn.bv-272 .btn-shader-canvas {
  z-index: 1;
  opacity: 0;
  transition: opacity .12s var(--ease-out);
}
.btn.bv-270:hover .btn-shader-canvas,
.btn.bv-271:hover .btn-shader-canvas,
.btn.bv-272:hover .btn-shader-canvas { opacity: 1; }

.btn.bv-270 .btn-label,
.btn.bv-271 .btn-label,
.btn.bv-272 .btn-label {
  position: relative;
  z-index: 0;
  color: #1c1c1c;
  transition: color .12s var(--ease-out);
}
/* `:not(:only-child)` — see the note above V268's identical rule. */
.btn.bv-270:hover .btn-label:not(:only-child),
.btn.bv-271:hover .btn-label:not(:only-child),
.btn.bv-272:hover .btn-label:not(:only-child) { color: transparent; }

/* ----- V270 — Soft lift + scale + warmer glow.
        Lifts 2px, grows 1.5%, gradient gets a touch warmer, the
        drop shadow expands with more orange in it. */
.btn.bv-270:hover {
  transform: translateY(-2px) scale(1.015);
  background: linear-gradient(to bottom, #ff6a30, #ff5520);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    0  2px  6px -2px rgba(255, 74, 8, 0.4),
    0 12px 26px -6px rgba(255, 74, 8, 0.55);
}
.btn.bv-270:active {
  transform: translateY(0) scale(1);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.18),
    0 1px 3px -1px rgba(255, 74, 8, 0.3);
}

/* ----- V271 — Lift + outer ring halo.
        Same skeuo base, but the hover state adds a soft outer
        ring via box-shadow spread — like a focus ring done
        beautifully. The ring contracts on press. */
.btn.bv-271:hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.42),
    0 0 0 4px rgba(255, 74, 8, 0.22),
    0 14px 28px -6px rgba(255, 74, 8, 0.5);
}
.btn.bv-271:active {
  transform: translateY(0);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.18),
    0 0 0 2px rgba(255, 74, 8, 0.32),
    0 2px 6px -2px rgba(255, 74, 8, 0.35);
}

/* ----- V272 — Bigger lift + layered drop shadow + inner bottom
        shade. The most dramatic of the three — feels like the
        button physically rises off the page. */
.btn.bv-272:hover {
  transform: translateY(-3px);
  background: linear-gradient(to bottom, #ff6c34, #ff4f1a);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -1px 0 rgba(120, 30, 0, 0.4),
    0  4px  8px -2px rgba(0, 0, 0, 0.22),
    0 16px 32px -8px rgba(255, 74, 8, 0.6),
    0 24px 48px -16px rgba(255, 74, 8, 0.3);
}
.btn.bv-272:active {
  transform: translateY(0);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.22),
    inset 0 -1px 0 rgba(120, 30, 0, 0.4),
    0 1px 3px -1px rgba(255, 74, 8, 0.3);
}

/* ============================================================
   ============================================================
   SKEUO + MAGNETIC TEXT CTAs — SECONDARIES  —  V273–V275
   White-outline glass-tile counterparts to V270–V272. Same
   canvas-driven magnetic text effect, same three hover
   treatments — but in V261's cool palette (tinted-glass
   gradient + white border + white text). The canvas paints
   the label in `#ffffff` via the `data-magnetic-color`
   attribute on each button.
     V273  Lift + scale + brighter glass    (mirrors V270)
     V274  Lift + white ring halo            (mirrors V271)
     V275  Bigger lift + layered dark shadow (mirrors V272)
   ============================================================
   ============================================================ */

.btn.bv-273, .btn.bv-274, .btn.bv-275 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  border-radius: 4px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.16px;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.85);
  isolation: isolate;

  /* V261-style outline-glass base: near-transparent gradient
     + faint inner highlight + soft dark drop shadow. The
     backdrop-filter is what gives it the "liquid-glass" feel —
     blurs + slightly desaturates whatever sits behind the button
     so page content doesn't bleed through as visual noise. */
  background: linear-gradient(to bottom,
    rgba(255, 255, 255, 0.05),
    rgba(255, 255, 255, 0));
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 2px 6px -2px rgba(0, 0, 0, 0.35);

  transition:
    transform     .35s var(--ease-out),
    background    .35s var(--ease-out),
    border-color  .35s var(--ease-out),
    box-shadow    .45s var(--ease-out);
}

/* Idle: HTML label is shown directly (white, pixel-perfect from
   the browser). Canvas overlay is invisible. On hover the swap
   happens — label fades to transparent, canvas fades in and
   runs the magnetic distortion in white text. */
.btn.bv-273 .btn-shader-canvas,
.btn.bv-274 .btn-shader-canvas,
.btn.bv-275 .btn-shader-canvas {
  z-index: 1;
  opacity: 0;
  transition: opacity .12s var(--ease-out);
}
.btn.bv-273:hover .btn-shader-canvas,
.btn.bv-274:hover .btn-shader-canvas,
.btn.bv-275:hover .btn-shader-canvas { opacity: 1; }

.btn.bv-273 .btn-label,
.btn.bv-274 .btn-label,
.btn.bv-275 .btn-label {
  position: relative;
  z-index: 0;
  color: #ffffff;
  transition: color .12s var(--ease-out);
}
/* `:not(:only-child)` — same graceful-degradation guard as V268/
   V270–V272 above. With no canvas sibling (production swap), the
   label stays visible on hover. */
.btn.bv-273:hover .btn-label:not(:only-child),
.btn.bv-274:hover .btn-label:not(:only-child),
.btn.bv-275:hover .btn-label:not(:only-child) { color: transparent; }

/* ----- V273 — Lift + scale + brighter glass (mirrors V270).
        Lifts 2px, grows 1.5%, the glass tint warms half a
        stop, and the drop shadow expands with deeper dark. */
.btn.bv-273:hover {
  transform: translateY(-2px) scale(1.015);
  background: linear-gradient(to bottom,
    rgba(255, 255, 255, 0.10),
    rgba(255, 255, 255, 0.03));
  border-color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    0  2px  6px -2px rgba(0, 0, 0, 0.4),
    0 12px 26px -6px rgba(0, 0, 0, 0.5);
}
.btn.bv-273:active {
  transform: translateY(0) scale(1);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.22),
    0 1px 3px -1px rgba(0, 0, 0, 0.35);
}

/* ----- V274 — Lift + white ring halo (mirrors V271).
        Soft 4px outer ring in white at 18% alpha — the cool
        equivalent of V271's orange focus-ring look. */
.btn.bv-274:hover {
  transform: translateY(-2px);
  border-color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.42),
    0 0 0 4px rgba(255, 255, 255, 0.18),
    0 14px 28px -6px rgba(0, 0, 0, 0.45);
}
.btn.bv-274:active {
  transform: translateY(0);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.22),
    0 0 0 2px rgba(255, 255, 255, 0.25),
    0 2px 6px -2px rgba(0, 0, 0, 0.3);
}

/* ----- V275 — Bigger lift + layered dark shadow (mirrors V272).
        Three-layer drop shadow — a close darker layer plus two
        further-spread dark layers — plus inner-bottom darkening
        so the underside catches light convincingly. */
.btn.bv-275:hover {
  transform: translateY(-3px);
  background: linear-gradient(to bottom,
    rgba(255, 255, 255, 0.12),
    rgba(255, 255, 255, 0.04));
  border-color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -1px 0 rgba(0, 0, 0, 0.3),
    0  4px  8px -2px rgba(0, 0, 0, 0.25),
    0 16px 32px -8px rgba(0, 0, 0, 0.55),
    0 24px 48px -16px rgba(0, 0, 0, 0.35);
}
.btn.bv-275:active {
  transform: translateY(0);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.25),
    inset 0 -1px 0 rgba(0, 0, 0, 0.3),
    0 1px 3px -1px rgba(0, 0, 0, 0.35);
}

/* ----- Magnetic-text-color CSS variable per variant -----
   The magnetic shader reads `--magnetic-text-color` via getComputedStyle
   to decide what color the canvas-rendered label should be. Defining
   it as a CSS var (instead of a hard-coded `data-magnetic-color` attr)
   lets light-theme overrides cascade for the secondaries — V273/V274/
   V275 paint dark text in light mode so they stay readable on the
   light page background. */
.btn.bv-267,
.btn.bv-268,
.btn.bv-269,
.btn.bv-270,
.btn.bv-271,
.btn.bv-272 { --magnetic-text-color: #1c1c1c; }
.btn.bv-273,
.btn.bv-274,
.btn.bv-275 { --magnetic-text-color: #ffffff; }

[data-theme="light"] .btn.bv-273,
[data-theme="light"] .btn.bv-274,
[data-theme="light"] .btn.bv-275 {
  --magnetic-text-color: #1c1c1c;
  /* Also flip the visible bits of the secondary outline so it stays
     legible on the warm-white light-theme background. */
  border-color: rgba(28, 28, 28, 0.85);
  background: linear-gradient(to bottom,
    rgba(28, 28, 28, 0.04),
    rgba(28, 28, 28, 0));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 2px 6px -2px rgba(28, 28, 28, 0.18);
}
[data-theme="light"] .btn.bv-273 .btn-label,
[data-theme="light"] .btn.bv-274 .btn-label,
[data-theme="light"] .btn.bv-275 .btn-label { color: #1c1c1c; }

/* Reduced-motion: the JS bails on PRM (see the setupMagneticButton
   factory in components.html), so the canvas stays at 0×0. V267
   and V269 already have CSS fallback bg + visible label, so they
   look correct as plain static buttons. V268 + V270–V275 now keep
   the HTML label visible at all times (the hover-swap to the
   canvas would otherwise hide the label too, since the canvas is
   hidden by display:none under PRM). */
@media (prefers-reduced-motion: reduce) {
  .btn.bv-268 .btn-label,
  .btn.bv-268:hover .btn-label,
  .btn.bv-270 .btn-label,
  .btn.bv-270:hover .btn-label,
  .btn.bv-271 .btn-label,
  .btn.bv-271:hover .btn-label,
  .btn.bv-272 .btn-label,
  .btn.bv-272:hover .btn-label { color: #1c1c1c; }
  .btn.bv-273 .btn-label,
  .btn.bv-273:hover .btn-label,
  .btn.bv-274 .btn-label,
  .btn.bv-274:hover .btn-label,
  .btn.bv-275 .btn-label,
  .btn.bv-275:hover .btn-label { color: #ffffff; }
  .btn-shader-canvas { display: none; }
}

/* ============================================================
   Reduced motion
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.1s !important;
  }
}
