Spaces:
Running
Running
| /* ============================================================ | |
| Puck — sprite, companion window, comments, notifications, | |
| Night Bloom. Loaded after styles.css. | |
| ============================================================ */ | |
| /* ============================================================ | |
| The sprite | |
| ============================================================ */ | |
| .puck { | |
| position: fixed; | |
| z-index: 60; | |
| left: 0; | |
| top: 0; | |
| width: 64px; | |
| height: 64px; | |
| transform: translate(-100px, -100px); | |
| transition: transform 1.25s cubic-bezier(0.45, 0.05, 0.25, 1); | |
| pointer-events: none; | |
| will-change: transform; | |
| } | |
| .puck.snappy { | |
| transition: transform 0.7s cubic-bezier(0.5, 0, 0.2, 1); | |
| } | |
| .puck-hit { | |
| position: absolute; | |
| inset: -6px; | |
| pointer-events: auto; | |
| cursor: pointer; | |
| } | |
| /* inner wrapper handles bob + facing so the flight transform stays clean */ | |
| .puck-bob { | |
| width: 100%; | |
| height: 100%; | |
| animation: bob 3.1s ease-in-out infinite; | |
| position: relative; | |
| } | |
| @keyframes bob { | |
| 0%, | |
| 100% { | |
| transform: translateY(-3px); | |
| } | |
| 50% { | |
| transform: translateY(3px); | |
| } | |
| } | |
| .puck.flying .puck-bob { | |
| animation-duration: 0.9s; | |
| } | |
| .puck-face { | |
| width: 100%; | |
| height: 100%; | |
| position: relative; | |
| transition: transform 0.4s; | |
| } | |
| .puck.face-left .puck-face { | |
| transform: scaleX(-1); | |
| } | |
| /* glow halo */ | |
| .puck-glow { | |
| position: absolute; | |
| inset: -55%; | |
| border-radius: 50%; | |
| background: radial-gradient(circle, var(--puck-glow, var(--glow)) 0%, transparent 62%); | |
| opacity: 1; | |
| animation: pulse 3.4s ease-in-out infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, | |
| 100% { | |
| transform: scale(0.9); | |
| opacity: 0.6; | |
| } | |
| 50% { | |
| transform: scale(1.12); | |
| opacity: 1; | |
| } | |
| } | |
| /* body */ | |
| .puck-body { | |
| position: absolute; | |
| left: 50%; | |
| top: 50%; | |
| width: 38px; | |
| height: 38px; | |
| transform: translate(-50%, -50%); | |
| border-radius: 50%; | |
| background: radial-gradient(circle at 35% 30%, var(--puck-hi, #cdeccb), var(--puck-body, #8fd6a0) 70%); | |
| box-shadow: | |
| inset -3px -4px 8px rgba(0, 0, 0, 0.25), | |
| 0 3px 14px rgba(0, 0, 0, 0.4); | |
| } | |
| .puck-eye { | |
| position: absolute; | |
| top: 40%; | |
| width: 6px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: #15201a; | |
| } | |
| .puck-eye.l { | |
| left: 31%; | |
| } | |
| .puck-eye.r { | |
| right: 31%; | |
| } | |
| .puck-eye::after { | |
| content: ""; | |
| position: absolute; | |
| top: 1px; | |
| left: 1px; | |
| width: 2.5px; | |
| height: 2.5px; | |
| border-radius: 50%; | |
| background: rgba(255, 255, 255, 0.9); | |
| } | |
| .puck-cheek { | |
| position: absolute; | |
| top: 56%; | |
| width: 5px; | |
| height: 3px; | |
| border-radius: 50%; | |
| background: rgba(255, 140, 120, 0.45); | |
| } | |
| .puck-cheek.l { | |
| left: 26%; | |
| } | |
| .puck-cheek.r { | |
| right: 26%; | |
| } | |
| /* wings */ | |
| .puck-wing { | |
| position: absolute; | |
| top: 42%; | |
| width: 26px; | |
| height: 30px; | |
| background: radial-gradient( | |
| circle at 50% 30%, | |
| rgba(255, 255, 255, 0.5), | |
| var(--puck-wing, rgba(180, 230, 200, 0.32)) 70%, | |
| transparent | |
| ); | |
| border: 0.5px solid rgba(255, 255, 255, 0.4); | |
| } | |
| .puck-wing.l { | |
| right: 56%; | |
| border-radius: 60% 30% 50% 50%; | |
| transform-origin: right center; | |
| animation: flapL 0.34s ease-in-out infinite alternate; | |
| } | |
| .puck-wing.r { | |
| left: 56%; | |
| border-radius: 30% 60% 50% 50%; | |
| transform-origin: left center; | |
| animation: flapR 0.34s ease-in-out infinite alternate; | |
| } | |
| @keyframes flapL { | |
| from { | |
| transform: rotateY(20deg) rotate(8deg); | |
| } | |
| to { | |
| transform: rotateY(60deg) rotate(-12deg); | |
| } | |
| } | |
| @keyframes flapR { | |
| from { | |
| transform: rotateY(-20deg) rotate(-8deg); | |
| } | |
| to { | |
| transform: rotateY(-60deg) rotate(12deg); | |
| } | |
| } | |
| .puck.flying .puck-wing.l, | |
| .puck.flying .puck-wing.r { | |
| animation-duration: 0.18s; | |
| } | |
| .puck.resting .puck-wing.l, | |
| .puck.resting .puck-wing.r { | |
| animation-duration: 0.7s; | |
| } | |
| /* sparkle trail dot */ | |
| .puck-trail { | |
| position: absolute; | |
| left: 50%; | |
| top: 50%; | |
| width: 4px; | |
| height: 4px; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| opacity: 0; | |
| } | |
| .puck.flying .puck-trail { | |
| animation: trail 0.9s ease-out infinite; | |
| } | |
| @keyframes trail { | |
| 0% { | |
| opacity: 0.8; | |
| transform: translate(-50%, -50%) scale(1); | |
| } | |
| 100% { | |
| opacity: 0; | |
| transform: translate(-50%, 14px) scale(0.2); | |
| } | |
| } | |
| /* mood tints applied to :root */ | |
| .mood-curious { | |
| --puck-body: #8fd6a0; | |
| --puck-hi: #cdeccb; | |
| --puck-wing: rgba(180, 230, 200, 0.34); | |
| --puck-glow: rgba(150, 220, 170, 0.22); | |
| } | |
| .mood-mischief { | |
| --puck-body: #c9a3ec; | |
| --puck-hi: #ead7fa; | |
| --puck-wing: rgba(210, 180, 240, 0.34); | |
| --puck-glow: rgba(190, 150, 235, 0.24); | |
| } | |
| .mood-sleepy { | |
| --puck-body: #7f93c4; | |
| --puck-hi: #c3cdec; | |
| --puck-wing: rgba(170, 185, 225, 0.3); | |
| --puck-glow: rgba(150, 170, 225, 0.2); | |
| } | |
| .mood-proud { | |
| --puck-body: #edc46a; | |
| --puck-hi: #f7e6b3; | |
| --puck-wing: rgba(240, 210, 150, 0.34); | |
| --puck-glow: rgba(231, 184, 92, 0.26); | |
| } | |
| .mood-grumpy { | |
| --puck-body: #d98a72; | |
| --puck-hi: #f0bca8; | |
| --puck-wing: rgba(225, 170, 150, 0.32); | |
| --puck-glow: rgba(210, 130, 100, 0.22); | |
| } | |
| /* ============================================================ | |
| Speech bubble (Puck's comments anchored to the sprite) | |
| ============================================================ */ | |
| .bubble { | |
| position: fixed; | |
| z-index: 61; | |
| max-width: 290px; | |
| pointer-events: auto; | |
| padding: 12px 15px 13px; | |
| border-radius: 15px; | |
| background: var(--panel-2); | |
| border: 0.5px solid var(--border-strong); | |
| backdrop-filter: blur(26px) saturate(150%); | |
| -webkit-backdrop-filter: blur(26px) saturate(150%); | |
| box-shadow: | |
| var(--shadow), | |
| 0 0 28px var(--glow); | |
| transform-origin: var(--bub-org, bottom left); | |
| animation: bubpop 0.4s cubic-bezier(0.2, 1.3, 0.4, 1); | |
| } | |
| @keyframes bubpop { | |
| from { | |
| opacity: 0; | |
| transform: scale(0.7) translateY(8px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: scale(1) translateY(0); | |
| } | |
| } | |
| .bubble.out { | |
| animation: bubout 0.3s ease forwards; | |
| } | |
| @keyframes bubout { | |
| to { | |
| opacity: 0; | |
| transform: scale(0.85) translateY(6px); | |
| } | |
| } | |
| .bubble .bub-src { | |
| font-size: 10px; | |
| font-weight: 700; | |
| letter-spacing: 0.07em; | |
| text-transform: uppercase; | |
| color: var(--accent); | |
| margin-bottom: 5px; | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .bubble .bub-src .bub-tier { | |
| color: var(--ink-faint); | |
| font-weight: 600; | |
| } | |
| .bubble .bub-text { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 16px; | |
| line-height: 1.4; | |
| color: var(--ink); | |
| } | |
| .bubble.style-plain .bub-text { | |
| font-family: var(--ui); | |
| font-style: normal; | |
| font-size: 14px; | |
| } | |
| .bubble.style-hand .bub-text { | |
| font-family: var(--hand); | |
| font-style: normal; | |
| font-size: 20px; | |
| } | |
| .bubble .bub-tail { | |
| position: absolute; | |
| width: 14px; | |
| height: 14px; | |
| background: inherit; | |
| border-left: 0.5px solid var(--border-strong); | |
| border-bottom: 0.5px solid var(--border-strong); | |
| transform: rotate(45deg); | |
| } | |
| .bubble .bub-acts { | |
| display: flex; | |
| gap: 6px; | |
| margin-top: 10px; | |
| } | |
| .bub-rate { | |
| flex: 1; | |
| appearance: none; | |
| border: 0.5px solid var(--border); | |
| background: var(--panel); | |
| color: var(--ink-soft); | |
| font-family: var(--ui); | |
| font-size: 11px; | |
| padding: 5px 4px; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| transition: all 0.13s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 3px; | |
| } | |
| .bub-rate:hover { | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| border-color: transparent; | |
| transform: translateY(-1px); | |
| } | |
| /* ============================================================ | |
| Companion window — the "note-taking" feed surface | |
| ============================================================ */ | |
| .comp { | |
| position: fixed; | |
| z-index: 40; | |
| width: 372px; | |
| display: flex; | |
| flex-direction: column; | |
| max-height: calc(100vh - 120px); | |
| } | |
| .comp-head { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 13px 14px 11px; | |
| cursor: grab; | |
| } | |
| .comp-head:active { | |
| cursor: grabbing; | |
| } | |
| .comp-spr { | |
| width: 34px; | |
| height: 34px; | |
| border-radius: 50%; | |
| flex: none; | |
| position: relative; | |
| background: radial-gradient(circle at 35% 30%, var(--puck-hi, #cdeccb), var(--puck-body, #8fd6a0) 70%); | |
| box-shadow: inset -2px -3px 6px rgba(0, 0, 0, 0.25); | |
| } | |
| .comp-spr .e { | |
| position: absolute; | |
| top: 13px; | |
| width: 4px; | |
| height: 6px; | |
| border-radius: 50%; | |
| background: #15201a; | |
| } | |
| .comp-spr .e.l { | |
| left: 11px; | |
| } | |
| .comp-spr .e.r { | |
| right: 11px; | |
| } | |
| .comp-id { | |
| line-height: 1.15; | |
| } | |
| .comp-id b { | |
| font-size: 14px; | |
| } | |
| .comp-id span { | |
| font-size: 11px; | |
| color: var(--ink-soft); | |
| display: block; | |
| font-family: var(--voice); | |
| font-style: italic; | |
| } | |
| .comp-head .comp-x { | |
| margin-left: auto; | |
| appearance: none; | |
| border: 0; | |
| background: transparent; | |
| color: var(--ink-faint); | |
| font-size: 14px; | |
| cursor: pointer; | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 7px; | |
| } | |
| .comp-head .comp-x:hover { | |
| background: var(--panel); | |
| color: var(--ink); | |
| } | |
| .comp-tabs { | |
| display: flex; | |
| gap: 2px; | |
| padding: 0 12px; | |
| border-bottom: 0.5px solid var(--border); | |
| } | |
| .comp-tab { | |
| appearance: none; | |
| border: 0; | |
| background: transparent; | |
| color: var(--ink-soft); | |
| font-family: var(--ui); | |
| font-size: 12.5px; | |
| font-weight: 600; | |
| padding: 9px 11px; | |
| cursor: pointer; | |
| border-bottom: 2px solid transparent; | |
| margin-bottom: -0.5px; | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .comp-tab:hover { | |
| color: var(--ink); | |
| } | |
| .comp-tab.on { | |
| color: var(--ink); | |
| border-bottom-color: var(--accent); | |
| } | |
| .comp-tab .tcount { | |
| font-size: 10px; | |
| background: var(--panel); | |
| padding: 1px 6px; | |
| border-radius: 9px; | |
| font-weight: 700; | |
| } | |
| .comp-body { | |
| flex: 1; | |
| min-height: 0; | |
| overflow-y: auto; | |
| padding: 12px 14px; | |
| } | |
| /* feed items */ | |
| .feed-day { | |
| font-size: 10px; | |
| font-weight: 700; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| margin: 4px 0 10px; | |
| } | |
| .feed-item { | |
| display: flex; | |
| gap: 11px; | |
| padding-bottom: 16px; | |
| position: relative; | |
| } | |
| .feed-item::before { | |
| content: ""; | |
| position: absolute; | |
| left: 6px; | |
| top: 16px; | |
| bottom: -2px; | |
| width: 1.5px; | |
| background: var(--border); | |
| } | |
| .feed-item:last-child::before { | |
| display: none; | |
| } | |
| .feed-dot { | |
| width: 13px; | |
| height: 13px; | |
| border-radius: 50%; | |
| flex: none; | |
| margin-top: 2px; | |
| background: var(--panel); | |
| border: 2px solid var(--border-strong); | |
| z-index: 1; | |
| } | |
| .feed-dot.notify { | |
| background: var(--accent); | |
| border-color: var(--accent); | |
| box-shadow: 0 0 10px var(--glow); | |
| } | |
| .feed-dot.interrupt { | |
| background: #ff5b54; | |
| border-color: #ff5b54; | |
| } | |
| .feed-dot.ignore { | |
| background: transparent; | |
| } | |
| .feed-main { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .feed-meta { | |
| display: flex; | |
| align-items: baseline; | |
| gap: 8px; | |
| margin-bottom: 2px; | |
| } | |
| .feed-src { | |
| font-size: 10.5px; | |
| font-weight: 700; | |
| letter-spacing: 0.05em; | |
| text-transform: uppercase; | |
| color: var(--ink-soft); | |
| } | |
| .feed-time { | |
| font-size: 10px; | |
| color: var(--ink-faint); | |
| font-family: var(--mono); | |
| margin-left: auto; | |
| } | |
| .feed-say { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 14.5px; | |
| line-height: 1.42; | |
| color: var(--ink); | |
| } | |
| .feed-say.plain { | |
| font-family: var(--ui); | |
| font-style: normal; | |
| font-size: 13px; | |
| } | |
| .feed-decision { | |
| font-size: 10.5px; | |
| color: var(--ink-faint); | |
| margin-top: 4px; | |
| font-family: var(--mono); | |
| } | |
| .feed-rated { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 4px; | |
| font-size: 10.5px; | |
| margin-top: 5px; | |
| padding: 2px 8px; | |
| border-radius: 9px; | |
| background: var(--panel); | |
| color: var(--ink-soft); | |
| } | |
| /* chat */ | |
| .chat-log { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 11px; | |
| } | |
| .chat-msg { | |
| max-width: 86%; | |
| padding: 9px 13px; | |
| border-radius: 14px; | |
| font-size: 13.5px; | |
| line-height: 1.4; | |
| } | |
| .chat-msg.user { | |
| align-self: flex-end; | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| border-bottom-right-radius: 5px; | |
| } | |
| .chat-msg.puck { | |
| align-self: flex-start; | |
| background: var(--panel); | |
| border: 0.5px solid var(--border); | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 14.5px; | |
| border-bottom-left-radius: 5px; | |
| } | |
| .chat-input { | |
| display: flex; | |
| gap: 8px; | |
| padding: 11px 14px; | |
| border-top: 0.5px solid var(--border); | |
| } | |
| .chat-input input { | |
| flex: 1; | |
| background: var(--panel); | |
| border: 0.5px solid var(--border); | |
| border-radius: 10px; | |
| padding: 9px 12px; | |
| color: var(--ink); | |
| font-family: var(--ui); | |
| font-size: 13px; | |
| outline: none; | |
| } | |
| .chat-input input:focus { | |
| border-color: var(--accent); | |
| } | |
| .chat-input button { | |
| appearance: none; | |
| border: 0; | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| border-radius: 10px; | |
| padding: 0 14px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| } | |
| /* memory garden */ | |
| .garden { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 9px; | |
| } | |
| .mem { | |
| display: flex; | |
| gap: 11px; | |
| padding: 11px 12px; | |
| border-radius: 11px; | |
| background: var(--panel); | |
| border: 0.5px solid var(--border); | |
| align-items: flex-start; | |
| transition: | |
| transform 0.15s, | |
| box-shadow 0.15s; | |
| } | |
| .mem.pinned { | |
| border-color: var(--accent); | |
| box-shadow: | |
| 0 0 0 0.5px var(--accent), | |
| 0 0 18px var(--glow); | |
| } | |
| .mem .mem-ico { | |
| font-size: 19px; | |
| flex: none; | |
| line-height: 1.2; | |
| } | |
| .mem .mem-main { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .mem .mem-text { | |
| font-size: 13px; | |
| line-height: 1.4; | |
| } | |
| .mem .mem-foot { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-top: 7px; | |
| } | |
| .mem .mem-type { | |
| font-size: 9.5px; | |
| font-weight: 700; | |
| letter-spacing: 0.06em; | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| } | |
| .mem .mem-salience { | |
| flex: 1; | |
| height: 4px; | |
| border-radius: 3px; | |
| background: var(--border); | |
| overflow: hidden; | |
| max-width: 80px; | |
| } | |
| .mem .mem-salience i { | |
| display: block; | |
| height: 100%; | |
| background: var(--accent); | |
| transition: width 0.4s; | |
| } | |
| .mem .mem-acts { | |
| display: flex; | |
| gap: 4px; | |
| } | |
| .mem-btn { | |
| appearance: none; | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 7px; | |
| border: 0.5px solid var(--border); | |
| background: transparent; | |
| cursor: pointer; | |
| font-size: 12px; | |
| opacity: 0.6; | |
| transition: all 0.13s; | |
| } | |
| .mem-btn:hover { | |
| opacity: 1; | |
| background: var(--panel-2); | |
| transform: translateY(-1px); | |
| } | |
| .mem-btn.on { | |
| opacity: 1; | |
| background: var(--accent); | |
| border-color: transparent; | |
| } | |
| .empty { | |
| text-align: center; | |
| color: var(--ink-faint); | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 14px; | |
| padding: 30px 16px; | |
| line-height: 1.5; | |
| } | |
| /* fairy state strip (companion footer) */ | |
| .state-strip { | |
| padding: 11px 14px; | |
| border-top: 0.5px solid var(--border); | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 9px 16px; | |
| } | |
| .stat-top { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 10.5px; | |
| margin-bottom: 4px; | |
| } | |
| .stat-top .sl { | |
| color: var(--ink-soft); | |
| font-weight: 600; | |
| } | |
| .stat-top .sv { | |
| color: var(--ink-faint); | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .stat-bar { | |
| height: 5px; | |
| border-radius: 3px; | |
| background: var(--border); | |
| overflow: hidden; | |
| } | |
| .stat-bar i { | |
| display: block; | |
| height: 100%; | |
| background: var(--accent); | |
| transition: width 0.6s cubic-bezier(0.3, 0.8, 0.3, 1); | |
| border-radius: 3px; | |
| } | |
| .stat-bar i.delta-up { | |
| animation: glowup 1.2s ease; | |
| } | |
| @keyframes glowup { | |
| 0%, | |
| 100% { | |
| box-shadow: none; | |
| } | |
| 40% { | |
| box-shadow: 0 0 12px var(--accent); | |
| } | |
| } | |
| /* ============================================================ | |
| Menu-bar dropdown | |
| ============================================================ */ | |
| .drop { | |
| position: fixed; | |
| top: 30px; | |
| z-index: 70; | |
| width: 280px; | |
| padding: 8px; | |
| } | |
| .drop-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 8px 10px; | |
| border-radius: 8px; | |
| font-size: 13px; | |
| cursor: pointer; | |
| } | |
| .drop-row:hover { | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| } | |
| .drop-row .dr-ico { | |
| width: 18px; | |
| text-align: center; | |
| opacity: 0.8; | |
| } | |
| .drop-row .dr-k { | |
| margin-left: auto; | |
| font-size: 11px; | |
| opacity: 0.5; | |
| font-family: var(--mono); | |
| } | |
| .drop-sep { | |
| height: 0.5px; | |
| background: var(--border); | |
| margin: 6px 4px; | |
| } | |
| .drop-status { | |
| padding: 9px 11px 11px; | |
| } | |
| .drop-status .ds-line { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 14px; | |
| line-height: 1.4; | |
| color: var(--ink); | |
| } | |
| .drop-modes { | |
| display: flex; | |
| gap: 5px; | |
| margin-top: 10px; | |
| } | |
| .mode-pill { | |
| flex: 1; | |
| text-align: center; | |
| font-size: 10.5px; | |
| font-weight: 600; | |
| padding: 6px 4px; | |
| border-radius: 8px; | |
| background: var(--panel); | |
| border: 0.5px solid var(--border); | |
| cursor: pointer; | |
| color: var(--ink-soft); | |
| } | |
| .mode-pill.on { | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| border-color: transparent; | |
| } | |
| /* ============================================================ | |
| Notifications (toast / interrupt) | |
| ============================================================ */ | |
| .toasts { | |
| position: fixed; | |
| top: 34px; | |
| right: 12px; | |
| z-index: 65; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 9px; | |
| width: 330px; | |
| } | |
| .toast { | |
| padding: 13px 14px; | |
| border-radius: 14px; | |
| background: var(--panel-2); | |
| border: 0.5px solid var(--border); | |
| backdrop-filter: blur(26px) saturate(150%); | |
| -webkit-backdrop-filter: blur(26px) saturate(150%); | |
| box-shadow: var(--shadow); | |
| animation: toastin 0.45s cubic-bezier(0.2, 1.1, 0.4, 1); | |
| } | |
| @keyframes toastin { | |
| from { | |
| opacity: 0; | |
| transform: translateX(40px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| .toast.out { | |
| animation: toastout 0.3s ease forwards; | |
| } | |
| @keyframes toastout { | |
| to { | |
| opacity: 0; | |
| transform: translateX(40px); | |
| } | |
| } | |
| .toast-top { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 6px; | |
| } | |
| .toast-top .tt-spr { | |
| width: 22px; | |
| height: 22px; | |
| border-radius: 50%; | |
| flex: none; | |
| background: radial-gradient(circle at 35% 30%, var(--puck-hi, #cdeccb), var(--puck-body, #8fd6a0) 70%); | |
| } | |
| .toast-top .tt-name { | |
| font-size: 12px; | |
| font-weight: 700; | |
| } | |
| .toast-top .tt-time { | |
| margin-left: auto; | |
| font-size: 10.5px; | |
| color: var(--ink-faint); | |
| font-family: var(--mono); | |
| } | |
| .toast-top .tt-hint { | |
| margin-left: auto; | |
| font-size: 10px; | |
| color: var(--ink-faint); | |
| opacity: 0.7; | |
| white-space: nowrap; | |
| } | |
| /* a toast is grab-and-fling: tap opens the app, throw swats it away */ | |
| .toast.throw { | |
| cursor: grab; | |
| user-select: none; | |
| touch-action: none; | |
| } | |
| .toast.throw:active { | |
| cursor: grabbing; | |
| } | |
| .toast-say { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 14.5px; | |
| line-height: 1.4; | |
| } | |
| .toast-say.plain { | |
| font-family: var(--ui); | |
| font-style: normal; | |
| font-size: 13px; | |
| } | |
| .toast-acts { | |
| display: flex; | |
| gap: 6px; | |
| margin-top: 10px; | |
| } | |
| /* full interrupt overlay */ | |
| .interrupt-wrap { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 80; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: rgba(0, 0, 0, 0.4); | |
| backdrop-filter: blur(3px); | |
| animation: fadein 0.3s; | |
| } | |
| @keyframes fadein { | |
| from { | |
| opacity: 0; | |
| } | |
| to { | |
| opacity: 1; | |
| } | |
| } | |
| .interrupt-card { | |
| width: 380px; | |
| padding: 22px; | |
| text-align: center; | |
| animation: bubpop 0.45s cubic-bezier(0.2, 1.3, 0.4, 1); | |
| } | |
| .interrupt-card .int-spr { | |
| width: 56px; | |
| height: 56px; | |
| margin: 0 auto 14px; | |
| position: relative; | |
| background: radial-gradient(circle at 35% 30%, var(--puck-hi, #cdeccb), var(--puck-body, #8fd6a0) 70%); | |
| border-radius: 50%; | |
| box-shadow: 0 0 30px var(--glow); | |
| } | |
| .interrupt-card .int-say { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 19px; | |
| line-height: 1.4; | |
| margin-bottom: 16px; | |
| } | |
| .interrupt-card .int-acts { | |
| display: flex; | |
| gap: 9px; | |
| } | |
| .btn { | |
| appearance: none; | |
| border: 0.5px solid var(--border); | |
| background: var(--panel); | |
| color: var(--ink); | |
| font-family: var(--ui); | |
| font-size: 12.5px; | |
| font-weight: 600; | |
| padding: 8px 12px; | |
| border-radius: 9px; | |
| cursor: pointer; | |
| flex: 1; | |
| transition: all 0.13s; | |
| } | |
| .btn:hover { | |
| background: var(--panel-2); | |
| transform: translateY(-1px); | |
| } | |
| .btn.primary { | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| border-color: transparent; | |
| } | |
| .btn.primary:hover { | |
| filter: brightness(1.08); | |
| } | |
| /* ============================================================ | |
| Night Bloom (sleep / wake) | |
| ============================================================ */ | |
| .bloom { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 90; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: radial-gradient(circle at 50% 40%, #14202c, #060a0f 80%); | |
| animation: fadein 0.6s; | |
| overflow: hidden; | |
| } | |
| :root[data-theme="candlelight"] .bloom { | |
| background: radial-gradient(circle at 50% 40%, #2a2114, #140d06 80%); | |
| } | |
| .bloom-stars { | |
| position: absolute; | |
| inset: 0; | |
| background-image: radial-gradient(circle, rgba(255, 255, 255, 0.7) 0.6px, transparent 1px); | |
| background-size: 38px 52px; | |
| opacity: 0.18; | |
| animation: twinkle 5s ease-in-out infinite; | |
| } | |
| @keyframes twinkle { | |
| 0%, | |
| 100% { | |
| opacity: 0.1; | |
| } | |
| 50% { | |
| opacity: 0.25; | |
| } | |
| } | |
| .bloom-card { | |
| width: 460px; | |
| max-width: 90vw; | |
| text-align: center; | |
| position: relative; | |
| z-index: 1; | |
| color: #f0e7d0; | |
| } | |
| .bloom-spr { | |
| width: 70px; | |
| height: 70px; | |
| margin: 0 auto 20px; | |
| position: relative; | |
| border-radius: 50%; | |
| background: radial-gradient(circle at 35% 30%, #c3cdec, #7f93c4 70%); | |
| box-shadow: 0 0 50px rgba(150, 170, 225, 0.5); | |
| animation: bob 3.6s ease-in-out infinite; | |
| } | |
| .bloom-spr .ze { | |
| position: absolute; | |
| top: 28px; | |
| width: 8px; | |
| height: 3px; | |
| border-radius: 3px; | |
| background: #1a2436; | |
| } | |
| .bloom-spr .ze.l { | |
| left: 20px; | |
| } | |
| .bloom-spr .ze.r { | |
| right: 20px; | |
| } | |
| .bloom-stage { | |
| font-size: 11px; | |
| font-weight: 700; | |
| letter-spacing: 0.16em; | |
| text-transform: uppercase; | |
| color: rgba(240, 231, 208, 0.5); | |
| margin-bottom: 14px; | |
| min-height: 14px; | |
| } | |
| .bloom-title { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 26px; | |
| margin-bottom: 8px; | |
| } | |
| .bloom-text { | |
| font-size: 14px; | |
| line-height: 1.6; | |
| color: rgba(240, 231, 208, 0.78); | |
| min-height: 70px; | |
| } | |
| .bloom-dream { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 17px; | |
| line-height: 1.6; | |
| color: rgba(240, 231, 208, 0.9); | |
| padding: 0 10px; | |
| } | |
| .bloom-deltas { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| margin: 18px 0; | |
| text-align: left; | |
| } | |
| .bloom-delta { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| font-size: 13px; | |
| padding: 9px 13px; | |
| border-radius: 10px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 0.5px solid rgba(255, 255, 255, 0.12); | |
| animation: deltain 0.5s ease backwards; | |
| } | |
| @keyframes deltain { | |
| from { | |
| opacity: 0; | |
| transform: translateY(8px); | |
| } | |
| to { | |
| opacity: 1; | |
| } | |
| } | |
| .bloom-delta .bd-dir { | |
| font-weight: 700; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .bloom-delta .bd-dir.up { | |
| color: #7fdc9a; | |
| } | |
| .bloom-delta .bd-dir.down { | |
| color: #e89a8a; | |
| } | |
| .bloom-delta .bd-label { | |
| flex: 1; | |
| } | |
| .bloom-mem { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| } | |
| .bloom-prog { | |
| display: flex; | |
| gap: 5px; | |
| justify-content: center; | |
| margin-top: 20px; | |
| } | |
| .bloom-prog i { | |
| width: 6px; | |
| height: 6px; | |
| border-radius: 50%; | |
| background: rgba(240, 231, 208, 0.25); | |
| transition: all 0.3s; | |
| } | |
| .bloom-prog i.on { | |
| background: rgba(240, 231, 208, 0.85); | |
| transform: scale(1.3); | |
| } | |
| .bloom-btn { | |
| margin-top: 24px; | |
| appearance: none; | |
| border: 0.5px solid rgba(255, 255, 255, 0.25); | |
| background: rgba(255, 255, 255, 0.08); | |
| color: #f0e7d0; | |
| font-family: var(--ui); | |
| font-size: 13.5px; | |
| font-weight: 600; | |
| padding: 11px 26px; | |
| border-radius: 11px; | |
| cursor: pointer; | |
| transition: all 0.15s; | |
| } | |
| .bloom-btn:hover { | |
| background: rgba(255, 255, 255, 0.16); | |
| transform: translateY(-1px); | |
| } | |
| /* sleeping-Z floaties */ | |
| .zfly { | |
| position: absolute; | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 22px; | |
| color: rgba(240, 231, 208, 0.5); | |
| animation: zfly 3.2s ease-out infinite; | |
| } | |
| @keyframes zfly { | |
| 0% { | |
| opacity: 0; | |
| transform: translateY(0) scale(0.6); | |
| } | |
| 30% { | |
| opacity: 0.7; | |
| } | |
| 100% { | |
| opacity: 0; | |
| transform: translateY(-60px) translateX(20px) scale(1.2); | |
| } | |
| } | |
| /* ============================================================ | |
| Speaking shimmer — sound rings when Puck talks aloud | |
| ============================================================ */ | |
| .puck-voicewave { | |
| position: absolute; | |
| left: 50%; | |
| top: 50%; | |
| width: 0; | |
| height: 0; | |
| pointer-events: none; | |
| opacity: 0; | |
| } | |
| .puck.speaking .puck-voicewave { | |
| opacity: 1; | |
| } | |
| .puck.speaking .puck-voicewave i { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| border-radius: 50%; | |
| border: 1.5px solid var(--accent); | |
| transform: translate(-50%, -50%); | |
| animation: voicering 1.5s ease-out infinite; | |
| } | |
| .puck.speaking .puck-voicewave i:nth-child(2) { | |
| animation-delay: 0.5s; | |
| } | |
| .puck.speaking .puck-voicewave i:nth-child(3) { | |
| animation-delay: 1s; | |
| } | |
| @keyframes voicering { | |
| 0% { | |
| width: 30px; | |
| height: 30px; | |
| opacity: 0.7; | |
| } | |
| 100% { | |
| width: 86px; | |
| height: 86px; | |
| opacity: 0; | |
| } | |
| } | |
| .puck.speaking .puck-glow { | |
| animation-duration: 0.7s; | |
| } | |
| /* ============================================================ | |
| Automation offer toast — the "want me to handle it?" card | |
| ============================================================ */ | |
| .toast.offer { | |
| border-color: var(--accent); | |
| box-shadow: | |
| var(--shadow), | |
| 0 0 28px var(--glow); | |
| } | |
| .toast.offer .tt-name { | |
| color: var(--accent); | |
| } | |
| /* feed dots for learned / handled */ | |
| .feed-dot.handled { | |
| background: var(--panel); | |
| border-color: var(--accent); | |
| position: relative; | |
| } | |
| .feed-dot.handled::after { | |
| content: "✓"; | |
| position: absolute; | |
| inset: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 8px; | |
| color: var(--accent); | |
| font-weight: 700; | |
| } | |
| .feed-dot.learned { | |
| background: var(--accent); | |
| border-color: var(--accent); | |
| box-shadow: 0 0 12px var(--glow); | |
| } | |
| /* ============================================================ | |
| Learning panel | |
| ============================================================ */ | |
| .learn-note { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 13.5px; | |
| line-height: 1.45; | |
| color: var(--ink-soft); | |
| padding: 2px 0 4px; | |
| } | |
| /* Memory tab — Puck's recent observations (peek log) */ | |
| .musings { | |
| display: flex; | |
| flex-direction: column; | |
| margin-top: 6px; | |
| } | |
| .musing { | |
| display: flex; | |
| gap: 9px; | |
| padding: 9px 2px; | |
| border-bottom: 1px solid var(--line, rgba(255, 255, 255, 0.06)); | |
| } | |
| .musing-dot { | |
| width: 6px; | |
| height: 6px; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| margin-top: 6px; | |
| flex: none; | |
| opacity: 0.65; | |
| } | |
| .musing-main { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .musing-text { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 13.5px; | |
| line-height: 1.4; | |
| } | |
| .musing-time { | |
| font-size: 10.5px; | |
| color: var(--ink-faint); | |
| font-family: var(--mono); | |
| margin-top: 3px; | |
| } | |
| /* a musing is clickable (→ label this peek) */ | |
| button.musing { | |
| width: 100%; | |
| text-align: left; | |
| font: inherit; | |
| color: inherit; | |
| background: none; | |
| border: none; | |
| border-bottom: 1px solid var(--line, rgba(255, 255, 255, 0.06)); | |
| cursor: pointer; | |
| } | |
| button.musing:hover { | |
| background: rgba(255, 255, 255, 0.04); | |
| } | |
| /* labeling view: screenshot + reuse-a-label chips + a new label */ | |
| .label-shot { | |
| display: block; | |
| width: 100%; | |
| border-radius: 10px; | |
| border: 1px solid var(--line, rgba(255, 255, 255, 0.12)); | |
| margin: 8px 0; | |
| } | |
| .label-quip { | |
| font-family: var(--voice); | |
| font-style: italic; | |
| font-size: 13px; | |
| color: var(--ink-soft); | |
| margin-bottom: 10px; | |
| } | |
| .label-pick { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| margin-bottom: 10px; | |
| } | |
| .label-pick .ltag { | |
| cursor: pointer; | |
| border: none; | |
| } | |
| .label-new { | |
| display: flex; | |
| gap: 6px; | |
| } | |
| .label-new input { | |
| flex: 1; | |
| min-width: 0; | |
| font: inherit; | |
| font-size: 12px; | |
| color: var(--ink); | |
| background: var(--surface-2, rgba(0, 0, 0, 0.08)); | |
| border: 1px solid var(--line, rgba(0, 0, 0, 0.12)); | |
| border-radius: 8px; | |
| padding: 6px 8px; | |
| } | |
| .label-new button { | |
| font: inherit; | |
| font-size: 12px; | |
| cursor: pointer; | |
| background: var(--accent); | |
| color: var(--accent-ink, #fff7e8); | |
| border: none; | |
| border-radius: 8px; | |
| padding: 6px 12px; | |
| } | |
| .label-back { | |
| font: inherit; | |
| font-size: 12px; | |
| cursor: pointer; | |
| background: none; | |
| color: var(--ink-faint); | |
| border: none; | |
| margin-top: 12px; | |
| padding: 4px 0; | |
| } | |
| .label-saved { | |
| font-size: 13px; | |
| color: var(--accent); | |
| padding: 10px 0; | |
| } | |
| .learn-empty { | |
| font-size: 12.5px; | |
| color: var(--ink-faint); | |
| font-style: italic; | |
| padding: 2px 0; | |
| } | |
| .learn-sources { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 11px; | |
| } | |
| .lsrc { | |
| display: flex; | |
| gap: 11px; | |
| align-items: flex-start; | |
| } | |
| .lsrc-glyph { | |
| font-size: 16px; | |
| width: 22px; | |
| text-align: center; | |
| flex: none; | |
| opacity: 0.85; | |
| margin-top: 1px; | |
| } | |
| .lsrc-main { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .lsrc-top { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: baseline; | |
| gap: 8px; | |
| margin-bottom: 5px; | |
| } | |
| .lsrc-label { | |
| font-size: 12.5px; | |
| font-weight: 600; | |
| } | |
| .lsrc-disp { | |
| font-size: 10.5px; | |
| font-weight: 700; | |
| letter-spacing: 0.02em; | |
| padding: 2px 8px; | |
| border-radius: 9px; | |
| background: var(--panel); | |
| white-space: nowrap; | |
| } | |
| .lsrc-disp.hi { | |
| color: var(--accent-ink); | |
| background: var(--accent); | |
| } | |
| .lsrc-disp.mid { | |
| color: var(--accent); | |
| } | |
| .lsrc-disp.lo { | |
| color: var(--ink-soft); | |
| } | |
| .lsrc-disp.off { | |
| color: var(--ink-faint); | |
| } | |
| .lsrc-track { | |
| height: 6px; | |
| border-radius: 4px; | |
| background: var(--border); | |
| overflow: hidden; | |
| position: relative; | |
| } | |
| .lsrc-track::before { | |
| content: ""; | |
| position: absolute; | |
| left: 50%; | |
| top: 0; | |
| bottom: 0; | |
| width: 1px; | |
| background: var(--border-strong); | |
| z-index: 1; | |
| } | |
| .lsrc-fill { | |
| display: block; | |
| height: 100%; | |
| background: var(--accent); | |
| transition: width 0.5s cubic-bezier(0.3, 0.8, 0.3, 1); | |
| border-radius: 4px; | |
| } | |
| .lsrc-fill.off, | |
| .lsrc-fill.lo { | |
| background: var(--ink-faint); | |
| } | |
| .lsrc-conf { | |
| font-size: 10px; | |
| color: var(--ink-faint); | |
| font-family: var(--mono); | |
| margin-top: 4px; | |
| } | |
| .learn-tags { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 7px; | |
| } | |
| .ltag { | |
| font-size: 12px; | |
| padding: 5px 11px; | |
| border-radius: 20px; | |
| background: var(--panel); | |
| border: 0.5px solid var(--border); | |
| color: var(--ink); | |
| white-space: nowrap; | |
| } | |
| .ltag.irk { | |
| border-color: rgba(230, 140, 110, 0.4); | |
| color: var(--ink-soft); | |
| } | |
| .learn-autos { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .lauto { | |
| display: flex; | |
| gap: 11px; | |
| padding: 11px 12px; | |
| border-radius: 11px; | |
| align-items: flex-start; | |
| background: var(--panel); | |
| border: 0.5px solid var(--accent); | |
| box-shadow: 0 0 0 0.5px var(--accent); | |
| } | |
| .lauto-check { | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 11px; | |
| font-weight: 800; | |
| flex: none; | |
| margin-top: 1px; | |
| } | |
| .lauto-verb { | |
| font-size: 13px; | |
| font-weight: 600; | |
| } | |
| .lauto-done { | |
| font-size: 11px; | |
| color: var(--ink-soft); | |
| font-family: var(--mono); | |
| margin-top: 3px; | |
| } | |
| /* ============================================================ | |
| Settings panel (Tweaks reborn as product UI) | |
| ============================================================ */ | |
| .settings { | |
| position: fixed; | |
| z-index: 75; | |
| width: 340px; | |
| display: flex; | |
| flex-direction: column; | |
| max-height: calc(100vh - 120px); | |
| } | |
| .set-body { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .set-body .sect-label { | |
| margin-top: 8px; | |
| } | |
| .set-body .sect-label:first-child { | |
| margin-top: 0; | |
| } | |
| .set-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .set-label { | |
| font-size: 12px; | |
| color: var(--ink-soft); | |
| width: 88px; | |
| flex: none; | |
| } | |
| .set-ctl { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .set-pills { | |
| display: flex; | |
| gap: 5px; | |
| flex-wrap: wrap; | |
| } | |
| .set-pills .mode-pill { | |
| flex: 1 1 auto; | |
| appearance: none; | |
| font-family: var(--ui); | |
| } | |
| .set-swatches { | |
| display: flex; | |
| gap: 7px; | |
| } | |
| .set-swatch { | |
| appearance: none; | |
| width: 22px; | |
| height: 22px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| border: 2px solid transparent; | |
| transition: | |
| transform 0.13s, | |
| border-color 0.13s; | |
| } | |
| .set-swatch:hover { | |
| transform: scale(1.12); | |
| } | |
| .set-swatch.on { | |
| border-color: var(--ink); | |
| transform: scale(1.12); | |
| } | |
| .set-slider { | |
| display: flex; | |
| align-items: center; | |
| gap: 9px; | |
| } | |
| .set-slider input[type="range"] { | |
| flex: 1; | |
| accent-color: var(--accent); | |
| } | |
| .set-val { | |
| font-size: 11px; | |
| font-family: var(--mono); | |
| color: var(--ink-faint); | |
| width: 24px; | |
| text-align: right; | |
| } | |
| .set-actions { | |
| display: flex; | |
| gap: 8px; | |
| margin-top: 6px; | |
| } | |
| /* menubar puck item is a real <button> now */ | |
| .mb-puck { | |
| appearance: none; | |
| border: 0; | |
| background: transparent; | |
| color: inherit; | |
| font: inherit; | |
| } | |
| /* ============================================================ | |
| Overlay mode — transparent shell over the real desktop | |
| ============================================================ */ | |
| html.overlay, | |
| html.overlay body { | |
| background: transparent ; | |
| } | |
| html.overlay .puck-hit { | |
| cursor: pointer; | |
| } | |
| /* during a real-screen capture, blank Puck so his own sprite/bubbles don't land | |
| in the screenshot he's about to read (the overlay window is otherwise clear) */ | |
| html.capturing #root { | |
| opacity: 0; | |
| transition: none; | |
| } | |
| /* Glassier comment surfaces over the real desktop — let it show through, but keep | |
| the blur so text stays legible (fully transparent would kill readability). */ | |
| html.overlay .bubble, | |
| html.overlay .toast { | |
| background: color-mix(in srgb, var(--panel-2) 60%, transparent); | |
| backdrop-filter: blur(32px) saturate(160%); | |
| -webkit-backdrop-filter: blur(32px) saturate(160%); | |
| } | |
| /* ============================================================ | |
| Attention: alert ring when something's waiting + hover-grow. | |
| On a busy desktop a quiet bob is missable; the ring isn't. | |
| ============================================================ */ | |
| .puck-alert-ring { | |
| position: absolute; | |
| left: 50%; | |
| top: 50%; | |
| width: 38px; | |
| height: 38px; | |
| margin: -19px 0 0 -19px; | |
| border-radius: 50%; | |
| border: 2px solid var(--accent); | |
| opacity: 0; | |
| pointer-events: none; | |
| } | |
| .puck.alert .puck-alert-ring { | |
| animation: alertring 1.4s ease-out infinite; | |
| } | |
| @keyframes alertring { | |
| 0% { | |
| opacity: 0.8; | |
| transform: scale(0.7); | |
| } | |
| 70% { | |
| opacity: 0; | |
| transform: scale(2.1); | |
| } | |
| 100% { | |
| opacity: 0; | |
| transform: scale(2.1); | |
| } | |
| } | |
| /* alert also quickens the bob and warms the glow so the whole sprite reads "!" */ | |
| .puck.alert .puck-bob { | |
| animation-duration: 1.5s; | |
| } | |
| .puck.alert .puck-glow { | |
| animation-duration: 1.4s; | |
| } | |
| /* hover-grow on the pokeable creature — tactile "I'm clickable" feedback */ | |
| .puck-bob { | |
| transition: transform 0.18s cubic-bezier(0.3, 0.8, 0.3, 1.4); | |
| } | |
| .puck-hit:hover ~ .puck-bob, | |
| .puck-bob:has(.puck-hit:hover) { | |
| transform: scale(1.18); | |
| } | |
| /* settings inline note (e.g. vision cost explainer) */ | |
| .set-note { | |
| font-size: 11px; | |
| line-height: 1.4; | |
| color: var(--ink-faint); | |
| font-style: italic; | |
| padding: 2px 0 2px; | |
| } | |
| /* voice picker — native select + audition button */ | |
| .set-voicepick { | |
| display: flex; | |
| gap: 6px; | |
| align-items: center; | |
| } | |
| .set-select { | |
| flex: 1; | |
| min-width: 0; | |
| font: inherit; | |
| font-size: 12px; | |
| color: var(--ink); | |
| background: var(--surface-2, rgba(0, 0, 0, 0.08)); | |
| border: 1px solid var(--line, rgba(0, 0, 0, 0.12)); | |
| border-radius: 8px; | |
| padding: 5px 7px; | |
| } | |
| /* molt gauge on the Night Bloom wake screen — real trace accumulation */ | |
| .bloom-molt { | |
| margin: 14px auto 4px; | |
| max-width: 320px; | |
| text-align: left; | |
| } | |
| .bm-row { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 12px; | |
| letter-spacing: 0.3px; | |
| color: rgba(255, 247, 224, 0.82); | |
| margin-bottom: 5px; | |
| } | |
| .bm-bar { | |
| height: 6px; | |
| border-radius: 99px; | |
| background: rgba(255, 255, 255, 0.12); | |
| overflow: hidden; | |
| } | |
| .bm-bar i { | |
| display: block; | |
| height: 100%; | |
| border-radius: 99px; | |
| background: linear-gradient(90deg, var(--accent), #fff7e0); | |
| transition: width 0.8s ease; | |
| } | |
| .bm-note { | |
| margin-top: 7px; | |
| font-size: 11px; | |
| line-height: 1.5; | |
| color: rgba(255, 247, 224, 0.6); | |
| font-style: italic; | |
| } | |
| /* ============================================================ | |
| Reactions — one-shot personality gestures. The react-* class | |
| lands on .puck; .puck-bob is keyed in React so the animation | |
| restarts even when the same reaction fires twice in a row. | |
| Each keyframe starts and ends at neutral so the resting bob | |
| resumes seamlessly when the class is removed. Durations mirror | |
| ReactionKind MS in engine/reactions.ts. | |
| ============================================================ */ | |
| .puck[class*="react-"] .puck-bob { | |
| animation-iteration-count: 1; | |
| } | |
| .puck.react-celebrate .puck-bob { | |
| animation: react-celebrate 1.1s cubic-bezier(0.3, 0.7, 0.3, 1.3); | |
| } | |
| @keyframes react-celebrate { | |
| 0% { | |
| transform: translateY(0) scale(1) rotate(0); | |
| } | |
| 20% { | |
| transform: translateY(-15px) scale(1.18) rotate(-8deg); | |
| } | |
| 45% { | |
| transform: translateY(2px) scale(0.96) rotate(6deg); | |
| } | |
| 65% { | |
| transform: translateY(-9px) scale(1.08) rotate(-4deg); | |
| } | |
| 100% { | |
| transform: translateY(0) scale(1) rotate(0); | |
| } | |
| } | |
| .puck.react-nani .puck-bob { | |
| animation: react-nani 0.9s cubic-bezier(0.2, 1.5, 0.3, 1); | |
| } | |
| @keyframes react-nani { | |
| 0% { | |
| transform: scale(1); | |
| } | |
| 14% { | |
| transform: scale(1.03) translateX(-2px); | |
| } /* the freeze beat */ | |
| 22% { | |
| transform: scale(1.46) translateY(-6px); | |
| } /* SNAP zoom */ | |
| 34% { | |
| transform: scale(1.4) translateX(4px); | |
| } | |
| 46% { | |
| transform: scale(1.43) translateX(-4px); | |
| } | |
| 60% { | |
| transform: scale(1.41); | |
| } | |
| 100% { | |
| transform: scale(1); | |
| } | |
| } | |
| .puck.react-perk .puck-bob { | |
| animation: react-perk 0.75s ease; | |
| } | |
| @keyframes react-perk { | |
| 0% { | |
| transform: scale(1) translateY(0); | |
| } | |
| 40% { | |
| transform: scale(1.16) translateY(-7px); | |
| } | |
| 100% { | |
| transform: scale(1) translateY(0); | |
| } | |
| } | |
| .puck.react-shrug .puck-bob { | |
| animation: react-shrug 1s ease-in-out; | |
| } | |
| @keyframes react-shrug { | |
| 0%, | |
| 100% { | |
| transform: translateY(0) rotate(0) scale(1); | |
| } | |
| 25% { | |
| transform: translateY(3px) rotate(-7deg) scale(0.97); | |
| } | |
| 60% { | |
| transform: translateY(3px) rotate(7deg) scale(0.97); | |
| } | |
| } | |
| .puck.react-sulk .puck-bob { | |
| animation: react-sulk 1.05s ease; | |
| } | |
| @keyframes react-sulk { | |
| 0%, | |
| 100% { | |
| transform: translateY(0) scale(1); | |
| opacity: 1; | |
| } | |
| 35% { | |
| transform: translateY(9px) scale(0.85); | |
| opacity: 0.65; | |
| } | |
| } | |
| .puck.react-dance .puck-bob { | |
| animation: react-dance 1.5s ease-in-out; | |
| } | |
| @keyframes react-dance { | |
| 0%, | |
| 100% { | |
| transform: translateY(0) rotate(0); | |
| } | |
| 15% { | |
| transform: translateY(-6px) rotate(-14deg); | |
| } | |
| 35% { | |
| transform: translateY(0) rotate(12deg); | |
| } | |
| 55% { | |
| transform: translateY(-6px) rotate(-12deg); | |
| } | |
| 75% { | |
| transform: translateY(0) rotate(10deg); | |
| } | |
| } | |
| .puck.react-summon .puck-bob { | |
| animation: react-summon 1.6s cubic-bezier(0.34, 1.56, 0.5, 1); | |
| } | |
| @keyframes react-summon { | |
| 0% { | |
| transform: scale(1) translateY(0); | |
| } | |
| 18% { | |
| transform: scale(1.42) translateY(-12px) rotate(-6deg); | |
| } /* big size-up */ | |
| 34% { | |
| transform: scale(1.34) translateY(2px) rotate(5deg); | |
| } | |
| 50% { | |
| transform: scale(1.42) translateY(-9px) rotate(-5deg); | |
| } /* insistent second hop */ | |
| 66% { | |
| transform: scale(1.34) translateY(2px) rotate(4deg); | |
| } | |
| 82% { | |
| transform: scale(1.38) translateY(-5px) rotate(0deg); | |
| } | |
| 100% { | |
| transform: scale(1) translateY(0) rotate(0); | |
| } | |
| } | |
| .puck.react-pop .puck-bob { | |
| animation: react-pop 0.48s cubic-bezier(0.3, 0.8, 0.3, 1.4); | |
| } | |
| @keyframes react-pop { | |
| 0%, | |
| 100% { | |
| transform: scale(1); | |
| } | |
| 45% { | |
| transform: scale(1.16); | |
| } | |
| } | |
| /* laugh — giddy little bounces with a rocking wobble (found something funny) */ | |
| .puck.react-laugh .puck-bob { | |
| animation: react-laugh 1.2s ease-in-out; | |
| } | |
| @keyframes react-laugh { | |
| 0%, | |
| 100% { | |
| transform: translateY(0) rotate(0) scale(1); | |
| } | |
| 15% { | |
| transform: translateY(-8px) rotate(-7deg) scale(1.06); | |
| } | |
| 30% { | |
| transform: translateY(1px) rotate(6deg) scale(0.98); | |
| } | |
| 45% { | |
| transform: translateY(-7px) rotate(-6deg) scale(1.05); | |
| } | |
| 60% { | |
| transform: translateY(1px) rotate(5deg) scale(0.98); | |
| } | |
| 75% { | |
| transform: translateY(-5px) rotate(-4deg) scale(1.03); | |
| } | |
| } | |
| /* sad — a slow droop, shrinking and dimming (something poignant or lonely) */ | |
| .puck.react-sad .puck-bob { | |
| animation: react-sad 1.3s ease; | |
| } | |
| @keyframes react-sad { | |
| 0%, | |
| 100% { | |
| transform: translateY(0) scale(1); | |
| filter: none; | |
| } | |
| 35%, | |
| 70% { | |
| transform: translateY(7px) scale(0.9) rotate(-3deg); | |
| filter: brightness(0.68) saturate(0.6); | |
| } | |
| } | |
| /* fret — a startled recoil then a nervous side-to-side tremble (the human's upset) */ | |
| .puck.react-fret .puck-bob { | |
| animation: react-fret 1.1s ease; | |
| } | |
| @keyframes react-fret { | |
| 0%, | |
| 100% { | |
| transform: translate(0, 0) scale(1); | |
| } | |
| 10% { | |
| transform: translate(0, -6px) scale(1.08); | |
| } | |
| 25% { | |
| transform: translateX(-4px) scale(1.04); | |
| } | |
| 37% { | |
| transform: translateX(4px) scale(1.04); | |
| } | |
| 49% { | |
| transform: translateX(-3px) scale(1.02); | |
| } | |
| 61% { | |
| transform: translateX(3px) scale(1.02); | |
| } | |
| 73% { | |
| transform: translateX(-2px); | |
| } | |
| 85% { | |
| transform: translateX(2px); | |
| } | |
| } | |
| /* Emotion COLOR — the aura flushes a feeling-hue for the gesture's duration, then | |
| reverts to the slow mood tint (--puck-glow is overridden on .puck, which beats the | |
| mood-* ancestor and cascades to .puck-glow). Layered on top of the body's mood color | |
| so curiosity stays "his" color and only the strong feelings recolor him. */ | |
| .puck.react-nani { | |
| --puck-glow: rgba(244, 244, 255, 0.62); /* white surprise flash */ | |
| } | |
| .puck.react-laugh { | |
| --puck-glow: rgba(246, 212, 120, 0.5); /* warm giggle gold */ | |
| } | |
| .puck.react-celebrate, | |
| .puck.react-dance { | |
| --puck-glow: rgba(255, 206, 105, 0.62); /* bright delight */ | |
| } | |
| .puck.react-celebrate .puck-glow, | |
| .puck.react-dance .puck-glow { | |
| animation-duration: 0.6s; /* giddy fast pulse */ | |
| } | |
| .puck.react-fret { | |
| --puck-glow: rgba(240, 92, 74, 0.58); /* alarm red */ | |
| } | |
| .puck.react-fret .puck-glow { | |
| animation-duration: 0.45s; /* anxious flicker */ | |
| } | |
| .puck.react-sad { | |
| --puck-glow: rgba(108, 148, 230, 0.42); /* cool, lonely blue */ | |
| } | |
| .puck.react-sad .puck-glow { | |
| animation-duration: 5s; /* slow, heavy */ | |
| } | |
| /* muted — watching but silent: calm the glow, drop a small badge */ | |
| .puck.muted .puck-glow { | |
| opacity: 0.35; | |
| animation-duration: 6s; | |
| } | |
| .puck-mute { | |
| position: absolute; | |
| right: -2px; | |
| top: -2px; | |
| font-size: 13px; | |
| line-height: 1; | |
| filter: grayscale(0.3); | |
| pointer-events: none; | |
| z-index: 4; | |
| } | |
| /* camo — after sitting still, Puck cloaks into an active-camo patch (the per-rule | |
| comments below cover the visual; the gist: what's behind reads through sharp, with a | |
| shimmer + rim so he's a cloaked shape, not a hole). Fades in over ~1.2s; dropping the | |
| class is an instant "boo!" reveal. Trigger lives in SimApp's idle loop. */ | |
| .puck.camo .puck-body { | |
| /* Active camo, not transparency: the fill goes clear so what's behind reads through | |
| SHARP (overlay: the real desktop through the transparent window; sim: the page). | |
| NO blur — blur is what made it unreadable. */ | |
| background: transparent ; | |
| /* the camo TELL — a non-blurring shimmer (brightness/contrast/hue keep text legible, | |
| unlike blur) so his shape registers as a cloaked patch, not a hole. The backdrop | |
| shimmer only renders in the sim (the overlay's transparent window has nothing to | |
| sample); the refractive rim below carries the tell in both habitats. */ | |
| backdrop-filter: brightness(1.08) contrast(1.05) hue-rotate(10deg); | |
| -webkit-backdrop-filter: brightness(1.08) contrast(1.05) hue-rotate(10deg); | |
| box-shadow: | |
| inset 0 0 0 1px rgba(255, 255, 255, 0.13), | |
| 0 0 8px rgba(170, 215, 255, 0.16); | |
| transition: | |
| background 1.2s ease, | |
| backdrop-filter 1.2s ease, | |
| box-shadow 1.2s ease; | |
| } | |
| .puck.camo .puck-wing, | |
| .puck.camo .puck-cheek, | |
| .puck.camo .puck-trail, | |
| .puck.camo .puck-glow { | |
| opacity: 0.07; | |
| transition: opacity 1.2s ease; | |
| } | |
| .puck.camo .puck-eye { | |
| opacity: 0.34; /* a faint watching glimmer through the cloak */ | |
| transition: opacity 1.2s ease; | |
| } | |
| /* the shout — a quick chat-flash that floats up and fades over the sprite */ | |
| .puck-shout { | |
| position: absolute; | |
| left: 50%; | |
| bottom: 100%; | |
| white-space: nowrap; | |
| font-weight: 800; | |
| font-size: 14px; | |
| letter-spacing: 0.2px; | |
| color: var(--accent-ink, #fff7e8); | |
| background: var(--accent); | |
| padding: 2px 9px; | |
| border-radius: 11px; | |
| box-shadow: 0 3px 10px rgba(0, 0, 0, 0.25); | |
| pointer-events: none; | |
| z-index: 3; | |
| animation: shout-pop 1s ease forwards; | |
| } | |
| @keyframes shout-pop { | |
| 0% { | |
| opacity: 0; | |
| transform: translate(-50%, 6px) scale(0.6); | |
| } | |
| 18% { | |
| opacity: 1; | |
| transform: translate(-50%, -6px) scale(1.1); | |
| } | |
| 35% { | |
| transform: translate(-50%, -8px) scale(1); | |
| } | |
| 80% { | |
| opacity: 1; | |
| transform: translate(-50%, -12px) scale(1); | |
| } | |
| 100% { | |
| opacity: 0; | |
| transform: translate(-50%, -22px) scale(0.95); | |
| } | |
| } | |