Files
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

659 lines
14 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================
Open Design — Web Clipper popup
Brand-aligned with the Open Design product design system
(warm neutral surfaces, ember accent, near-black brand ink).
============================================================ */
:root {
color-scheme: light dark;
--bg: #faf9f7;
--panel: #fdfcfa;
--subtle: #f4f5f7;
--muted: #eef1f5;
--fill: rgba(0, 0, 0, 0.04);
--fill-hover: rgba(0, 0, 0, 0.06);
--border: #e1e5eb;
--border-soft: #edf0f4;
--text: #1a1916;
--text-strong: #0d0c0a;
--text-muted: #74716b;
--text-soft: #989590;
/* Brand ink — the Open Design mark. */
--brand-ink: #202020;
--on-brand: #ffffff;
/* Ember accent — Open Design primary action color. */
--accent: #c96442;
--accent-strong: #b45a3b;
--on-accent: #ffffff;
--green: #1f7a3a;
--green-bg: #e8f7ee;
--green-border: #c6ead2;
--red: #9c2a25;
--radius-sm: 6px;
--radius: 8px;
--radius-md: 10px;
--radius-lg: 12px;
--radius-pill: 999px;
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
--dur-quick: 120ms;
--dur-enter: 200ms;
--shadow-sm: 0 1px 2px rgba(28, 27, 26, 0.05), 0 1px 3px rgba(28, 27, 26, 0.04);
--shadow-md: 0 6px 24px rgba(28, 27, 26, 0.08), 0 2px 6px rgba(28, 27, 26, 0.04);
--sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Microsoft YaHei UI', 'Noto Sans', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1917;
--panel: #222120;
--subtle: #252321;
--muted: #2e2c29;
--fill: rgba(255, 255, 255, 0.06);
--fill-hover: rgba(255, 255, 255, 0.1);
--border: #333128;
--border-soft: #2a2825;
--text: #e8e4dc;
--text-strong: #f2ede4;
--text-muted: #9a9690;
--text-soft: #6e6b65;
--brand-ink: #f2ede4;
--on-brand: #1a1917;
--accent: #d97a56;
--accent-strong: #e8896a;
--green: #4caf72;
--green-bg: #0f2a18;
--green-border: #1a4028;
--red: #e06b65;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2);
--shadow-md: 0 6px 24px rgba(0, 0, 0, 0.4), 0 2px 6px rgba(0, 0, 0, 0.25);
}
}
* {
box-sizing: border-box;
}
body {
width: 340px;
margin: 0;
padding: 0;
font-family: var(--sans);
color: var(--text);
background: var(--bg);
overflow: hidden;
-webkit-font-smoothing: antialiased;
}
/* Flush content — no outer frame; Chrome rounds the popup window itself. */
.app {
background: transparent;
}
/* ---- Brand header ---- */
.brand {
display: flex;
align-items: center;
gap: 11px;
padding: 15px 16px 14px;
border-bottom: 1px solid var(--border-soft);
background:
radial-gradient(120% 140% at 0% 0%, var(--fill), transparent 60%),
var(--panel);
}
.brand-mark {
flex: none;
width: 34px;
height: 34px;
display: block;
filter: drop-shadow(0 2px 5px rgba(28, 27, 26, 0.18));
}
.brand-mark svg {
width: 100%;
height: 100%;
display: block;
}
.brand-name {
display: flex;
flex-direction: column;
gap: 1px;
line-height: 1.05;
margin-right: auto;
}
.brand-eyebrow {
font-size: 10px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-soft);
}
.brand-title {
font-size: 17px;
font-weight: 700;
letter-spacing: -0.01em;
color: var(--text-strong);
}
.status {
flex: none;
display: inline-flex;
align-items: center;
gap: 6px;
height: 24px;
padding: 0 10px 0 9px;
border-radius: var(--radius-pill);
border: 1px solid var(--border);
background: var(--subtle);
font-size: 11px;
font-weight: 600;
color: var(--text-muted);
white-space: nowrap;
}
.status::before {
content: '';
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--text-soft);
box-shadow: 0 0 0 0 transparent;
}
.status[data-paired='true'] {
color: var(--green);
border-color: var(--green-border);
background: var(--green-bg);
}
.status[data-paired='true']::before {
background: var(--green);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 22%, transparent);
}
/* Info icon + hover/focus tooltip — keeps the chrome minimal while the long
"what gets captured" explanation stays one hover away. */
.info {
flex: none;
position: relative;
display: grid;
place-items: center;
width: 26px;
height: 26px;
border-radius: var(--radius-pill);
color: var(--text-soft);
cursor: help;
transition: color var(--dur-quick) var(--ease-out), background var(--dur-quick) var(--ease-out);
}
.info svg {
width: 17px;
height: 17px;
display: block;
}
.info:hover,
.info:focus-visible {
color: var(--accent);
background: var(--fill);
outline: none;
}
.tooltip {
position: absolute;
top: calc(100% + 9px);
right: -2px;
width: 244px;
padding: 10px 12px;
border-radius: var(--radius-md);
background: var(--panel);
border: 1px solid var(--border);
box-shadow: var(--shadow-md);
color: var(--text-muted);
font-size: 11.5px;
font-weight: 500;
line-height: 1.55;
text-align: left;
letter-spacing: normal;
text-transform: none;
opacity: 0;
visibility: hidden;
transform: translateY(-4px);
transition:
opacity var(--dur-enter) var(--ease-out),
transform var(--dur-enter) var(--ease-out),
visibility var(--dur-enter);
z-index: 5;
pointer-events: none;
}
.info:hover .tooltip,
.info:focus-visible .tooltip {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
/* ---- Body ---- */
.body {
padding: 14px 16px 12px;
}
.actions {
display: flex;
flex-direction: column;
gap: 8px;
}
/* Shared action surface */
.action {
display: flex;
align-items: center;
gap: 11px;
width: 100%;
border: 1px solid var(--border);
background: var(--panel);
color: var(--text);
border-radius: var(--radius-md);
cursor: pointer;
text-align: left;
font-family: inherit;
transition:
background var(--dur-quick) var(--ease-out),
border-color var(--dur-quick) var(--ease-out),
transform var(--dur-quick) var(--ease-out),
box-shadow var(--dur-quick) var(--ease-out);
}
.action:hover {
background: var(--subtle);
border-color: var(--border);
}
.action:active {
transform: translateY(1px);
}
.action:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.action-icon {
flex: none;
display: grid;
place-items: center;
color: var(--text-muted);
}
.action-icon svg {
width: 20px;
height: 20px;
display: block;
}
.action-title {
font-size: 13px;
font-weight: 600;
color: var(--text-strong);
}
/* Primary capture CTA */
.action-primary {
padding: 13px 14px;
background: var(--accent);
border-color: transparent;
color: var(--on-accent);
box-shadow: var(--shadow-sm);
}
.action-primary:hover {
background: var(--accent-strong);
}
.action-primary .action-icon,
.action-primary .action-title {
color: var(--on-accent);
}
.action-text {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: auto;
}
.action-sub {
font-size: 11px;
font-weight: 500;
color: color-mix(in srgb, var(--on-accent) 78%, transparent);
}
.action-go {
flex: none;
display: grid;
place-items: center;
color: color-mix(in srgb, var(--on-accent) 70%, transparent);
transition: transform var(--dur-enter) var(--ease-out);
}
.action-go svg {
width: 18px;
height: 18px;
}
.action-primary:hover .action-go {
transform: translateX(2px);
color: var(--on-accent);
}
/* Secondary 2×2 grid */
.action-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.action-grid .action {
flex-direction: column;
align-items: flex-start;
gap: 9px;
padding: 12px 12px 11px;
min-height: 70px;
}
.action-grid .action:hover .action-icon {
color: var(--accent);
}
/* A lone trailing action (odd count — e.g. Figma as the 5th) spans the full
width so the grid never leaves a ragged half-empty last row. */
.action-grid .action:last-child:nth-child(odd) {
grid-column: 1 / -1;
}
/* ---- States ---- */
.hint {
font-size: 12px;
line-height: 1.5;
color: var(--text-muted);
background: var(--subtle);
border: 1px solid var(--border-soft);
border-radius: var(--radius);
padding: 10px 12px;
margin: 12px 0 0;
}
.hint strong {
color: var(--text-strong);
}
/* ---- Advanced ---- */
.advanced {
margin-top: 12px;
border-top: 1px solid var(--border-soft);
padding-top: 12px;
}
.advanced > summary {
font-size: 12px;
font-weight: 600;
color: var(--text-soft);
cursor: pointer;
list-style: none;
user-select: none;
transition: color var(--dur-quick) var(--ease-out);
}
.advanced > summary::-webkit-details-marker {
display: none;
}
.advanced > summary::before {
content: '';
display: inline-block;
margin-right: 6px;
transition: transform var(--dur-enter) var(--ease-out);
}
.advanced[open] > summary::before {
transform: rotate(90deg);
}
.advanced > summary:hover {
color: var(--text-muted);
}
.advanced[open] > summary {
margin-bottom: 12px;
}
/* On-page bar — compact switch row. The bar stays an opt-in power feature,
so it lives in Advanced as a small toggle rather than a full action row. */
.adv-switch {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 14px;
}
.adv-switch-text {
display: flex;
flex-direction: column;
gap: 2px;
margin-right: auto;
font-size: 12px;
font-weight: 600;
color: var(--text);
line-height: 1.3;
}
.adv-switch-text em {
font-style: normal;
font-weight: 500;
font-size: 11px;
color: var(--text-soft);
}
/* Track + thumb switch — accent fill when on. */
.switch {
flex: none;
position: relative;
width: 38px;
height: 22px;
padding: 0;
border: 1px solid var(--border);
border-radius: var(--radius-pill);
background: var(--muted);
cursor: pointer;
transition:
background var(--dur-quick) var(--ease-out),
border-color var(--dur-quick) var(--ease-out);
}
.switch:hover {
border-color: var(--text-soft);
}
.switch:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.switch-thumb {
position: absolute;
top: 50%;
left: 2px;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--panel);
box-shadow: var(--shadow-sm);
transform: translateY(-50%);
transition: transform var(--dur-enter) var(--ease-out);
}
.switch[aria-checked='true'] {
background: var(--accent);
border-color: var(--accent);
}
.switch[aria-checked='true'] .switch-thumb {
transform: translate(16px, -50%);
background: var(--on-accent);
}
.check {
display: flex;
align-items: flex-start;
gap: 9px;
font-size: 12px;
color: var(--text);
margin-bottom: 12px;
cursor: pointer;
line-height: 1.4;
}
.check input {
margin: 1px 0 0;
accent-color: var(--accent);
}
.check em {
font-style: normal;
color: var(--text-soft);
}
.label-field {
display: block;
font-size: 11px;
font-weight: 600;
color: var(--text-muted);
margin-bottom: 6px;
}
.row {
display: flex;
gap: 8px;
}
.row input {
flex: 1;
height: 34px;
padding: 0 10px;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--panel);
color: var(--text);
font-size: 13px;
font-family: inherit;
transition: border-color var(--dur-quick) var(--ease-out), box-shadow var(--dur-quick) var(--ease-out);
}
.row input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.btn-save {
flex: none;
height: 34px;
padding: 0 14px;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--panel);
color: var(--text-strong);
font-size: 13px;
font-weight: 600;
font-family: inherit;
cursor: pointer;
transition: background var(--dur-quick) var(--ease-out);
}
.btn-save:hover {
background: var(--subtle);
}
/* ---- Status message ---- */
.msg {
font-size: 12px;
font-weight: 500;
margin: 0;
color: var(--text-muted);
}
.msg:not(:empty) {
margin-top: 12px;
}
.msg[data-kind='ok'] {
color: var(--green);
}
.msg[data-kind='err'] {
color: var(--red);
}
/* In-flight capture state: an inline spinner ahead of the status text. */
.msg[data-kind='loading'] {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--text-muted);
}
.msg[data-kind='loading']::before {
content: '';
flex: none;
width: 13px;
height: 13px;
border-radius: 50%;
border: 2px solid color-mix(in srgb, var(--accent) 28%, transparent);
border-top-color: var(--accent);
animation: msg-spin 0.7s linear infinite;
}
@keyframes msg-spin {
to {
transform: rotate(360deg);
}
}
/* While a capture is in flight, dim + lock the capture buttons so the spinner
message reads as the active state and double-fires are impossible. */
.actions {
transition: opacity var(--dur-enter) var(--ease-out);
}
body.busy .actions {
opacity: 0.5;
pointer-events: none;
}
/* ---- Inline "refresh page" recovery affordance ----
Shown only when an on-page surface (image/element picker, on-page bar) can't
be reached because the content script never loaded into this already-open tab
— the usual case right after the extension is installed or updated. */
.refresh-page {
display: inline-flex;
align-items: center;
gap: 6px;
margin-top: 9px;
padding: 6px 12px 6px 9px;
border: 1px solid var(--border);
border-radius: var(--radius-pill);
background: var(--panel);
color: var(--text-strong);
font-family: inherit;
font-size: 12px;
font-weight: 600;
cursor: pointer;
box-shadow: var(--shadow-sm);
transition:
background var(--dur-quick) var(--ease-out),
border-color var(--dur-quick) var(--ease-out),
color var(--dur-quick) var(--ease-out),
transform var(--dur-quick) var(--ease-out);
}
.refresh-page[hidden] {
display: none;
}
.refresh-page:hover {
background: var(--subtle);
border-color: var(--accent);
color: var(--accent);
}
.refresh-page:active {
transform: translateY(1px);
}
.refresh-page:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.refresh-icon {
display: grid;
place-items: center;
color: var(--text-muted);
transition: color var(--dur-quick) var(--ease-out);
}
.refresh-page:hover .refresh-icon {
color: var(--accent);
}
.refresh-icon svg {
width: 14px;
height: 14px;
display: block;
}
.refresh-page.spinning {
pointer-events: none;
opacity: 0.9;
}
.refresh-page.spinning .refresh-icon {
color: var(--accent);
}
.refresh-page.spinning .refresh-icon svg {
animation: refresh-spin 0.7s linear infinite;
}
@keyframes refresh-spin {
to {
transform: rotate(360deg);
}
}