voice-typing-ext 0.1.0

Browser extensions (Chrome, Safari) for the voice-typing overlay
Documentation
/* voice-typing — content script styles
   All selectors prefixed with .voice-typing- / .dd- to avoid page conflicts. */

/* ── Overlay container ─────────────────────────────────────────────────── */

.voice-typing-overlay {
  position: fixed;
  z-index: 2147483647;
  width: 22px;
  height: 22px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  pointer-events: auto;
  transition:
    box-shadow 0.3s ease,
    background 0.3s ease;
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}

.voice-typing-overlay:hover {
  transform: scale(1.12);
}

/* ── Icon wrapper ──────────────────────────────────────────────────────── */

.voice-typing-icon {
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.dd-icon {
  width: 100%;
  height: 100%;
}

/* ── Idle — dark mic (default) ─────────────────────────────────────────── */

.voice-typing-overlay[data-state="idle"] .dd-p {
  fill: #1a1a1a;
}
.voice-typing-overlay[data-state="idle"] .dd-s {
  fill: #333;
}

/* ── Disconnected — muted grey ─────────────────────────────────────────── */

.voice-typing-overlay[data-state="disconnected"] {
  background: rgba(240, 240, 240, 0.9);
}
.voice-typing-overlay[data-state="disconnected"] .dd-p {
  fill: #888;
}
.voice-typing-overlay[data-state="disconnected"] .dd-a {
  fill: #666;
}

/* ── Booting — orange glow + spinning clock ────────────────────────────── */

.voice-typing-overlay[data-state="booting"] {
  background: rgba(255, 160, 40, 0.15);
  box-shadow:
    0 0 10px 2px rgba(255, 140, 0, 0.55),
    0 0 24px 4px rgba(255, 100, 0, 0.25);
  animation: dd-glow-pulse 1.2s ease-in-out infinite;
}
.voice-typing-overlay[data-state="booting"] .dd-p {
  fill: #ff8c00;
}
.voice-typing-overlay[data-state="booting"] .dd-s {
  fill: #cc6600;
}
.voice-typing-overlay[data-state="booting"] .dd-spin {
  animation: dd-spin 1.8s linear infinite;
  transform-origin: center;
}

/* ── Active — gradient mic + wifi arcs ─────────────────────────────────── */

.voice-typing-overlay[data-state="active"] {
  background: rgba(155, 48, 255, 0.1);
  box-shadow:
    0 0 8px 2px rgba(155, 48, 255, 0.35),
    0 0 20px 4px rgba(255, 51, 51, 0.15);
}
.voice-typing-overlay[data-state="active"] .dd-p {
  fill: url(#ddGrad);
}
.voice-typing-overlay[data-state="active"] .dd-s {
  fill: url(#ddGrad);
}

/* ── Error — red warning ───────────────────────────────────────────────── */

.voice-typing-overlay[data-state="error"] {
  background: rgba(255, 68, 68, 0.12);
  box-shadow: 0 0 8px 2px rgba(255, 68, 68, 0.4);
}
.voice-typing-overlay[data-state="error"] .dd-p {
  fill: #ff4444;
}
.voice-typing-overlay[data-state="error"] .dd-s {
  fill: #cc0000;
}

/* ── Wifi arcs (active state only) ─────────────────────────────────────── */

.voice-typing-arcs {
  position: absolute;
  bottom: 100%;
  left: 50%;
  width: 0;
  height: 20px;
  pointer-events: none;
  display: none;
}

.voice-typing-overlay[data-state="active"] .voice-typing-arcs {
  display: block;
}

.voice-typing-arc {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  border-style: solid;
  border-bottom: none;
  border-radius: 999px 999px 0 0;
  opacity: 0;
}

.voice-typing-arc-1 {
  width: 10px;
  height: 5px;
  bottom: 0;
  border-width: 2px 2px 0;
  border-color: #ff5555;
  animation: dd-emanate 1.4s 0s ease-in-out infinite;
}
.voice-typing-arc-2 {
  width: 16px;
  height: 8px;
  bottom: 5px;
  border-width: 2px 2px 0;
  border-color: #bb44ff;
  animation: dd-emanate 1.4s 0.18s ease-in-out infinite;
}
.voice-typing-arc-3 {
  width: 22px;
  height: 11px;
  bottom: 10px;
  border-width: 2px 2px 0;
  border-color: #ffffff;
  animation: dd-emanate 1.4s 0.36s ease-in-out infinite;
}

/* ── Animations ────────────────────────────────────────────────────────── */

@keyframes dd-glow-pulse {
  0%,
  100% {
    box-shadow:
      0 0 10px 2px rgba(255, 140, 0, 0.55),
      0 0 24px 4px rgba(255, 100, 0, 0.25);
  }
  50% {
    box-shadow:
      0 0 16px 4px rgba(255, 140, 0, 0.75),
      0 0 32px 8px rgba(255, 100, 0, 0.35);
  }
}

@keyframes dd-emanate {
  0%,
  100% {
    opacity: 0.15;
    transform: translateX(-50%) scaleY(0.8);
  }
  50% {
    opacity: 1;
    transform: translateX(-50%) scaleY(1.1);
  }
}

@keyframes dd-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}