/* * Composer, toolbar, emoji popover and attachment row (spec "Composer", * ADR 0001). Ported from the mockup's .cmp, .bar, .emo and .att rules. * Tokens only. The Post button is the flip reveal from buttons.css. */ .composer { --composer-soft: color-mix(in srgb, var(--ink), transparent 93%); position: relative; border-radius: var(--r-card); background: var(--tile-2); box-shadow: inset 0 0 0 1px var(--line); padding: 10px 10px 8px 12px; display: flex; flex-direction: column; transition: box-shadow .3s, background-color .3s; } .composer.composer-open { background: var(--tile); box-shadow: inset 0 0 0 1px var(--line-2), var(--shadow-float); } .composer-top { display: flex; gap: 12px; align-items: flex-start; } .composer-top .hex-avatar { flex: none; } .composer .composer-label { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } .composer textarea { flex: 1; min-width: 0; margin: 0; border: 0; outline: 0; resize: none; background: transparent; font: inherit; font-size: 15px; line-height: 1.5; color: var(--ink); padding: 12px 2px; height: 50px; transition: height .3s var(--ease); } .composer.composer-open textarea { height: 92px; } .composer textarea::placeholder { color: var(--ink-3); } .composer textarea:disabled { color: var(--ink-2); } /* Toolbar: photo, video, emoji | bulleted list ... Ctrl + Enter, Post. */ .composer-bar { display: flex; align-items: center; gap: 2px; margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--line); } .composer-tool { appearance: none; margin: 0; padding: 0; border: 0; background: transparent; width: 40px; height: 40px; border-radius: var(--r-ctl); display: inline-grid; place-items: center; color: var(--ink-2); cursor: pointer; flex: none; transition: background-color .2s, color .2s, transform .15s; } .composer-tool svg { width: 20px; height: 20px; } .composer-tool:hover:not(:disabled), .composer-tool.composer-tool-on { background: var(--composer-soft); color: var(--ink); } .composer-tool:active:not(:disabled) { transform: scale(.9); } .composer-tool:disabled { cursor: not-allowed; color: var(--ink-3); background: transparent; } .composer-file { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); border: 0; } .composer-sep { width: 1px; height: 20px; background: var(--line-2); margin: 0 6px; flex: none; } .composer-spacer { flex: 1; } .composer-kbd { font-size: 11.5px; color: var(--ink-3); margin-right: 10px; white-space: nowrap; } .composer-kbd b { font-weight: 700; color: var(--ink-2); padding: 1px 6px; border-radius: 6px; background: var(--tile-2); box-shadow: inset 0 0 0 1px var(--line); } /* Emoji: a frosted popover with 32 frequent emoji. */ .composer-emoji-wrap { position: relative; } .composer-emoji { position: absolute; z-index: 30; top: calc(100% + 8px); left: -8px; width: 320px; padding: 10px; background: var(--glass); -webkit-backdrop-filter: blur(20px) saturate(1.7); backdrop-filter: blur(20px) saturate(1.7); border: 1px solid var(--line); border-radius: var(--r-card); box-shadow: var(--shadow-pop); animation: composer-pop .24s cubic-bezier(.2,.9,.3,1.25) both; } .composer-eyebrow { display: block; padding: 2px 6px 8px; font-size: 11px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-3); } .composer-emoji-grid { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 2px; } .composer-emoji-grid button { appearance: none; margin: 0; padding: 0; border: 0; background: transparent; color: var(--ink); height: 36px; border-radius: 10px; font-family: inherit; font-size: 20px; line-height: 1; cursor: pointer; transition: transform .15s cubic-bezier(.2,.9,.3,1.4), background-color .15s; } .composer-emoji-grid button:hover { background: var(--composer-soft); transform: scale(1.2); } /* Attachment row: thumbnail, name, type and size, progress, remove. */ .composer-att { display: flex; align-items: center; gap: 12px; margin: 6px 0 2px; padding: 8px; border-radius: 14px; background: var(--tile-2); box-shadow: inset 0 0 0 1px var(--line); animation: composer-rise .35s var(--ease) both; } .composer-att.composer-att-indent { margin-left: 58px; } .composer-thumb { position: relative; width: 56px; height: 56px; border-radius: 10px; flex: none; overflow: hidden; background: var(--tile-3); } .composer-thumb img, .composer-thumb video { display: block; width: 100%; height: 100%; object-fit: cover; } .composer-thumb svg { position: absolute; inset: 0; margin: auto; width: 20px; height: 20px; color: var(--on-accent); filter: drop-shadow(0 1px 3px var(--accent-deep)); } .composer-att-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; } .composer-att-text strong { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .composer-att-text span { font-size: 12px; color: var(--ink-3); } .composer-prog { height: 3px; border-radius: 3px; background: var(--tile-3); overflow: hidden; } .composer-prog i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: composer-load 1.6s var(--ease) both; } /* While posting the upload has no byte count, so the bar sweeps. */ .composer-prog.composer-prog-busy i { width: 40%; animation: composer-sweep 1.1s ease-in-out infinite; } .composer .error { margin: 8px 0 0; } /* The flip Post button keeps its own size inside the toolbar. */ .composer-bar .composer-post { flex: none; } @keyframes composer-pop { from { opacity: 0; transform: translateY(-6px) scale(.96); } to { opacity: 1; transform: none; } } @keyframes composer-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } } @keyframes composer-load { from { transform: scaleX(0); } to { transform: scaleX(1); } } @keyframes composer-sweep { from { transform: translateX(-100%); } to { transform: translateX(250%); } } @media (prefers-reduced-motion: reduce) { .composer, .composer textarea, .composer-tool, .composer-emoji-grid button { transition: none !important; } .composer-emoji, .composer-att, .composer-prog i { animation: none !important; } } /* Publish failure, above the toolbar. */ .composer-error { margin: 0 0 4px; padding: 10px 12px; border: 1px solid var(--accent); border-radius: 8px; color: var(--danger); background: var(--accent-soft); font-size: 14px; }