/* kc — keycap buttons in the SMHcoders v3 palette.
   Sculpted after the "Keyboard of Knob" keycaps: a skirt lit from the top-left,
   a dished top face set slightly up-and-left of centre, and real key travel.

   Markup (kc.js builds this for you from <button class="kc">Label</button>):
     <button class="kc kc--teal">
       <span class="kc__glow"></span><span class="kc__side"></span>   (sockets only)
       <span class="kc__cap"><span class="kc__face">
         <span class="kc__label">Click here</span><span class="kc__icon">→</span>
       </span></span>
     </button>
*/

@property --kc-ty { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --kc-rx { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@property --kc-ry { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@property --kc-s { syntax: "<number>"; inherits: true; initial-value: 1; }

.kc {
  /* geometry */
  --h: 52px;
  --px: 26px;
  --r: 14px;
  --depth: 7px;
  --fs: 15px;
  --gap: 10px;

  /* teal (default) */
  --c-hi: #46c9c0;
  --c-mid: #0e9e96;
  --c-lo: #075e59;
  --c-face1: #1db0a7;
  --c-face2: #0b8981;
  --c-side: #05504c;
  --c-text: #effffd;
  --c-glow: rgba(14, 158, 150, .55);
  --c-led: #9bfff8;
  --c-ring: #0e9e96;
  --c-shadow: rgba(7, 17, 20, .38);

  /* live state, driven by :hover / :active / kc.js */
  --kc-ty: 0px;
  --kc-rx: 0deg;
  --kc-ry: 0deg;
  --mx: 35%;
  --my: 25%;

  position: relative;
  box-sizing: border-box;
  display: inline-flex;
  flex: none;
  vertical-align: middle;
  height: calc(var(--h) + var(--depth));
  min-width: var(--h);
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-text);
  font: 500 var(--fs)/1 var(--kc-font, "Space Grotesk", ui-sans-serif, system-ui, sans-serif);
  letter-spacing: -.005em;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  perspective: 700px;
  isolation: isolate;
  outline: none;
}

/* the shadow the key throws on the surface; becomes a coloured glow on hover */
.kc::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 6%; right: 6%;
  bottom: -3px;
  height: 70%;
  border-radius: var(--r);
  background: var(--c-shadow);
  filter: blur(10px);
  opacity: .6;
  transform: translateY(2px);
  transition: opacity .35s ease, filter .35s ease, transform .35s ease, background-color .35s ease;
  pointer-events: none;
}

/* the key's side wall: the cap travels down over it */
.kc::after {
  content: "";
  position: absolute;
  z-index: 0;
  left: var(--pad, 0px);
  right: var(--pad, 0px);
  top: calc(var(--pad, 0px) + var(--depth));
  height: var(--h);
  border-radius: var(--r);
  background:
    linear-gradient(90deg, rgba(255,255,255,.12), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 70%, rgba(0,0,0,.28)),
    var(--c-side-fill, var(--c-side));
  box-shadow: 0 1px 0 rgba(0,0,0,.22), inset 0 -2px 3px rgba(0,0,0,.28);
  pointer-events: none;
}

/* ── cap: skirt ──────────────────────────────────────── */

.kc__cap {
  position: relative;
  display: flex;
  width: 100%;
  height: var(--h);
  border-radius: var(--r);
  background:
    linear-gradient(90deg, rgba(255,255,255,.16), rgba(255,255,255,0) 22%, rgba(0,0,0,0) 72%, rgba(0,0,0,.16)),
    linear-gradient(180deg, var(--c-hi) 0%, var(--c-mid) 42%, var(--c-lo) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.4),
    inset 1px 0 1px rgba(255,255,255,.18),
    inset -1px -1px 2px rgba(0,0,0,.25);
  transform: rotateX(var(--kc-rx)) rotateY(var(--kc-ry)) translateY(var(--kc-ty)) scale(var(--kc-s));
  transform-origin: 50% 60%;
  /* release: springs back with a little overshoot */
  transition:
    --kc-ty .34s cubic-bezier(.34, 1.7, .5, 1),
    --kc-s .34s cubic-bezier(.34, 1.7, .5, 1),
    --kc-rx .5s cubic-bezier(.2, .7, .1, 1),
    --kc-ry .5s cubic-bezier(.2, .7, .1, 1),
    box-shadow .3s cubic-bezier(.34, 1.5, .5, 1),
    filter .25s ease;
  z-index: 1;
}

/* the white glow that peeks out from behind the face, top-left (Figma "Rectangle 17") */
.kc__cap::before {
  content: "";
  position: absolute;
  left: 2px; top: 2px;
  width: min(70%, calc(100% - 10px));
  height: 72%;
  border-radius: var(--r) 2px 2px calc(var(--r) / 3);
  background: radial-gradient(110% 120% at 0 0, rgba(255,255,255,.75) 0%, rgba(255,255,255,.25) 45%, rgba(255,255,255,0) 75%);
  filter: blur(2px);
  pointer-events: none;
}

/* dark lip under the face, bottom-right (Figma "Rectangle 31" shade) */
.kc__cap::after {
  content: "";
  position: absolute;
  inset: 30% 3px 3px 22%;
  border-radius: calc(var(--r) * 1.4);
  background: rgba(0,0,0,.22);
  filter: blur(5px);
  pointer-events: none;
}

/* ── face: the dished top ────────────────────────────── */

.kc__face {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap);
  min-width: 0;
  margin: 3px 6px 7px 4px;
  padding: 0 calc(var(--px) - 5px);
  border-radius: calc(var(--r) - 3px);
  overflow: hidden;
  background: linear-gradient(155deg, var(--c-face1) 0%, var(--c-face2) 100%);
  box-shadow:
    inset 1px 1px 1px rgba(255,255,255,.28),
    inset -1px -2px 3px rgba(0,0,0,.14),
    0 0 3px 1px var(--c-halo, var(--c-face2));
  white-space: nowrap;
  transition: box-shadow .25s ease, background .25s ease;
}

/* specular hot spot that follows the pointer */
.kc__face::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at var(--mx) var(--my), rgba(255,255,255,.34), rgba(255,255,255,.08) 38%, rgba(255,255,255,0) 62%);
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
}

/* one sweep of light across the face on hover */
.kc__face::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, rgba(255,255,255,0) 38%, rgba(255,255,255,.38) 50%, rgba(255,255,255,0) 62%) no-repeat;
  background-size: 260% 100%;
  background-position: 130% 0;
  pointer-events: none;
}

.kc__label, .kc__icon, .kc__led, .kc__spin {
  position: relative;
  z-index: 1;
  text-shadow: 0 1px 0 rgba(0,0,0,.18);
  transition: transform .3s cubic-bezier(.34, 1.6, .5, 1), opacity .2s ease;
}
.kc__label { overflow: hidden; text-overflow: ellipsis; }
.kc__icon { display: inline-flex; font-family: var(--kc-icon-font, "IBM Plex Mono", ui-monospace, monospace); }
.kc__icon svg { width: 1.1em; height: 1.1em; }

/* latching keys get an LED */
.kc__led {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: rgba(0,0,0,.28);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.35), 0 1px 0 rgba(255,255,255,.25);
  transition: background .2s ease, box-shadow .2s ease;
}

/* press ripple (added by kc.js) */
.kc__ripple {
  position: absolute;
  z-index: 0;
  width: 12px; height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.55) 0%, rgba(255,255,255,0) 70%);
  pointer-events: none;
  animation: kc-ripple .6s cubic-bezier(.2, .7, .1, 1) forwards;
}
@keyframes kc-ripple { from { transform: scale(0); opacity: 1; } to { transform: scale(22); opacity: 0; } }

/* ── states ──────────────────────────────────────────── */

@media (hover: hover) {
  .kc:is(:hover, .is-hover):not(:disabled):not([aria-disabled="true"]):not(.is-down) {
    --kc-ty: -2px;
  }
  .kc:is(:hover, .is-hover):not(:disabled):not([aria-disabled="true"])::before {
    background: var(--glow-bg, var(--c-glow));
    opacity: .9;
    filter: blur(14px);
    transform: translateY(6px) scale(1.04);
  }
  .kc:is(:hover, .is-hover):not(:disabled):not([aria-disabled="true"]) .kc__face::before { opacity: 1; }
  .kc:is(:hover, .is-hover):not(:disabled):not([aria-disabled="true"]) .kc__face::after {
    background-position: -30% 0;
    transition: background-position .9s cubic-bezier(.2, .7, .1, 1);
  }
  .kc:is(:hover, .is-hover):not(:disabled):not([aria-disabled="true"]) .kc__icon { transform: translateX(3px); }
}

/* pressed: fast travel down, extrusion collapses, face dims slightly */
.kc:active:not(:disabled):not([aria-disabled="true"]),
.kc.is-down {
  --kc-ty: calc(var(--depth) - 1px);
}
.kc:active:not(:disabled):not([aria-disabled="true"]) .kc__cap,
.kc.is-down .kc__cap {
  /* a key that bottoms out sits flat (and the label stays crisp: no 3D rotation while held) */
  transform: translateY(var(--kc-ty)) scale(var(--kc-s));
  transition: --kc-ty .06s ease-out, --kc-s .06s ease-out, --kc-rx .5s, --kc-ry .5s, box-shadow .06s ease-out;
}
.kc:active:not(:disabled):not([aria-disabled="true"]) .kc__face,
.kc.is-down .kc__face {
  box-shadow:
    inset 1px 2px 3px rgba(0,0,0,.16),
    inset -1px -1px 1px rgba(255,255,255,.12),
    0 0 3px 1px var(--c-halo, var(--c-face2));
}
.kc:active:not(:disabled):not([aria-disabled="true"])::before,
.kc.is-down::before {
  opacity: .45;
  filter: blur(5px);
  transform: translateY(1px) scale(.97);
  transition-duration: .06s;
}
.kc:active .kc__icon, .kc.is-down .kc__icon { transform: translateX(6px); }

/* latched (toggle buttons with aria-pressed="true") rest part-way down */
.kc[aria-pressed="true"]:not(.is-down) {
  --kc-ty: calc(var(--depth) * .55);
}
.kc[aria-pressed="true"] .kc__led {
  background: var(--c-led);
  box-shadow: 0 0 4px 1px var(--c-led), 0 0 12px 2px var(--c-glow);
}

/* loading */
.kc[aria-busy="true"] { cursor: progress; }
.kc[aria-busy="true"]:not(.is-down) { --kc-ty: calc(var(--depth) * .4); }
.kc__spin {
  width: 1em; height: 1em;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-right-color: transparent;
  animation: kc-spin .7s linear infinite;
}
.kc:not([aria-busy="true"]) .kc__spin { display: none; }
.kc[aria-busy="true"] .kc__icon { display: none; }
@keyframes kc-spin { to { transform: rotate(1turn); } }

/* disabled */
.kc:disabled, .kc[aria-disabled="true"]:not([aria-busy="true"]) {
  cursor: not-allowed;
  filter: grayscale(.75) opacity(.55);
}
.kc:disabled::before, .kc[aria-disabled="true"]::before { opacity: .3; }

.kc-no-spec .kc__face::before { display: none; }

/* keyboard focus */
.kc:focus-visible .kc__cap {
  outline: 2px solid var(--c-ring);
  outline-offset: 3px;
}

/* ── colours ─────────────────────────────────────────── */

.kc--orange {
  --c-hi: #ffad6b; --c-mid: #f07b1e; --c-lo: #a3480b;
  --c-face1: #f78d36; --c-face2: #de6a12; --c-side: #8a3a06;
  --c-text: #fff8f1; --c-glow: rgba(240, 123, 30, .55); --c-led: #fff1c2; --c-ring: #f07b1e;
}
.kc--ink {
  --c-hi: #4a5759; --c-mid: #1c2729; --c-lo: #060b0c;
  --c-face1: #253335; --c-face2: #131d1f; --c-side: #020506;
  --c-text: #e9f1f0; --c-glow: rgba(14, 158, 150, .45); --c-led: #2fe0d4; --c-ring: #0c1517;
}
.kc--paper {
  --c-hi: #ffffff; --c-mid: #e2dfd6; --c-lo: #a6a296;
  --c-face1: #f8f7f3; --c-face2: #e2dfd6; --c-side: #96928a;
  --c-text: #0c1517; --c-glow: rgba(12, 21, 23, .28); --c-led: #f07b1e; --c-ring: #0c1517;
}
.kc--paper .kc__label, .kc--paper .kc__icon { text-shadow: 0 1px 0 rgba(255,255,255,.7); }
.kc--brand {
  --c-hi: #46c9c0; --c-mid: #0e9e96; --c-lo: #7a3d0c;
  --c-face1: #14a79e; --c-face2: #f07b1e; --c-side: #3b3a1a;
  --c-text: #ffffff; --c-glow: rgba(240, 123, 30, .5); --c-led: #fff1c2; --c-ring: #0e9e96;
  --c-halo: rgba(0, 0, 0, .1);
  --glow-bg: linear-gradient(100deg, rgba(14, 158, 150, .6), rgba(240, 123, 30, .55));
  --c-side-fill: linear-gradient(100deg, #05504c 0%, #2b5a3e 35%, #80400f 75%, #8a3a06 100%);
}
.kc--brand .kc__cap {
  background:
    linear-gradient(180deg, rgba(255,255,255,.28), rgba(255,255,255,0) 40%, rgba(0,0,0,.28)),
    linear-gradient(100deg, #0e9e96 0%, #2fa58a 35%, #e0812c 75%, #f07b1e 100%);
}
.kc--brand .kc__face { background: linear-gradient(100deg, #18aba2 0%, #3fae86 35%, #e98a2e 75%, #f07b1e 100%); }

/* ── sizes & shapes ──────────────────────────────────── */

.kc--sm { --h: 38px; --px: 16px; --r: 10px; --depth: 5px; --fs: 13px; --gap: 8px; }
.kc--lg { --h: 66px; --px: 36px; --r: 18px; --depth: 9px; --fs: 18px; --gap: 12px; }
.kc--xl { --h: 84px; --px: 46px; --r: 22px; --depth: 11px; --fs: 22px; --gap: 14px; }
.kc--icon { width: var(--h); }
.kc--icon .kc__face { padding: 0; }
.kc--pill { --r: calc(var(--h) / 2); }
.kc--block { display: flex; width: 100%; }

/* sit the key in a recessed socket, like the Figma keyboard case.
   Proportions from the Figma layers, relative to key height (281):
     bezel 68 → .2h, flat #797778 with a white rim highlight top-left
     well #100e0c, gap to the key ~.1h
   The key colour is its light catching the bezel edge: a soft glow cast by the
   well's top-left edge, no ring of its own. It is strongest when the key is up,
   and when the key sinks the light retreats into the corner and fades. */
.kc--socket {
  --bz: clamp(6px, calc(var(--h) * .2), 16px);
  --pad: max(4px, calc(var(--h) * .1));
  --g: max(3px, calc(var(--h) * .09));
  --c-spill: var(--c-mid);
  --tmax: 1;
  --tint: .75;
  --reach: 1;
  /* how much of the key's side shows below it in the well */
  --sd: max(3px, calc(var(--depth) * .6));
  height: calc(var(--h) + 2 * var(--pad) + var(--sd) + 2 * var(--bz));
  padding: var(--pad) var(--pad) calc(var(--pad) + var(--sd));
  border: var(--bz) solid transparent;
  border-radius: calc(var(--r) + var(--pad) + var(--bz));
  background: linear-gradient(160deg, #8a8889 0%, #797778 45%, #6f6d6e 100%) border-box;
  box-shadow:
    1px 2px 4px rgba(0,0,0,.3),
    0 10px 22px -10px rgba(0,0,0,.45);
}
.kc--brand.kc--socket {
  --glow-fill: linear-gradient(100deg, #18aba2 0%, #3fae86 35%, #e98a2e 75%, #f07b1e 100%);
  --side-fill: linear-gradient(100deg, #04423f 0%, #1f4a35 35%, #6e3410 75%, #763206 100%);
}
.kc--ink.kc--socket { --c-spill: #0e9e96; --tmax: .7; }
.kc--paper.kc--socket { --c-spill: #ffffff; --tmax: .45; }

/* the well, and the light it throws onto the bezel */
.kc--socket::after {
  inset: 0;
  height: auto;
  border-radius: calc(var(--r) + var(--pad));
  /* the floor: black, catching a little light at the far (bottom) wall, so the key's shadow has somewhere to land */
  background: radial-gradient(130% 90% at 50% 108%, #2c2927 0%, #181614 45%, #0d0c0b 80%);
  box-shadow:
    /* walls: top and left in shade, bottom lip catches light */
    inset 0 calc(var(--g) * .5) calc(var(--g) * .7) rgba(0,0,0,.9),
    inset calc(var(--g) * .3) 0 calc(var(--g) * .5) rgba(0,0,0,.6),
    inset 0 -1px 0 rgba(255,255,255,.09),
    inset -1px 0 0 rgba(255,255,255,.05),
    /* the well's soft dark lip, so there is no hard bezel edge */
    0 0 calc(var(--g) * .3) 1px rgba(16,14,12,.8);
}

/* key light on the bezel's inner edge (kc.js adds the span). It sits under the well,
   shifted up-left and faded towards the bottom-right, so only a soft edge shows at the
   top and left. Its fill follows the key: a gradient key throws a gradient light. */
.kc__glow, .kc__side { display: none; position: absolute; pointer-events: none; }
.kc--socket .kc__glow {
  display: block;
  z-index: 0;
  inset: calc(var(--g) * -.45);
  border-radius: calc(var(--r) + var(--pad) + var(--g) * .45);
  background: var(--glow-fill, var(--c-spill));
  -webkit-mask: radial-gradient(160% 180% at 0 0, #000 25%, transparent 68%);
          mask: radial-gradient(160% 180% at 0 0, #000 25%, transparent 68%);
  filter: blur(calc(var(--g) * .4));
  opacity: calc(var(--tint) * var(--tmax));
  transform: translate(calc(var(--g) * -.28 * var(--reach)), calc(var(--g) * -.28 * var(--reach)));
  /* release: the light floods back */
  transition: opacity .55s cubic-bezier(.2, .7, .1, 1), transform .55s cubic-bezier(.2, .7, .1, 1);
}

/* hover: the key lifts, more light escapes */
@media (hover: hover) {
  .kc--socket:is(:hover, .is-hover):not(:disabled):not([aria-disabled="true"]):not(.is-down) {
    --tint: .95; --reach: 1.2; --kc-ty: -1px; --kc-s: 1.008;
  }
}
/* pressed: the key sinks below the bezel, its light pulls back into the corner and fades */
.kc--socket:active:not(:disabled):not([aria-disabled="true"]),
.kc--socket.is-down { --tint: .1; --reach: .25; --kc-ty: calc(var(--sd) - 1px); --kc-s: .985; }
.kc--socket:active .kc__glow, .kc--socket.is-down .kc__glow { transition-duration: .14s; transition-timing-function: ease-out; }
/* latched and loading rest part-way down, part-lit */
.kc--socket[aria-pressed="true"]:not(.is-down),
.kc--socket[aria-busy="true"]:not(.is-down) { --tint: .4; --reach: .6; --kc-ty: calc(var(--sd) * .5); --kc-s: .99; }

/* the key's side wall and its shadow on the well floor (kc.js adds the span).
   It stays put; the key travels down over it, so less side shows as it sinks. */
.kc--socket .kc__side {
  display: block;
  z-index: 1;
  left: var(--pad);
  right: var(--pad);
  top: calc(var(--pad) + var(--sd));
  height: var(--h);
  border-radius: var(--r);
  background:
    linear-gradient(90deg, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 70%, rgba(0,0,0,.25)),
    var(--side-fill, color-mix(in srgb, var(--c-side) 88%, #000));
  box-shadow: 0 1px 0 rgba(0,0,0,.55), 1px 2px calc(var(--g) * .9) rgba(0,0,0,.8);
}
.kc--socket .kc__cap { z-index: 2; }

/* the bezel's lit outer rim (Figma: white inner shadow 8,8 on the case) */
.kc--socket::before,
.kc--socket:is(:hover, .is-hover, :active, .is-down):not(:disabled):not([aria-disabled="true"])::before {
  inset: calc(-1 * var(--bz));
  height: auto;
  z-index: 0;
  border-radius: inherit;
  background: none;
  box-shadow:
    inset calc(var(--bz) * .22) calc(var(--bz) * .22) calc(var(--bz) * .3) rgba(255,255,255,.85),
    inset 1px 1px 2px rgba(0,0,0,.35),
    inset -1px -1px 2px rgba(60,60,60,.45);
  filter: none;
  opacity: 1;
  transform: none;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .kc__cap, .kc::before, .kc__label, .kc__icon { transition-duration: .01s !important; }
  .kc__face::after, .kc__ripple { display: none; }
  .kc { --kc-rx: 0deg !important; --kc-ry: 0deg !important; }
}
