diff options
Diffstat (limited to 'src/style.css')
| -rw-r--r-- | src/style.css | 159 |
1 files changed, 146 insertions, 13 deletions
diff --git a/src/style.css b/src/style.css index 4a9b191..fcef5a0 100644 --- a/src/style.css +++ b/src/style.css @@ -30,6 +30,12 @@ --accent-fg: #ffffff; /* text on accent */ --accent-ink: #000000; --accent-soft: #ececef; + /* a button's fill (primary, chosen chip or tab): the accent in light; in + dark a lifted grey, not a white slab (Adam, 2026-10-18: "Probably + shouldn't have white buttons in dark mode") */ + --fill: var(--accent); + --fill-hover: var(--accent-hover); + --fill-fg: var(--accent-fg); --green: #14935a; --green-soft: #e7f6ee; --green-line: #c4e7d4; @@ -65,6 +71,9 @@ --accent-fg: #0f1216; /* text on accent */ --accent-ink: #e7e9ee; --accent-soft: #262b33; + --fill: #353b45; + --fill-hover: #404753; + --fill-fg: #f3f5f8; --green: #2dbd80; --green-soft: #14271d; --green-line: #235340; @@ -92,6 +101,12 @@ html { one last time" after a switch. Stable gutter = no reflow when content grows. */ scrollbar-gutter: stable; + /* Nothing ever scrolls the page sideways. Anything wider than the screen + (a strip of chips, a stray wide row) would otherwise let an iPhone + pinch the page out and pan to it. (On the root element, not body: a + body that clips becomes the scroll container a sticky rail measures + against, and the rail would stop sticking.) */ + overflow-x: hidden; } html, body { @@ -224,8 +239,8 @@ button, .btn { button:hover { background: var(--surface2); } button:active { transform: translateY(1px); } button:disabled { opacity: .5; cursor: not-allowed; } -.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); } -.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); } +.btn-primary { background: var(--fill); border-color: var(--fill); color: var(--fill-fg); } +.btn-primary:hover { background: var(--fill-hover); border-color: var(--fill-hover); } .btn-ghost { background: transparent; } .btn-sm { padding: 7px 11px; font-size: 13px; border-radius: 9px; } .btn-sm.on { border-color: var(--accent); color: var(--accent); } @@ -285,6 +300,12 @@ textarea.send-dest::placeholder { font-family: var(--sans); } .seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 10px; overflow: hidden; } .seg button { border: 0; border-radius: 0; padding: 9px 14px; background: var(--paper); } .seg button.active { background: var(--accent-soft); color: var(--accent-ink); } +/* The profile's Posts / Replies tabs sit right on white cards: a soft-grey + active tab beside a white one read as the WHITE one being selected (its + colour matched the posts under it). So these take the feed chips' look: + the chosen tab solid accent, the other one quiet (Adam, 2026-10-16). */ +.prof-tabs button { background: var(--surface2); color: var(--muted); } +.prof-tabs button.active { background: var(--fill); color: var(--fill-fg); } /* ---- address / qr ---- */ .qr { width: 220px; height: 220px; display: block; border-radius: 12px; border: 1px solid var(--line); } @@ -714,7 +735,7 @@ html:has(#app .chat-card), body:has(#app .chat-card) { overflow: hidden; } .pos-big { font-size: 34px; font-weight: 700; line-height: 1.1; letter-spacing: -.5px; } .pos-tips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; width: 100%; } .pos-tip { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 12px 6px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface2); color: var(--ink); cursor: pointer; } -.pos-tip.on { border-color: var(--accent); background: var(--accent); color: var(--accent-fg); } +.pos-tip.on { border-color: var(--fill); background: var(--fill); color: var(--fill-fg); } .pos-tip.on .muted { color: inherit; opacity: .8; } .pos-tip-label { font-size: 20px; font-weight: 600; } .pos-total { font-size: 22px; font-weight: 600; margin-top: 4px; } @@ -723,14 +744,12 @@ html:has(#app .chat-card), body:has(#app .chat-card) { overflow: hidden; } .pos-sale.faint { opacity: .55; } .pos-pad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; width: 100%; } .pos-key { padding: 14px 0; font-size: 22px; font-weight: 600; border: 1px solid var(--line); border-radius: 12px; background: var(--surface2); color: var(--ink); cursor: pointer; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; } -.pos-key:active { background: var(--accent); color: var(--accent-fg); } +.pos-key:active { background: var(--fill); color: var(--fill-fg); } .pos-key.del { font-weight: 400; } /* the feeds row: pills that scroll sideways, the one on screen filled */ .feed-chips { gap: 6px; flex-wrap: nowrap; overflow-x: auto; margin: 0 -14px; padding: 2px 14px; scrollbar-width: none; -webkit-overflow-scrolling: touch; } .feed-chips::-webkit-scrollbar { display: none; } /* with a mouse: a thin bar says the strip scrolls, and it drags (app.js) */ -/* grabbing the feed to scroll it (app.js) */ -.grab-scrolling, .grab-scrolling * { cursor: grabbing !important; user-select: none !important; } @media (hover: hover) and (pointer: fine) { .feed-chips { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; padding-bottom: 6px; cursor: grab; } .feed-chips::-webkit-scrollbar { display: block; height: 6px; } @@ -739,7 +758,7 @@ html:has(#app .chat-card), body:has(#app .chat-card) { overflow: hidden; } .feed-chips.dragging .feed-chip { pointer-events: none; } } .feed-chip { flex: 0 0 auto; border: 1px solid var(--line); background: var(--surface2); color: var(--muted); border-radius: 999px; padding: 5px 12px; font-size: 14px; line-height: 1.2; cursor: pointer; white-space: nowrap; max-width: 180px; overflow: hidden; text-overflow: ellipsis; } -.feed-chip.on { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); } +.feed-chip.on { background: var(--fill); color: var(--fill-fg); border-color: var(--fill); } .feed-chip.add { font-weight: 600; padding: 5px 11px; } .note-act { background: none; border: 0; padding: 4px 6px; margin: 0; line-height: 1; @@ -867,6 +886,51 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; } .addr-cover { width: 100%; aspect-ratio: 2 / 1; object-fit: cover; display: block; background: var(--line); } .addr-title { font-weight: 650; font-size: 1.05em; line-height: 1.3; } .addr-summary { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; } +/* Live streams (NIP-53): the row of what's on above a feed, a profile's + "on now", a post's card, and the stream's own page (player over chat). */ +/* a face whose person is streaming now: a red ring, and LIVE under the bigger ones */ +.chat-avatar.live-ring { box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px #e0245e; position: relative; overflow: visible; } +.chat-avatar.mini.live-ring { box-shadow: 0 0 0 1px var(--paper), 0 0 0 2.5px #e0245e; } +.chat-avatar.live-ring:not(.mini)::after { content: 'LIVE'; position: absolute; left: 50%; bottom: -7px; transform: translateX(-50%); + padding: 0 4px; border-radius: 3px; font-size: 9px; font-weight: 700; line-height: 13px; letter-spacing: .04em; + color: #fff; background: #e0245e; box-shadow: 0 0 0 2px var(--paper); text-transform: none; } +.live-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 14px 10px; padding: 2px 0 4px; } +.live-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #e0245e; margin-right: 5px; vertical-align: 1px; } +.live-tile { display: flex; flex-direction: column; gap: 5px; padding: 0; text-align: left; + background: none; border: 0; color: inherit; cursor: pointer; min-width: 0; } +.live-cover { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden; + background: var(--line) center / cover no-repeat; } +.live-badge { display: inline-block; padding: 1px 6px; border-radius: 4px; font-size: 11px; font-weight: 700; + letter-spacing: .04em; color: #fff; background: #555; line-height: 1.5; flex-shrink: 0; } +.live-badge.live { background: #e0245e; } +.live-cover .live-badge { position: absolute; top: 6px; left: 6px; } +.live-viewers { position: absolute; bottom: 6px; left: 6px; padding: 1px 6px; border-radius: 4px; font-size: 11px; + color: #fff; background: rgba(0, 0, 0, .6); } +.live-tile-title { font-weight: 600; font-size: 14px; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; + -webkit-box-orient: vertical; overflow: hidden; } +.live-tile-host { align-items: center; min-width: 0; } +.live-tile-host .small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.live-banner { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid #e0245e; + border-radius: 10px; background: none; color: inherit; cursor: pointer; text-align: left; min-width: 0; } +.live-banner-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; } +.live-card { flex-direction: row; align-items: center; gap: 10px; } +.live-card .live-cover { flex: 0 0 120px; width: 120px; } +.live-title { margin: 0; min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.live-player { width: 100%; aspect-ratio: 16 / 9; background: #000; border-radius: 10px; overflow: hidden; } +.live-frame { width: 100%; height: 100%; } +.live-video { width: 100%; height: 100%; display: block; background: #000; } +.live-still { border-radius: 0; height: 100%; display: flex; align-items: center; justify-content: center; } +.live-say { padding: 6px 12px; border-radius: 8px; color: #fff; background: rgba(0, 0, 0, .65); font-size: 14px; text-align: center; } +.live-chat { display: flex; flex-direction: column; gap: 8px; max-height: 46vh; min-height: 120px; overflow-y: auto; overscroll-behavior: contain; } +.live-line { display: flex; gap: 8px; align-items: flex-start; min-width: 0; } +.live-line-body { min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; line-height: 1.35; } +.live-zap .live-line-body b { color: var(--accent); } +.live-input { min-width: 0; } +.bc-preview.mirror { transform: scaleX(-1); } +.bc-bar .bc-clock { font-variant-numeric: tabular-nums; font-weight: 650; } +.go-live-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: #e0245e; box-shadow: 0 0 0 3px rgba(224, 36, 94, .25); } +.go-live-btn { display: inline-flex; align-items: center; gap: 8px; } +.go-live-title { width: 100%; } .article-title { font-size: 1.35em; font-weight: 700; line-height: 1.25; margin-bottom: 6px; white-space: normal; } .article-h1, .article-h2, .article-h3 { font-weight: 650; line-height: 1.3; margin: 10px 0 2px; white-space: normal; } .article-h1 { font-size: 1.2em; } .article-h2 { font-size: 1.1em; } .article-h3 { font-size: 1em; } @@ -942,7 +1006,7 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; } position: fixed; bottom: calc(env(safe-area-inset-bottom, 0px) + 18px); left: 50%; transform: translateX(-50%); z-index: 30; width: auto; padding: 12px 24px; border-radius: 999px; - background: var(--accent); color: var(--accent-fg); border: none; + background: var(--fill); color: var(--fill-fg); border: none; font-size: 16px; font-weight: 650; cursor: pointer; touch-action: none; user-select: none; -webkit-user-select: none; /* it swipes away */ box-shadow: 0 3px 12px rgba(0, 0, 0, .28); @@ -951,7 +1015,7 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; } /* the generic button hover (a light surface) and press (a 1px drop, which REPLACED the centring transform and threw the pill half its width to the right, out from under the pointer, so the tap never landed) stay off it */ -.feed-new-pill:hover { background: var(--accent-hover); color: var(--accent-fg); } +.feed-new-pill:hover { background: var(--fill-hover); color: var(--fill-fg); } .feed-new-pill:active { transform: translate(-50%, 1px); } /* the count bumps each time it changes: a fresh node per value replays it */ .feed-new-pill .n { display: inline-block; min-width: 1.1em; text-align: center; animation: pill-bump .32s cubic-bezier(.2,.9,.3,1.4); } @@ -1177,7 +1241,7 @@ html.no-scroll { overflow: hidden; scrollbar-gutter: auto; } .hat-demo { position: relative; display: inline-flex; width: 34px; height: 34px; flex-shrink: 0; margin-top: 12px; } .hat-demo-head { width: 100%; height: 100%; border-radius: 50%; background: var(--accent-soft); } .hat-btn { white-space: nowrap; flex-shrink: 0; } -.hat-btn.wearing { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); } +.hat-btn.wearing { background: var(--fill); border-color: var(--fill); color: var(--fill-fg); } .hat-btn.confirm { border-color: var(--green); color: var(--green); } /* a small centered confirm popup over a dimmed page */ @@ -1455,7 +1519,13 @@ body::after { .social-count.on { color: var(--ink); border-bottom-color: var(--accent); } /* ---- feed media views: All / Images / Videos, the grid, the pager ---- */ -.media-modes { gap: 6px; } +/* The view strip scrolls sideways like the feed chips above it: five + chips no longer fit a phone (Conversations joined them), and a flex row + that neither wraps nor scrolls made the page 42px wider than the screen + — on an iPhone that is a page you can pinch out of and pan, a blank + strip down the right (Adam, 2026-10-16). */ +.media-modes { gap: 6px; flex-wrap: nowrap; overflow-x: auto; margin: 0 -14px; padding: 2px 14px; scrollbar-width: none; -webkit-overflow-scrolling: touch; } +.media-modes::-webkit-scrollbar { display: none; } .media-modes .feed-chip { padding: 4px 12px; font-size: 13px; } .article-list { gap: 10px; } .article-list > .quote-card { margin-top: 0; } @@ -1533,6 +1603,7 @@ body::after { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; cursor: pointer; overflow-wrap: anywhere; } .mp-caption.open { -webkit-line-clamp: unset; max-height: 40vh; overflow-y: auto; } +.mp-caption a { color: #fff; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; text-decoration-color: rgba(255, 255, 255, .5); } .mp-counts { display: flex; flex-direction: column; align-items: center; gap: 14px; flex: 0 0 auto; } .mp-counts button { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 0; margin: 0; border: 0; @@ -1555,6 +1626,17 @@ body::after { } .mp-sound { font-size: 15px; } .mp-sound .off { display: none; } +.mp-top-r { display: flex; align-items: center; gap: 8px; } +.mp-fit { height: 40px; padding: 0 14px; font-size: 14px; font-weight: 600; border-radius: 999px; border: 0; color: #fff; background: rgba(255, 255, 255, .16); } +.media-pager.quiet .mp-top .mp-fit { pointer-events: auto; } +/* a post out of the carousel: its clip not ready to play yet (mp-wait), or + the wrong way round for the screen (mp-off). Parked far above the screen + (fixed: out of the scroller's flow and its snap points, no height to + count) rather than display:none, so its box isn't a zero rect at the + origin that a "what's at the top left" lookup takes for the slide on + screen; its clip's poster still loads there. */ +.mp-group.mp-wait, .mp-group.mp-off { position: fixed; top: -400vh; left: 0; height: 0; visibility: hidden; pointer-events: none; } +/* over the Videos grid: which shapes */ /* A mouse's way through the pager: arrows, where there is a pointer to hover with (a phone swipes). Faint until the pointer is over the pager; the sideways pair only when the post has a picture that way. */ @@ -1642,9 +1724,12 @@ body::after { .media-pager { --mp-seek-lift: calc(env(safe-area-inset-bottom, 0px) + 32px); } .mp-seek { position: absolute; left: 16px; right: 16px; bottom: var(--mp-seek-lift); z-index: 3; height: 28px; - display: flex; align-items: flex-end; touch-action: none; cursor: pointer; visibility: hidden; + display: flex; align-items: flex-end; touch-action: none; cursor: pointer; visibility: hidden; opacity: 0; } -.mp-seek.ready { visibility: visible; } +.mp-seek.ready { visibility: visible; opacity: 1; transition: opacity .18s; } +/* only the clip on screen's bar, and not while the pager is in motion (a + finger, a glide, a flight): it goes at once and fades back in on landing */ +.mp-slide:not(.mp-cur) .mp-seek, .media-pager.moving .mp-seek { opacity: 0; transition: none; pointer-events: none; } .mp-seek-track { position: relative; width: 100%; height: 3px; border-radius: 3px; background: rgba(255, 255, 255, .28); transition: height .15s; } .mp-seek-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; border-radius: inherit; background: #fff; } .mp-seek-fill::after { @@ -1797,6 +1882,11 @@ body::after { .gif-tile video, .gif-tile img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; } .gif-note { display: flex; justify-content: center; padding: 32px 0; } .note-reposted { margin-bottom: 2px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +/* a reply shown with the post it answers above it (Conversations, a profile's Replies) */ +.note-context { margin-bottom: 6px; } +.note-context-label { margin-bottom: 2px; } +.note-context .quote-card { margin-top: 0; } +.note-context .quote-card .note-text { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden; } /* attach + GIF inside the composer's field, bottom right; the field keeps room under its text so a long post never runs beneath them */ .compose-box { position: relative; } @@ -1816,3 +1906,46 @@ body::after { /* Always visible, including when the media controls are tucked away. */ .mp-position { position: absolute; top: calc(env(safe-area-inset-top, 0px) + 16px); left: 50%; transform: translateX(-50%); padding: 5px 10px; border-radius: 20px; background: #0009; color: #fff; font-size: 13px; font-variant-numeric: tabular-nums; pointer-events: none; z-index: 5; } +/* the counter shows while the pager is in motion and fades out a moment + after it settles (the animation restarts each time `moving` comes off) */ +.media-pager .mp-position { animation: mp-position-out .4s 1.2s both; } +.media-pager.moving .mp-position { animation: none; opacity: 1; } +@keyframes mp-position-out { from { opacity: 1; } to { opacity: 0; } } +.media-pager.few .mp-position { visibility: hidden; } + +/* A call (calls.js): over every page, its picture filling it when there is + one; minimized, a bar along the top. */ +.call-overlay { position: fixed; inset: 0; z-index: 1000; background: #101318; color: #fff; + display: flex; flex-direction: column; align-items: center; justify-content: space-between; + padding: max(28px, env(safe-area-inset-top)) 16px max(28px, env(safe-area-inset-bottom)); } +.call-overlay .call-remote { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: #000; display: none; } +.call-overlay.has-video .call-remote { display: block; } +.call-overlay.has-video .call-who { position: relative; text-shadow: 0 1px 3px rgba(0, 0, 0, .7); } +.call-overlay.has-video .call-who .call-avatar { display: none; } +.call-who { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-top: 8vh; z-index: 1; } +.call-who .call-avatar { width: 112px; height: 112px; font-size: 32px; } +.call-name { font-size: 22px; font-weight: 650; } +.call-status { font-size: 15px; opacity: .8; font-variant-numeric: tabular-nums; } +.call-local { position: absolute; right: 16px; bottom: 120px; width: 28vw; max-width: 180px; aspect-ratio: 3 / 4; object-fit: cover; + border-radius: 12px; background: #000; box-shadow: 0 2px 12px rgba(0, 0, 0, .5); z-index: 2; } +.call-local.mirror { transform: scaleX(-1); } +.call-bar { display: flex; gap: 18px; z-index: 2; flex-wrap: wrap; justify-content: center; } +.call-btn { width: 60px; height: 60px; border-radius: 50%; border: 0; display: flex; align-items: center; justify-content: center; + background: rgba(255, 255, 255, .16); color: #fff; cursor: pointer; padding: 0; } +.call-btn:hover { background: rgba(255, 255, 255, .26); } +.call-btn.on { background: #fff; color: #101318; } +.call-btn.call-hang, .call-btn.call-decline { background: #e0245e; } +.call-btn.call-accept { background: #1fa45a; } +.call-overlay.call-min { inset: 0 0 auto 0; padding: 0; background: none; height: auto; justify-content: flex-start; pointer-events: none; } +.call-min-bar { pointer-events: auto; margin: max(8px, env(safe-area-inset-top)) auto 0; display: flex; align-items: center; gap: 10px; + padding: 8px 16px; border-radius: 999px; border: 0; background: #1fa45a; color: #fff; font-weight: 600; cursor: pointer; box-shadow: 0 2px 10px rgba(0, 0, 0, .3); } +.call-min-status { font-variant-numeric: tabular-nums; opacity: .9; } +.call-min .call-audio { display: none; } +/* a call in its conversation: a row of its own, centred, a tap calls back */ +.chat-row.call-log { justify-content: center; margin: 6px 0; flex-direction: column; align-items: center; gap: 3px; } +.call-log-why { text-align: center; max-width: 320px; } +.call-log-pill { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: 999px; + border: 1px solid var(--line); background: var(--surface2); color: inherit; font-size: 13px; cursor: pointer; } +.call-log-pill .chat-time { margin: 0; font-size: 11px; opacity: .7; } +.call-log-pill svg { width: 16px; height: 16px; } +.chat-row.call-log.missed .call-log-pill { color: var(--red); border-color: color-mix(in srgb, var(--red) 40%, var(--line)); } |
