_inputs.scss
sha256:7d6dd8f4a89e2d1fef2d84f6e65feaff51385d382f466766b7f690a22ec18e32
fix: fall back to DB ancestry check when mpack-only fast-fo…
Sonnet 4.6
patch
6 days ago
| 1 | // ───────────────────────────────────────────────────────────────────────────── |
| 2 | // Component: Inputs |
| 3 | // File: src/scss/components/_inputs.scss |
| 4 | // |
| 5 | // Variants: input, select, textarea, .form-input, .form-select |
| 6 | // .form-group, .form-label, .form-hint, .form-checkbox-row |
| 7 | // Tokens: --bg-surface, --border-default, --color-accent, --text-primary |
| 8 | // Usage: <input type="text" class="form-input"> |
| 9 | // |
| 10 | // Notes: Focus ring uses color-mix for a soft accent glow. |
| 11 | // Tag-pill input widget also lives here. |
| 12 | // ───────────────────────────────────────────────────────────────────────────── |
| 13 | |
| 14 | .form-group { |
| 15 | display: flex; |
| 16 | flex-direction: column; |
| 17 | gap: var(--space-1); |
| 18 | margin-bottom: var(--space-4); |
| 19 | } |
| 20 | |
| 21 | .form-label { |
| 22 | display: block; |
| 23 | font-size: var(--text-sm); |
| 24 | font-weight: var(--weight-semibold); |
| 25 | margin-bottom: var(--space-1); |
| 26 | color: var(--text-primary); |
| 27 | |
| 28 | .required { color: var(--color-danger); margin-left: 2px; } |
| 29 | } |
| 30 | |
| 31 | .form-description { |
| 32 | font-size: var(--text-xs); |
| 33 | color: var(--text-muted); |
| 34 | margin-bottom: var(--space-2); |
| 35 | } |
| 36 | |
| 37 | .form-hint { |
| 38 | font-size: var(--text-xs); |
| 39 | color: var(--text-muted); |
| 40 | } |
| 41 | |
| 42 | .form-input, |
| 43 | .form-select, |
| 44 | select, |
| 45 | input[type="text"], |
| 46 | input[type="password"], |
| 47 | input[type="email"], |
| 48 | input[type="search"], |
| 49 | textarea { |
| 50 | width: 100%; |
| 51 | box-sizing: border-box; |
| 52 | padding: 6px 10px; |
| 53 | background: var(--bg-surface); |
| 54 | border: 1px solid var(--border-default); |
| 55 | border-radius: var(--radius-md); |
| 56 | color: var(--text-primary); |
| 57 | font-size: var(--text-sm); |
| 58 | font-family: var(--font-sans); |
| 59 | transition: border-color var(--transition-base); |
| 60 | } |
| 61 | |
| 62 | .form-input::placeholder, |
| 63 | input[type="text"]::placeholder, |
| 64 | input[type="password"]::placeholder, |
| 65 | input[type="email"]::placeholder, |
| 66 | input[type="search"]::placeholder, |
| 67 | textarea::placeholder { |
| 68 | color: var(--text-muted); |
| 69 | } |
| 70 | |
| 71 | .form-input:focus, |
| 72 | .form-select:focus, |
| 73 | select:focus, |
| 74 | input[type="text"]:focus, |
| 75 | input[type="password"]:focus, |
| 76 | input[type="email"]:focus, |
| 77 | input[type="search"]:focus, |
| 78 | textarea:focus { |
| 79 | outline: none; |
| 80 | border-color: var(--color-accent); |
| 81 | box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 25%, transparent); |
| 82 | } |
| 83 | |
| 84 | .form-input:disabled, |
| 85 | .form-select:disabled, |
| 86 | select:disabled, |
| 87 | input:disabled, |
| 88 | textarea:disabled { |
| 89 | opacity: 0.5; |
| 90 | cursor: not-allowed; |
| 91 | background: var(--bg-overlay); |
| 92 | } |
| 93 | |
| 94 | .form-input[aria-invalid="true"], |
| 95 | input[aria-invalid="true"], |
| 96 | textarea[aria-invalid="true"] { |
| 97 | border-color: var(--color-danger); |
| 98 | box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-danger) 25%, transparent); |
| 99 | } |
| 100 | |
| 101 | .form-error { |
| 102 | font-size: var(--text-xs); |
| 103 | color: var(--color-danger); |
| 104 | margin-top: var(--space-1); |
| 105 | } |
| 106 | |
| 107 | // Toggle switch |
| 108 | .form-toggle { |
| 109 | position: relative; |
| 110 | display: inline-flex; |
| 111 | align-items: center; |
| 112 | gap: var(--space-2); |
| 113 | cursor: pointer; |
| 114 | |
| 115 | input[type="checkbox"] { |
| 116 | position: absolute; |
| 117 | opacity: 0; |
| 118 | width: 0; |
| 119 | height: 0; |
| 120 | } |
| 121 | |
| 122 | &__track { |
| 123 | width: 36px; |
| 124 | height: 20px; |
| 125 | background: var(--bg-overlay); |
| 126 | border: 1px solid var(--border-default); |
| 127 | border-radius: 10px; |
| 128 | transition: background var(--transition-fast), border-color var(--transition-fast); |
| 129 | flex-shrink: 0; |
| 130 | } |
| 131 | |
| 132 | &__thumb { |
| 133 | position: absolute; |
| 134 | left: 3px; |
| 135 | width: 14px; |
| 136 | height: 14px; |
| 137 | background: var(--text-muted); |
| 138 | border-radius: 50%; |
| 139 | transition: transform var(--transition-fast), background var(--transition-fast); |
| 140 | } |
| 141 | |
| 142 | input:checked ~ &__track { |
| 143 | background: color-mix(in srgb, var(--color-accent) 20%, transparent); |
| 144 | border-color: var(--color-accent); |
| 145 | } |
| 146 | |
| 147 | input:checked ~ &__track &__thumb { |
| 148 | transform: translateX(16px); |
| 149 | background: var(--color-accent); |
| 150 | } |
| 151 | |
| 152 | input:focus-visible ~ &__track { |
| 153 | outline: 2px solid var(--color-accent); |
| 154 | outline-offset: 2px; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | .form-checkbox-row { |
| 159 | display: flex; |
| 160 | align-items: flex-start; |
| 161 | gap: var(--space-3); |
| 162 | padding: var(--space-3); |
| 163 | background: var(--bg-surface); |
| 164 | border: 1px solid var(--border-subtle); |
| 165 | border-radius: var(--radius-md); |
| 166 | margin-bottom: var(--space-2); |
| 167 | |
| 168 | input[type=checkbox] { margin-top: 2px; flex-shrink: 0; } |
| 169 | } |
| 170 | |
| 171 | .form-checkbox-label { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-primary); } |
| 172 | .form-checkbox-desc { font-size: var(--text-xs); color: var(--text-muted); margin-top: 2px; } |
| 173 | |
| 174 | // Tag-pill input widget |
| 175 | .tag-input-container { |
| 176 | display: flex; |
| 177 | flex-wrap: wrap; |
| 178 | gap: 4px; |
| 179 | padding: 6px 8px; |
| 180 | background: var(--bg-surface); |
| 181 | border: 1px solid var(--border-default); |
| 182 | border-radius: var(--radius-md); |
| 183 | min-height: 38px; |
| 184 | cursor: text; |
| 185 | } |
| 186 | |
| 187 | .tag-pill { |
| 188 | display: inline-flex; |
| 189 | align-items: center; |
| 190 | gap: 4px; |
| 191 | background: var(--bg-overlay); |
| 192 | border: 1px solid var(--border-subtle); |
| 193 | border-radius: 20px; |
| 194 | padding: 2px 8px; |
| 195 | font-size: 12px; |
| 196 | color: var(--text-primary); |
| 197 | } |
| 198 | |
| 199 | .tag-pill-remove { |
| 200 | background: none; |
| 201 | border: none; |
| 202 | cursor: pointer; |
| 203 | color: var(--text-muted); |
| 204 | font-size: 14px; |
| 205 | padding: 0; |
| 206 | line-height: 1; |
| 207 | |
| 208 | &:hover { color: var(--color-danger); } |
| 209 | } |
| 210 | |
| 211 | .tag-text-input { |
| 212 | border: none; |
| 213 | outline: none; |
| 214 | background: transparent; |
| 215 | color: var(--text-primary); |
| 216 | font-size: var(--text-sm); |
| 217 | min-width: 80px; |
| 218 | flex: 1; |
| 219 | } |
| 220 | |
| 221 | // Verified-only toggle — styled checkbox pill used on listing pages |
| 222 | .verified-toggle { |
| 223 | display: inline-flex; |
| 224 | align-items: center; |
| 225 | cursor: pointer; |
| 226 | user-select: none; |
| 227 | |
| 228 | input[type="checkbox"] { |
| 229 | position: absolute; |
| 230 | opacity: 0; |
| 231 | width: 0; |
| 232 | height: 0; |
| 233 | pointer-events: none; |
| 234 | } |
| 235 | |
| 236 | &:hover .verified-chip { |
| 237 | border-color: var(--border-emphasis); |
| 238 | color: var(--text-secondary); |
| 239 | |
| 240 | svg { opacity: 0.7; } |
| 241 | } |
| 242 | |
| 243 | input:checked ~ .verified-chip { |
| 244 | background: color-mix(in srgb, var(--color-success) 8%, transparent); |
| 245 | border-color: color-mix(in srgb, var(--color-success) 30%, transparent); |
| 246 | color: var(--color-success); |
| 247 | |
| 248 | svg { opacity: 1; stroke: var(--color-success); } |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | .verified-chip { |
| 253 | display: inline-flex; |
| 254 | align-items: center; |
| 255 | gap: 5px; |
| 256 | font-size: 11px; |
| 257 | font-weight: var(--weight-medium); |
| 258 | letter-spacing: 0.02em; |
| 259 | padding: 4px 10px; |
| 260 | border-radius: 20px; |
| 261 | border: 1px solid var(--border-default); |
| 262 | color: var(--text-muted); |
| 263 | background: transparent; |
| 264 | transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast); |
| 265 | |
| 266 | svg { opacity: 0.4; transition: opacity var(--transition-fast); } |
| 267 | } |
| 268 | |
| 269 | // Token form (auth fallback) |
| 270 | .token-form { |
| 271 | background: var(--bg-surface); |
| 272 | border: 1px solid var(--color-orange); |
| 273 | border-radius: var(--radius-base); |
| 274 | padding: var(--space-4); |
| 275 | margin-bottom: var(--space-5); |
| 276 | |
| 277 | p { |
| 278 | font-size: var(--text-base); |
| 279 | color: var(--text-muted); |
| 280 | margin-bottom: var(--space-2); |
| 281 | } |
| 282 | } |
File History
1 commit
sha256:7d6dd8f4a89e2d1fef2d84f6e65feaff51385d382f466766b7f690a22ec18e32
fix: fall back to DB ancestry check when mpack-only fast-fo…
Sonnet 4.6
patch
6 days ago