JamesNR/patchnet
0
1/* ───────────── Reset & Base ───────────── */2*,3*::before,4*::after {5 box-sizing: border-box;6 margin: 0;7 padding: 0;8}9 10:root {11 --bg: #0c0e14;12 --bg-card: #141722;13 --bg-card-alt: #1a1e2e;14 --border: #252a3a;15 --text: #e4e6ef;16 --text-dim: #8b90a5;17 --accent: #6c63ff;18 --accent-glow: rgba(108, 99, 255, .25);19 --green: #2dd4a8;20 --amber: #f5a623;21 --red: #f45b69;22 --radius: 14px;23 --font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;24}25 26html {27 font-size: 15px;28}29 30body {31 font-family: var(--font);32 background: var(--bg);33 color: var(--text);34 min-height: 100vh;35 -webkit-font-smoothing: antialiased;36}37 38/* ───────────── Layout ───────────── */39.app {40 display: flex;41 flex-direction: column;42 min-height: 100vh;43}44 45.main {46 max-width: 960px;47 width: 100%;48 margin: 0 auto;49 padding: 2rem 1.25rem 4rem;50}51 52/* ───────────── Header ───────────── */53.header {54 background: linear-gradient(180deg, rgba(108, 99, 255, .08) 0%, transparent 100%);55 border-bottom: 1px solid var(--border);56 padding: 1.25rem 1.5rem;57}58 59.header-inner {60 max-width: 960px;61 margin: 0 auto;62}63 64.logo {65 display: flex;66 align-items: center;67 gap: .85rem;68}69 70.logo-icon {71 width: 42px;72 height: 42px;73 background: var(--accent);74 border-radius: 10px;75 display: grid;76 place-items: center;77 font-weight: 700;78 font-size: 1.35rem;79 color: #fff;80 box-shadow: 0 4px 20px var(--accent-glow);81}82 83.logo h1 {84 font-size: 1.3rem;85 font-weight: 700;86 letter-spacing: -.02em;87}88 89.subtitle {90 font-size: .78rem;91 color: var(--text-dim);92 font-weight: 400;93}94 95/* ───────────── Card Base ───────────── */96.card {97 background: var(--bg-card);98 border: 1px solid var(--border);99 border-radius: var(--radius);100 padding: 1.75rem;101}102 103.card h2 {104 font-size: 1.05rem;105 font-weight: 600;106 margin-bottom: .35rem;107}108 109.card-subtitle {110 color: var(--text-dim);111 font-size: .82rem;112 margin-bottom: 1rem;113}114 115/* ───────────── Upload Section ───────────── */116.upload-section {117 margin-bottom: 2rem;118}119 120.form-grid {121 display: grid;122 grid-template-columns: 1fr 1fr;123 gap: 1.5rem;124 align-items: start;125}126 127@media (max-width: 640px) {128 .form-grid {129 grid-template-columns: 1fr;130 }131}132 133.upload-area {134 border: 2px dashed var(--border);135 border-radius: 12px;136 min-height: 220px;137 display: flex;138 align-items: center;139 justify-content: center;140 cursor: pointer;141 transition: border-color .2s, background .2s;142 position: relative;143 overflow: hidden;144}145 146.upload-area:hover,147.upload-area.dragover {148 border-color: var(--accent);149 background: rgba(108, 99, 255, .04);150}151 152.upload-placeholder {153 text-align: center;154 padding: 1.5rem;155}156 157.upload-icon {158 color: var(--text-dim);159 margin-bottom: .75rem;160}161 162.upload-text {163 font-size: .9rem;164 color: var(--text-dim);165 margin-bottom: .25rem;166}167 168.upload-link {169 color: var(--accent);170 font-weight: 500;171 text-decoration: underline;172 cursor: pointer;173}174 175.upload-hint {176 font-size: .75rem;177 color: var(--text-dim);178 opacity: .7;179}180 181.preview-img {182 width: 100%;183 height: 100%;184 object-fit: contain;185 border-radius: 10px;186 position: absolute;187 inset: 0;188}189 190/* ───────────── Form Controls ───────────── */191.form-controls {192 display: flex;193 flex-direction: column;194 gap: 1rem;195}196 197.input-group label {198 display: block;199 font-size: .82rem;200 font-weight: 500;201 color: var(--text-dim);202 margin-bottom: .4rem;203}204 205.input-group input {206 width: 100%;207 padding: .75rem 1rem;208 background: var(--bg);209 border: 1px solid var(--border);210 border-radius: 10px;211 color: var(--text);212 font-family: var(--font);213 font-size: .9rem;214 outline: none;215 transition: border-color .2s;216}217 218.input-group input:focus {219 border-color: var(--accent);220}221 222.input-group input::placeholder {223 color: var(--text-dim);224 opacity: .5;225}226 227/* ───────────── Button ───────────── */228.btn-primary {229 padding: .85rem 1.5rem;230 background: var(--accent);231 color: #fff;232 border: none;233 border-radius: 10px;234 font-family: var(--font);235 font-size: .92rem;236 font-weight: 600;237 cursor: pointer;238 transition: opacity .2s, transform .1s, box-shadow .2s;239 box-shadow: 0 4px 20px var(--accent-glow);240 margin-top: auto;241}242 243.btn-primary:hover:not(:disabled) {244 opacity: .9;245 transform: translateY(-1px);246}247 248.btn-primary:active:not(:disabled) {249 transform: translateY(0);250}251 252.btn-primary:disabled {253 opacity: .45;254 cursor: not-allowed;255}256 257.btn-text,258.btn-loading {259 display: inline-flex;260 align-items: center;261 gap: .4rem;262}263 264.spinner {265 display: inline-block;266 width: 16px;267 height: 16px;268 border: 2px solid rgba(255, 255, 255, .3);269 border-top-color: #fff;270 border-radius: 50%;271 animation: spin .7s linear infinite;272}273 274@keyframes spin {275 to {276 transform: rotate(360deg);277 }278}279 280/* ───────────── Scores Grid ───────────── */281.scores-grid {282 display: grid;283 grid-template-columns: repeat(3, 1fr);284 gap: 1rem;285 margin-bottom: 1.5rem;286}287 288@media (max-width: 640px) {289 .scores-grid {290 grid-template-columns: 1fr;291 }292}293 294.score-card {295 text-align: center;296 padding: 1.5rem 1rem;297 transition: transform .2s;298}299 300.score-card:hover {301 transform: translateY(-3px);302}303 304.score-label {305 font-size: .82rem;306 font-weight: 600;307 text-transform: uppercase;308 letter-spacing: .06em;309 color: var(--text-dim);310 margin-bottom: 1rem;311}312 313.score-ring {314 position: relative;315 width: 110px;316 height: 110px;317 margin: 0 auto 1rem;318}319 320.score-ring svg {321 width: 100%;322 height: 100%;323 transform: rotate(-90deg);324}325 326.ring-bg {327 fill: none;328 stroke: var(--bg);329 stroke-width: 8;330}331 332.ring-fill {333 fill: none;334 stroke: var(--accent);335 stroke-width: 8;336 stroke-linecap: round;337 stroke-dasharray: 326.73;338 /* 2π·52 */339 stroke-dashoffset: 326.73;340 transition: stroke-dashoffset 1s ease-out, stroke .3s;341}342 343.score-value {344 position: absolute;345 inset: 0;346 display: flex;347 align-items: center;348 justify-content: center;349 font-size: 1.4rem;350 font-weight: 700;351}352 353.score-desc {354 font-size: .78rem;355 color: var(--text-dim);356}357 358/* Score colour classes */359.ring-good {360 stroke: var(--green);361}362 363.ring-mid {364 stroke: var(--amber);365}366 367.ring-low {368 stroke: var(--red);369}370 371/* ───────────── Annotated Image ───────────── */372.annotated-section {373 margin-bottom: 1.5rem;374}375 376.annotated-wrapper {377 border-radius: 10px;378 overflow: hidden;379 border: 1px solid var(--border);380 margin-bottom: .75rem;381}382 383.annotated-wrapper img {384 width: 100%;385 display: block;386}387 388.patch-info {389 font-size: .82rem;390 color: var(--text-dim);391 text-align: center;392}393 394.legend-dot {395 display: inline-block;396 width: 10px;397 height: 10px;398 border-radius: 3px;399 margin-right: .25rem;400 vertical-align: middle;401}402 403.legend-grid {404 background: #b4f0ff;405}406 407.legend-surf {408 background: #00ff80;409}410 411/* ───────────── SURF Patches Gallery ───────────── */412.patches-section {413 margin-bottom: 2rem;414}415 416.patches-gallery {417 display: grid;418 grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));419 gap: .75rem;420}421 422.patches-gallery img {423 width: 100%;424 aspect-ratio: 1;425 object-fit: cover;426 border-radius: 8px;427 border: 1px solid var(--border);428 transition: transform .2s;429}430 431.patches-gallery img:hover {432 transform: scale(1.05);433}434 435/* ───────────── Footer ───────────── */436.footer {437 text-align: center;438 padding: 1.5rem;439 font-size: .78rem;440 color: var(--text-dim);441 border-top: 1px solid var(--border);442 margin-top: auto;443}444 445/* ───────────── Utilities ───────────── */446.hidden {447 display: none !important;448}449 450/* ───────────── Fade-in animation ───────────── */451.results-section {452 animation: fadeUp .5s ease-out;453}454 455@keyframes fadeUp {456 from {457 opacity: 0;458 transform: translateY(16px);459 }460 461 to {462 opacity: 1;463 transform: translateY(0);464 }465}