/* ============================================================
   EMBER components — keycaps, tickets, envelope, postures
   Requires: tokens/ember.css + base.css
   ============================================================ */

/* ---- buttons: THE KEYCAP --------------------------------------
   Not the bordered-rect-with-diagonal-shadow cliché. A keycap
   stands on a side wall; pressing sinks the cap the full wall
   height and it LANDS. On hover a motion ghost trails off the
   left — the key looks ready to move. */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-grot);
  font-weight: 500;
  font-size: var(--text-md);
  line-height: 1;
  padding: 0.75em 1.4em;
  background: var(--raise);
  color: var(--ink);
  border: var(--line-heavy) solid var(--edge-strong);
  border-radius: 0;
  box-shadow: 0 var(--keycap-wall) 0 var(--edge-strong);
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--dur-1) var(--ease-press),
    box-shadow var(--dur-1) var(--ease-press),
    background-color var(--dur-1) var(--ease-press);
}

.btn:hover {
  transform: translateY(-2px);
  /* the motion ghost: a shrinking echo trailing off to the left */
  box-shadow: 0 calc(var(--keycap-wall) + 2px) 0 var(--edge-strong),
    calc(-1 * var(--keycap-wall)) calc(var(--keycap-wall) + 2px) 0 -2px var(--edge-strong);
}

.btn:active {
  transform: translateY(var(--keycap-wall));
  box-shadow: 0 0 0 var(--edge-strong);
}

/* disabled: the wall has collapsed — there is nothing left to press */
.btn:disabled,
.btn:disabled:hover,
.btn:disabled:active,
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  transform: none;
  background: var(--sunk);
  color: var(--ink-faint);
  border-color: var(--ink-faint);
  box-shadow: 0 2px 0 var(--ink-faint);
}

.btn .key {
  font-family: var(--font-mono);
  font-size: 0.85em;
  opacity: 0.55;
}

.btn-primary {
  background: var(--ink);
  color: var(--bg);
}

.btn-primary:hover {
  background: var(--ink);
  color: var(--bg);
}

/* The ember cut — the one ember keycap. One per view.
   Its glow is the language's single sanctioned blur. */
.btn-ember {
  background: var(--ember);
  color: var(--ember-text);
}

.btn-ember:hover {
  background: var(--ember);
  color: var(--ember-text);
  box-shadow: 0 calc(var(--keycap-wall) + 2px) 0 var(--edge-strong),
    calc(-1 * var(--keycap-wall)) calc(var(--keycap-wall) + 2px) 0 -2px var(--edge-strong),
    var(--glow-ember);
}

.btn-ghost {
  background: transparent;
  border-width: var(--line-fine);
  box-shadow: 0 4px 0 var(--edge-strong);
}

.btn-ghost:hover {
  border-width: var(--line-fine);
  box-shadow: 0 6px 0 var(--edge-strong),
    -6px 6px 0 -2px var(--edge-strong);
}

.btn-ghost:active {
  transform: translateY(4px);
  box-shadow: 0 0 0 var(--edge-strong);
}

.btn-sm {
  font-size: var(--text-sm);
  padding: 0.55em 1em;
}

.btn-lg {
  font-size: var(--text-lg);
  padding: 0.85em 1.6em;
}

/* ---- chips: TICKETS — punched, not printed --------------------- */

.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  line-height: 1;
  padding: 0.45em 1.2em;
  border: var(--line-fine) solid var(--edge-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink);
}

/* punched holes, left and right — a raffle ticket */
.chip::before,
.chip::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--bg);
  border: var(--line-fine) solid var(--edge-strong);
  transform: translateY(-50%);
}

.chip::before {
  left: -4px;
}

.chip::after {
  right: -4px;
}

.chip-solid {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--edge-strong);
}

/* ---- cards: RARE objects, in the GIVE posture -------------------
   A card informs, so it gives: sharp top, open bottom. */

.card {
  background: var(--raise);
  border: var(--line-heavy) solid var(--edge-strong);
  border-radius: var(--shape-give);
  box-shadow: var(--shadow-md);
  padding: var(--sp-5);
}

.card-flat {
  box-shadow: none;
}

.card-sunk {
  background: var(--sunk);
  box-shadow: none;
}

.card-raise-hover {
  transition: transform var(--dur-1) var(--ease-press),
    box-shadow var(--dur-1) var(--ease-press);
}

.card-raise-hover:hover {
  transform: translate(-2px, -2px);
  box-shadow: 8px 8px 0 var(--shadow-ink);
}

.card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3);
  border-bottom: var(--line-fine) solid var(--edge-faint);
  padding-block-end: var(--sp-3);
  margin-block-end: var(--sp-4);
}

/* ---- callouts: the SPEAK posture --------------------------------
   A callout announces, so it is a tag pointing at its subject:
   rounded on the left (the mouth), sharp on the right (the point). */

.callout {
  background: var(--sunk);
  border: var(--line-heavy) solid var(--edge-strong);
  border-radius: var(--shape-speak);
  box-shadow: var(--shadow-sm);
  padding: var(--sp-4) var(--sp-5) var(--sp-4) calc(var(--sp-5) + 6px);
}

/* Ember wash variant — counts as the composition's ember cut. */
.callout-ember {
  background: var(--ember-wash);
  border-color: var(--edge-strong);
  box-shadow: var(--shadow-sm);
}

/* ---- the envelope: the ASK posture ------------------------------
   Anything that requests input is an envelope: airmail stripes,
   a sealed flap, sky for the air inside. It wants to be sent. */

.envelope {
  position: relative;
  display: grid;
  gap: var(--sp-3);
  max-width: 440px;
  padding: calc(var(--sp-6) + 6px) var(--sp-5) var(--sp-5);
  background: var(--sky);
  border: var(--line-heavy) solid var(--edge-strong);
  border-radius: var(--shape-give);
}

/* the unsealed V-flap hanging from the top edge */
.envelope::before {
  content: "";
  position: absolute;
  top: calc(-1 * var(--line-heavy));
  left: calc(-1 * var(--line-heavy));
  right: calc(-1 * var(--line-heavy));
  height: 26px;
  background: var(--raise);
  border-bottom: var(--line-heavy) solid var(--edge-strong);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

/* par avion: the airmail stripe along the bottom edge */
.envelope::after {
  content: "";
  position: absolute;
  left: var(--sp-4);
  right: var(--sp-4);
  bottom: 6px;
  height: 4px;
  background: repeating-linear-gradient(
    -45deg,
    var(--ember) 0 7px,
    transparent 7px 14px,
    var(--azure) 14px 21px,
    transparent 21px 28px
  );
}

.envelope > :first-child {
  z-index: 1;
}

/* small envelope: the ASK posture at chip scale — flap and stripe kept */
.envelope--sm {
  display: inline-grid;
  padding: calc(var(--sp-4) + 4px) var(--sp-4) calc(var(--sp-3) + 6px);
  font-size: var(--text-sm);
  font-weight: 500;
}

.envelope--sm::before {
  height: 14px;
}

.envelope--sm::after {
  left: var(--sp-2);
  right: var(--sp-2);
  bottom: 4px;
  height: 3px;
}

.envelope input,
.envelope textarea,
.envelope select {
  font-family: var(--font-grot);
  font-size: var(--text-md);
  background: var(--raise);
  color: var(--ink);
  border: var(--line-fine) solid var(--edge-strong);
  border-radius: 0;
  padding: 0.65em 0.8em;
}

.envelope input:focus {
  outline: none;
  border-color: var(--edge-strong);
  border-width: var(--line-heavy);
  box-shadow: var(--shadow-sm);
}

.envelope .send-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-3);
}

/* ---- fields (plain, non-envelope) -------------------------------- */

.field {
  display: grid;
  gap: var(--sp-2);
}

.field input,
.field textarea,
.field select {
  font-family: var(--font-grot);
  font-size: var(--text-md);
  background: var(--raise);
  color: var(--ink);
  border: var(--line-fine) solid var(--edge-strong);
  border-radius: 0;
  padding: 0.65em 0.8em;
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--ink-faint);
}

.field input:focus,
.field textarea:focus,
.field select:focus {
  outline: none;
  border-color: var(--edge-strong);
  border-width: var(--line-heavy);
  box-shadow: var(--shadow-sm);
}

/* ---- table: rules carry the structure, headers are ink slabs ----- */

.table {
  width: 100%;
  border-collapse: collapse;
  border-top: var(--line-heavy) solid var(--edge-strong);
  border-bottom: var(--line-heavy) solid var(--edge-strong);
}

.table th {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  text-align: left;
  background: var(--ink);
  color: var(--bg);
  padding: var(--sp-2) var(--sp-3);
}

.table td {
  padding: var(--sp-3);
  border-bottom: var(--line-fine) solid var(--edge-faint);
}

.table tr:last-child td {
  border-bottom: none;
}

/* ---- stat ------------------------------------------------------- */

.stat {
  display: grid;
  gap: var(--sp-1);
  border-top: var(--line-heavy) solid var(--edge-strong);
  padding-top: var(--sp-3);
}

.stat-value {
  font-size: var(--text-3xl);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-display);
}

/* ---- icons: drawn by the language's own rules -----------------------
   24-unit grid, 2.5 stroke (the heavy rule at icon scale), square caps,
   miter joins, currentColor. Motion icons carry a trail that animates
   on the host: .icon-move:hover drives --trail into the <use> tree.
   Needs icons/ember-icons.js (inline sprite) on the page. */

@property --trail {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

.icon {
  display: inline-block;
  flex: none;
  width: 1.25em;
  height: 1.25em;
  vertical-align: -0.22em;
  overflow: visible;
}

.icon--sm {
  width: 1em;
  height: 1em;
}

.icon--lg {
  width: 2em;
  height: 2em;
}

/* hard shadow, zero blur — the same offset every EMBER object casts */
.icon--shadow {
  filter: drop-shadow(2px 2px 0 var(--shadow-ink));
}

.icon-move:hover,
.icon-move:focus-visible {
  animation: ember-trail 0.7s var(--ease-press) infinite alternate;
}

@keyframes ember-trail {
  from {
    --trail: 0;
  }

  to {
    --trail: 2.5;
  }
}

/* ---- index tabs: the PRESS posture, in a row ------------------------
   Each tab is a keycap standing on the rule; the selected one has been
   pressed all the way in and becomes an ink slab flush with the rule. */

.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  border-bottom: var(--line-heavy) solid var(--edge-strong);
  padding-top: calc(var(--keycap-wall) + 2px);
}

.tab {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6em;
  padding: 0.7em 1em 0.6em;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  line-height: 1;
  color: var(--ink-soft);
  background: var(--raise);
  border: var(--line-fine) solid var(--edge-strong);
  border-bottom: none;
  border-radius: 0;
  text-decoration: none;
  cursor: pointer;
  transform: translateY(calc(-1 * var(--keycap-wall)));
  box-shadow: 0 var(--keycap-wall) 0 var(--edge-strong);
  transition: transform var(--dur-1) var(--ease-press),
    box-shadow var(--dur-1) var(--ease-press),
    background-color var(--dur-1) var(--ease-press);
}

.tab .tab-index {
  opacity: 0.6;
}

.tab:hover {
  background: var(--raise);
  color: var(--ink);
  transform: translateY(calc(-1 * var(--keycap-wall) - 2px));
  box-shadow: 0 calc(var(--keycap-wall) + 2px) 0 var(--edge-strong),
    calc(-1 * var(--keycap-wall)) calc(var(--keycap-wall) + 2px) 0 -2px var(--edge-strong);
}

.tab[aria-selected="true"],
.tab[aria-current],
.tab[aria-selected="true"]:hover,
.tab[aria-current]:hover {
  transform: none;
  box-shadow: none;
  background: var(--ink);
  color: var(--bg);
}

.tab-panel[hidden] {
  display: none;
}

/* ---- the latch: a PRESS-posture toggle ------------------------------
   A sunk slot with a keycap knob on its wall. The knob slides with the
   press easing, sinks while held, and the slot inverts to ink when on. */

.latch {
  --latch-w: 3.25rem;
  --latch-knob: 1.15rem;
  --latch-wall: 3px;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  line-height: 1;
  cursor: pointer;
  user-select: none;
}

.latch input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}

.latch-track {
  position: relative;
  flex: none;
  width: var(--latch-w);
  height: 1.5rem;
  background: var(--sunk);
  border: var(--line-fine) solid var(--edge-strong);
  transition: background-color var(--dur-2) var(--ease-press);
}

.latch-track::after {
  content: "";
  position: absolute;
  top: 1px;
  left: 2px;
  width: var(--latch-knob);
  height: calc(100% - 2px - var(--latch-wall) - 2px);
  background: var(--raise);
  border: var(--line-fine) solid var(--edge-strong);
  box-shadow: 0 var(--latch-wall) 0 var(--edge-strong);
  transition: transform var(--dur-2) var(--ease-press),
    box-shadow var(--dur-1) var(--ease-press);
}

.latch input:checked + .latch-track {
  background: var(--ink);
}

.latch input:checked + .latch-track::after {
  transform: translateX(calc(var(--latch-w) - var(--latch-knob) - 6px));
}

/* held: the knob sinks the full wall and lands */
.latch:active .latch-track::after {
  box-shadow: 0 0 0 var(--edge-strong);
  transform: translateY(var(--latch-wall));
}

.latch:active input:checked + .latch-track::after {
  transform: translate(calc(var(--latch-w) - var(--latch-knob) - 6px), var(--latch-wall));
}

.latch input:focus-visible + .latch-track {
  outline: var(--line-heavy) solid var(--ember);
  outline-offset: 2px;
}

.latch-legend::before {
  content: attr(data-off);
}

.latch input:checked ~ .latch-legend::before {
  content: attr(data-on);
}

/* ---- status tags: the SPEAK posture, with a semantic mouth ----------
   A status announces, so it is a tag — rounded at the mouth, sharp at
   the point. Semantic color lives only in the mouth dot: functional,
   never decorative. (Not a rubber stamp: EMBER wears no costume.) */

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.45em 0.9em 0.45em 0.65em;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  line-height: 1;
  color: var(--ink);
  background: var(--raise);
  border: var(--line-fine) solid var(--edge-strong);
  border-radius: var(--shape-speak);
}

.status::before {
  content: "";
  width: 0.7em;
  height: 0.7em;
  border-radius: 50%;
  background: var(--status, var(--ink-faint));
}

.status--ok {
  --status: var(--ok);
}

.status--warn {
  --status: var(--warn);
}

.status--err {
  --status: var(--err);
}

@media (prefers-reduced-motion: reduce) {
  .icon-move:hover,
  .icon-move:focus-visible {
    animation: none;
  }
}
