Download src/ui/style.css from magnusp/image-lab: direct link, hf CLI and curl.
- Browser
- Download file 11.3 kB
-
https://huggingface.co/spaces/magnusp/image-lab/resolve/main/src/ui/style.css
- Command line
-
hf download hf://spaces/magnusp/image-lab/src/ui/style.css
-
curl -L -o style.css https://huggingface.co/spaces/magnusp/image-lab/resolve/main/src/ui/style.css
11.3 kB
| /* Tap targets are at least 44px (Apple's minimum) for iPad use. */ | |
| .gradio-container { | |
| max-width: 960px ; | |
| width: 100% ; | |
| margin: 0 auto; | |
| } | |
| button { | |
| min-height: 44px; | |
| } | |
| body, | |
| .gradio-container, | |
| button, | |
| textarea { | |
| font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif ; | |
| } | |
| /* The two Create columns read as cards. */ | |
| #controls-col, | |
| #result-col, | |
| .card-col { | |
| padding: 16px; | |
| gap: 12px; | |
| border: 1px solid var(--border-color-primary); | |
| border-radius: 16px; | |
| background: var(--background-fill-secondary); | |
| box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08); | |
| } | |
| #header h1 { | |
| margin: 0; | |
| font-size: 1.6rem; | |
| font-weight: 700; | |
| letter-spacing: -0.01em; | |
| } | |
| #header p { | |
| margin: 2px 0 0; | |
| font-size: 0.95rem; | |
| opacity: 0.7; | |
| } | |
| #header { | |
| align-items: center; | |
| flex-wrap: nowrap; | |
| } | |
| #header-tools { | |
| justify-content: flex-end; | |
| align-items: center; | |
| flex-wrap: nowrap; | |
| gap: 8px; | |
| } | |
| /* Header buttons are 44px tall (Apple's minimum tap size) so they stay small. */ | |
| #lang-button, | |
| #theme-button { | |
| flex: 0 0 auto ; | |
| min-width: 56px ; | |
| min-height: 44px; | |
| padding: 0 12px; | |
| } | |
| #lang-toggle { | |
| display: none; | |
| flex: 0 0 auto; | |
| min-width: 0; | |
| } | |
| #lang-toggle.open { | |
| display: block; | |
| } | |
| #lang-toggle label { | |
| min-height: 44px; | |
| display: inline-flex; | |
| align-items: center; | |
| } | |
| #idea-box textarea { | |
| font-size: 1.05rem; | |
| line-height: 1.45; | |
| } | |
| #idea-box label span { | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| } | |
| #image-actions { | |
| gap: 8px; | |
| } | |
| #chip-panel { | |
| gap: 8px; | |
| } | |
| #new-visitor-confirm { | |
| display: none; | |
| gap: 8px; | |
| } | |
| #new-visitor-confirm.open { | |
| display: flex; | |
| } | |
| /* The empty frame says what it is for; it disappears when an image arrives. */ | |
| #result-hint { | |
| position: absolute; | |
| inset: 0; | |
| z-index: 1; | |
| display: flex; | |
| align-items: flex-end; | |
| justify-content: center; | |
| padding-bottom: 28px; | |
| pointer-events: none; | |
| background: transparent; | |
| border: 0; | |
| font-size: 0.95rem; | |
| opacity: 0.65; | |
| } | |
| #result-wrap:has(#result-image img) #result-hint { | |
| display: none; | |
| } | |
| .style-tile.primary::before { | |
| content: "\2713 "; | |
| } | |
| #create-layout { | |
| gap: 16px; | |
| flex-wrap: wrap; | |
| } | |
| .section-heading, | |
| .section-heading .prose { | |
| overflow: visible ; | |
| } | |
| .section-heading p { | |
| margin: 0; | |
| font-size: 0.85rem; | |
| line-height: 1.35; | |
| opacity: 0.75; | |
| } | |
| .section-heading strong { | |
| font-size: 0.8rem; | |
| font-weight: 700; | |
| letter-spacing: 0.05em; | |
| text-transform: uppercase; | |
| opacity: 1; | |
| } | |
| #status-slot { | |
| min-height: 44px; | |
| } | |
| #style-row { | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| .style-tile { | |
| min-height: 44px; | |
| flex: 0 0 auto ; | |
| min-width: 0 ; | |
| padding: 0 16px; | |
| border-radius: 999px; | |
| font-size: 0.95rem; | |
| font-weight: 500; | |
| } | |
| .primary-action { | |
| min-height: 52px; | |
| font-size: 1.05rem; | |
| font-weight: 600; | |
| width: 100%; | |
| background: linear-gradient(135deg, #6366f1, #7c3aed); | |
| border: 0; | |
| color: #fff; | |
| box-shadow: 0 2px 8px rgba(99, 102, 241, 0.35); | |
| } | |
| .status-card { | |
| padding: 10px 14px; | |
| border-radius: 12px; | |
| font-size: 0.95rem; | |
| } | |
| .rewrite-card { | |
| min-height: 52px; | |
| font-size: 0.95rem; | |
| white-space: normal; | |
| text-align: left; | |
| } | |
| #result-image { | |
| aspect-ratio: 1 / 1; | |
| max-height: min(55vh, 520px); | |
| } | |
| #result-image img, | |
| #photo-result img { | |
| max-height: 100%; | |
| object-fit: contain; | |
| cursor: zoom-in; | |
| } | |
| #result-image.zoomed, | |
| #photo-result.zoomed { | |
| aspect-ratio: auto; | |
| max-height: none; | |
| height: 100vh ; /* the photo result has a fixed height set by Gradio */ | |
| width: 100vw ; | |
| position: fixed; | |
| inset: 0; | |
| z-index: 1000; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: rgba(0, 0, 0, 0.9); | |
| border: 0; | |
| border-radius: 0; | |
| } | |
| #result-image.zoomed img, | |
| #photo-result.zoomed img { | |
| max-height: 100vh; | |
| max-width: 100vw; | |
| width: 100%; | |
| height: 100vh; | |
| cursor: zoom-out; | |
| } | |
| .new-visitor { | |
| min-height: 44px; | |
| } | |
| #helper-row { | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| #chip-row { | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| /* The "working" overlay: shown while a .result-wrap has the busy class (see src/ui/busy.py). */ | |
| .result-wrap { | |
| position: relative; | |
| gap: 0; | |
| } | |
| .busy-overlay { | |
| display: none; | |
| } | |
| .result-wrap.busy { | |
| min-height: 260px; | |
| } | |
| .result-wrap.busy .busy-overlay { | |
| display: flex; | |
| position: absolute; | |
| inset: 0; | |
| z-index: 20; | |
| align-items: center; | |
| justify-content: center; | |
| background: rgba(8, 10, 20, 0.6); | |
| border-radius: 12px; | |
| } | |
| .busy-box { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 14px; | |
| padding: 16px; | |
| color: #fff; | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| text-align: center; | |
| } | |
| .spinner { | |
| width: 56px; | |
| height: 56px; | |
| border: 6px solid rgba(255, 255, 255, 0.3); | |
| border-top-color: #fff; | |
| border-radius: 50%; | |
| animation: busy-spin 0.9s linear infinite; | |
| } | |
| @keyframes busy-spin { | |
| to { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| /* Help me / Give me an idea: the text box dims and shows a small spinner while the AI writes. */ | |
| #idea-box { | |
| position: relative; | |
| } | |
| #idea-box.busy-helper textarea { | |
| opacity: 0.4; | |
| pointer-events: none; | |
| } | |
| #idea-box.busy-helper::after { | |
| content: ""; | |
| position: absolute; | |
| top: 62%; | |
| right: 24px; | |
| z-index: 5; | |
| width: 32px; | |
| height: 32px; | |
| margin-top: -16px; | |
| border: 4px solid rgba(99, 102, 241, 0.25); | |
| border-top-color: #6366f1; | |
| border-radius: 50%; | |
| animation: busy-spin 0.9s linear infinite; | |
| } | |
| .result-wrap.busy-create .busy-edit-text, | |
| .result-wrap.busy-edit .busy-create-text { | |
| display: none; | |
| } | |
| .swap-button { | |
| min-height: 44px; | |
| width: 100%; | |
| font-size: 0.95rem; | |
| } | |
| /* "What did the model receive?": opened by a class from src/ui/chips.py. */ | |
| #received-card:not(.open) { | |
| display: none; | |
| } | |
| .received-box { | |
| padding: 12px 14px; | |
| border: 1px solid rgba(99, 102, 241, 0.35); | |
| border-radius: 12px; | |
| font-size: 0.9rem; | |
| line-height: 1.45; | |
| } | |
| .received-box p { | |
| margin: 0 0 6px; | |
| } | |
| .received-box blockquote { | |
| margin: 0 0 10px; | |
| padding: 6px 10px; | |
| border-left: 3px solid #6366f1; | |
| overflow-wrap: anywhere; | |
| } | |
| .received-note, | |
| .received-model { | |
| opacity: 0.75; | |
| } | |
| .chip-button { | |
| min-height: 44px; | |
| flex: 0 0 auto ; | |
| min-width: 0 ; | |
| padding: 0 16px; | |
| border-radius: 999px; | |
| font-size: 0.95rem; | |
| font-weight: 500; | |
| } | |
| .ideas-button, | |
| .helper-button { | |
| min-height: 44px; | |
| flex: 0 0 auto ; | |
| min-width: 0 ; | |
| padding: 0 16px; | |
| border-radius: 999px; | |
| font-size: 0.95rem; | |
| font-weight: 500; | |
| } | |
| /* The ideas popup: a fixed overlay, so it needs no modal component. */ | |
| #ideas-overlay { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 1000; | |
| background: rgba(0, 0, 0, 0.55); | |
| align-items: center; | |
| justify-content: center; | |
| padding: 16px; | |
| } | |
| #ideas-panel { | |
| background: var(--background-fill-primary); | |
| border-radius: 16px; | |
| width: min(920px, 100%); | |
| max-height: 92vh; | |
| overflow-y: auto; | |
| padding: 16px; | |
| flex-grow: 0; | |
| } | |
| #ideas-header { | |
| align-items: center; | |
| } | |
| .ideas-close { | |
| min-height: 48px; | |
| max-width: 160px; | |
| } | |
| .ideas-gallery .grid-wrap { | |
| max-height: none ; | |
| overflow-y: visible ; | |
| } | |
| /* Example cards: the picture on top, its text below (not laid over it). 2 columns on a phone. */ | |
| .ideas-gallery .grid-container { | |
| grid-template-columns: repeat(2, minmax(0, 1fr)) ; | |
| gap: 12px; | |
| } | |
| @media (min-width: 700px) { | |
| .ideas-gallery .grid-container { | |
| grid-template-columns: repeat(3, minmax(0, 1fr)) ; | |
| } | |
| } | |
| .ideas-gallery .thumbnail-item { | |
| display: flex; | |
| flex-direction: column; | |
| height: auto ; | |
| aspect-ratio: auto ; | |
| overflow: visible; | |
| background: transparent; | |
| border: 0; | |
| text-align: left; | |
| } | |
| .ideas-gallery .thumbnail-item img { | |
| width: 100%; | |
| height: auto; | |
| aspect-ratio: 1 / 1; | |
| border-radius: 12px; | |
| object-fit: cover; | |
| } | |
| .ideas-gallery .caption-label { | |
| position: static ; | |
| margin: 0; | |
| padding: 6px 2px 0; | |
| white-space: normal; | |
| font-size: 0.9rem; | |
| line-height: 1.3; | |
| text-align: left; | |
| background: transparent; | |
| color: var(--body-text-color); | |
| } | |
| /* Category pills: they wrap, so every category is visible on any screen. */ | |
| #ideas-categories, | |
| #ideas-categories .wrap { | |
| height: auto ; | |
| min-height: 0; | |
| overflow: visible ; | |
| } | |
| /* The panel is a scrolling flex column: without this the pills shrink to nothing. */ | |
| #ideas-categories, | |
| .ideas-group { | |
| flex-shrink: 0; | |
| } | |
| #ideas-categories .wrap { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| #ideas-categories label { | |
| min-height: 40px; | |
| padding: 0 12px; | |
| border-radius: 999px; | |
| font-size: 0.85rem; | |
| } | |
| /* The "How it works" pipeline: steps are lit by src/ui/how_tab.py scripts. */ | |
| .pipe-you { --kind: #22a06b; } | |
| .pipe-code { --kind: #8b95a7; } | |
| .pipe-language { --kind: #3b82f6; } | |
| .pipe-image { --kind: #a855f7; } | |
| .pipe-safety { --kind: #f59e0b; } | |
| .pipe-flow { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .pipe-box { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 10px 14px; | |
| border: 2px solid var(--kind); | |
| border-radius: 12px; | |
| font-weight: 600; | |
| opacity: 0.4; | |
| transition: all 0.25s ease; | |
| } | |
| .pipe-box.done { | |
| opacity: 0.85; | |
| } | |
| .pipe-box.active { | |
| opacity: 1; | |
| transform: scale(1.08); | |
| background: color-mix(in srgb, var(--kind) 25%, transparent); | |
| box-shadow: 0 0 0 4px color-mix(in srgb, var(--kind) 35%, transparent), 0 0 20px var(--kind); | |
| } | |
| .pipe-num { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 26px; | |
| height: 26px; | |
| border-radius: 50%; | |
| background: var(--kind); | |
| color: #fff; | |
| font-size: 0.85rem; | |
| } | |
| .pipe-arrow { | |
| font-size: 1.6rem; | |
| opacity: 0.5; | |
| } | |
| .pipe-captions { | |
| min-height: 190px; | |
| margin-top: 16px; | |
| } | |
| .pipe-caption { | |
| display: none; | |
| padding: 14px 18px; | |
| border-left: 8px solid var(--kind); | |
| border-radius: 8px; | |
| background: var(--background-fill-secondary); | |
| font-size: 1rem; | |
| } | |
| .pipe-caption.active { | |
| display: block; | |
| } | |
| .pipe-caption h3 { | |
| margin: 0 0 6px; | |
| } | |
| .pipe-caption p { | |
| margin: 0 0 10px; | |
| } | |
| .pipe-tag { | |
| display: inline-block; | |
| padding: 2px 10px; | |
| border-radius: 999px; | |
| background: var(--kind); | |
| color: #fff; | |
| font-size: 0.9rem; | |
| font-weight: 600; | |
| } | |
| .pipe-legend { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px 16px; | |
| margin-top: 12px; | |
| font-size: 0.9rem; | |
| } | |
| .pipe-key i { | |
| display: inline-block; | |
| width: 12px; | |
| height: 12px; | |
| margin-right: 6px; | |
| border-radius: 3px; | |
| background: var(--kind); | |
| } | |
| #pipe-buttons { | |
| gap: 8px; | |
| } | |
| .pipe-button { | |
| min-height: 52px; | |
| font-size: 1rem; | |
| } | |
| /* Photo studio */ | |
| /* body.photo-open is set by the browser from the admin's switch (src/ui/photo_tab.py). */ | |
| body:not(.photo-open) #photo-layout, | |
| body.photo-open #photo-closed, | |
| #photo-flag { | |
| display: none ; | |
| } | |
| #photo-layout { | |
| gap: 16px; | |
| flex-wrap: wrap; | |
| } | |
| .photo-notice { | |
| padding: 12px 14px; | |
| border: 1px solid #f59e0b; | |
| border-radius: 12px; | |
| background: rgba(245, 158, 11, 0.12); | |
| font-size: 0.9rem; | |
| line-height: 1.4; | |
| } | |
| .photo-notice p { | |
| margin: 0; | |
| } | |
| #photo-styles { | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| } | |
| .photo-style { | |
| min-height: 44px; | |
| flex: 0 0 auto ; | |
| min-width: 0 ; | |
| padding: 0 16px; | |
| border-radius: 999px; | |
| font-size: 0.95rem; | |
| font-weight: 500; | |
| } | |