Release Scan Tools v0.1.0

This commit is contained in:
2026-09-01 14:34:51 +02:00
commit 75cd6a6195
64 changed files with 11626 additions and 0 deletions
+491
View File
@@ -0,0 +1,491 @@
:root {
color-scheme: light dark;
font-family:
Inter,
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
--scan-ink: var(--toolbox-text, #17212b);
--scan-muted: var(--toolbox-muted, #5f6b76);
--scan-panel: var(--toolbox-surface, #ffffff);
--scan-soft: color-mix(
in srgb,
var(--scan-panel) 91%,
var(--toolbox-accent, #296b66)
);
--scan-line: color-mix(in srgb, var(--scan-ink) 18%, transparent);
--scan-accent: var(--toolbox-accent, #176c63);
--scan-danger: #b3261e;
}
* {
box-sizing: border-box;
}
button,
input,
select,
textarea {
font: inherit;
}
button,
select,
input[type="range"] {
min-height: 2.65rem;
}
button,
select {
border: 1px solid var(--scan-line);
border-radius: 0.75rem;
background: var(--scan-panel);
color: var(--scan-ink);
padding: 0.6rem 0.85rem;
}
button {
cursor: pointer;
font-weight: 700;
}
button:hover:not(:disabled) {
border-color: var(--scan-accent);
}
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="slider"]:focus-visible {
outline: 3px solid color-mix(in srgb, var(--scan-accent) 65%, transparent);
outline-offset: 2px;
}
button:disabled {
cursor: not-allowed;
opacity: 0.55;
}
.workbench {
width: min(100%, 90rem);
margin: 0 auto;
padding: 1rem;
color: var(--scan-ink);
}
.intro-card,
.empty-card,
.pages-card,
.editor-card,
.export-card,
.preview-card,
.action-panel > section,
.ocr-result {
border: 1px solid var(--scan-line);
border-radius: 1rem;
background: var(--scan-panel);
box-shadow: 0 0.6rem 1.8rem color-mix(in srgb, #000 7%, transparent);
}
.intro-card {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1.5rem;
padding: 1.2rem 1.35rem;
}
.intro-card h2,
.section-heading h2,
.export-card h2,
.empty-card h2 {
margin: 0.15rem 0 0.35rem;
}
.intro-card p:not(.eyebrow) {
max-width: 72ch;
margin: 0;
color: var(--scan-muted);
}
.eyebrow {
margin: 0;
color: var(--scan-accent);
text-transform: uppercase;
letter-spacing: 0.09em;
font-size: 0.73rem;
font-weight: 800;
}
.file-button {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
min-height: 3rem;
border-radius: 0.8rem;
background: var(--scan-accent);
color: #fff;
padding: 0.7rem 1rem;
cursor: pointer;
font-weight: 800;
}
.file-button input {
position: absolute;
inline-size: 1px;
block-size: 1px;
opacity: 0;
}
.status-line {
min-height: 1.5rem;
margin: 0.75rem 0 0;
color: var(--scan-muted);
}
.error {
margin: 0.65rem 0;
border-left: 0.3rem solid var(--scan-danger);
border-radius: 0.4rem;
background: color-mix(in srgb, var(--scan-danger) 10%, var(--scan-panel));
padding: 0.7rem 0.9rem;
}
.empty-card {
margin-top: 1rem;
padding: 2rem;
}
.empty-card li + li {
margin-top: 0.45rem;
}
.workspace-grid {
display: grid;
grid-template-columns: 15.5rem minmax(0, 1fr) 15.5rem;
align-items: start;
gap: 1rem;
margin-top: 0.75rem;
}
.pages-card,
.export-card {
position: sticky;
top: 5.3rem;
padding: 1rem;
max-height: calc(100vh - 6.5rem);
overflow: auto;
}
.editor-card {
min-width: 0;
padding: 1rem;
}
.section-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.section-heading h3 {
margin: 0;
}
.section-heading small,
.section-heading span {
color: var(--scan-muted);
}
.page-strip {
display: grid;
gap: 0.55rem;
list-style: none;
margin: 0.8rem 0;
padding: 0;
}
.page-strip li {
position: relative;
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
border: 1px solid var(--scan-line);
border-radius: 0.8rem;
overflow: hidden;
background: var(--scan-soft);
}
.page-strip li.selected {
border-color: var(--scan-accent);
box-shadow: inset 0 0 0 1px var(--scan-accent);
}
.page-choice {
display: grid;
justify-items: start;
min-width: 0;
border: 0;
border-radius: 0;
background: transparent;
text-align: left;
}
.page-choice span,
.page-choice small {
max-width: 11rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.page-choice small {
color: var(--scan-muted);
}
.drag-hint {
position: absolute;
right: 2.6rem;
color: var(--scan-muted);
cursor: grab;
}
.icon-button {
width: 2.45rem;
border: 0;
border-left: 1px solid var(--scan-line);
border-radius: 0;
background: transparent;
font-size: 1.3rem;
}
.microcopy {
margin: 0.35rem 0;
color: var(--scan-muted);
font-size: 0.84rem;
line-height: 1.45;
}
.preview-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.8rem;
margin: 1rem 0;
}
.preview-card {
min-width: 0;
padding: 0.8rem;
}
.preview-card h3 {
margin: 0;
font-size: 1rem;
}
.source-stage,
.processed-stage {
position: relative;
display: grid;
place-items: center;
width: 100%;
max-height: 28rem;
overflow: hidden;
border-radius: 0.6rem;
background-color: #3c4146;
background-image:
linear-gradient(45deg, #454b50 25%, transparent 25%),
linear-gradient(-45deg, #454b50 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #454b50 75%),
linear-gradient(-45deg, transparent 75%, #454b50 75%);
background-size: 20px 20px;
background-position:
0 0,
0 10px,
10px -10px,
-10px 0;
}
.source-stage img {
display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
.source-stage svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
touch-action: none;
}
.source-stage polygon {
fill: color-mix(in srgb, var(--scan-accent) 15%, transparent);
stroke: #6af8dc;
stroke-width: 0.65;
vector-effect: non-scaling-stroke;
}
.source-stage circle {
fill: #fff;
stroke: #08776b;
stroke-width: 0.8;
vector-effect: non-scaling-stroke;
cursor: move;
}
.source-stage text {
pointer-events: none;
fill: #092b28;
font-size: 3px;
font-weight: 900;
text-anchor: middle;
dominant-baseline: central;
}
.processed-stage {
min-height: 12rem;
}
.processed-stage canvas {
display: block;
max-width: 100%;
max-height: 28rem;
width: auto;
height: auto;
}
.controls-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.8rem;
border: 1px solid var(--scan-line);
border-radius: 0.9rem;
padding: 0.8rem;
}
.controls-grid legend {
padding: 0 0.35rem;
font-weight: 800;
}
.controls-grid label,
.export-card label {
display: grid;
gap: 0.3rem;
font-weight: 700;
font-size: 0.9rem;
}
.controls-grid output,
.export-card output {
justify-self: end;
color: var(--scan-muted);
font-variant-numeric: tabular-nums;
}
.action-panel {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.8rem;
margin-top: 0.8rem;
}
.action-panel > section,
.ocr-result {
padding: 0.9rem;
}
.action-panel h3 {
margin: 0;
}
.action-panel p {
color: var(--scan-muted);
}
.button-row {
display: flex;
flex-wrap: wrap;
gap: 0.45rem;
}
.consent {
display: flex;
gap: 0.5rem;
align-items: flex-start;
margin-bottom: 0.65rem;
}
.consent input {
margin-top: 0.2rem;
}
.ocr-result {
margin-top: 0.8rem;
}
.ocr-result textarea {
display: block;
width: 100%;
min-height: 12rem;
margin: 0.7rem 0;
resize: vertical;
border: 1px solid var(--scan-line);
border-radius: 0.7rem;
background: var(--scan-soft);
color: var(--scan-ink);
padding: 0.7rem;
}
.export-card {
display: grid;
gap: 0.8rem;
}
.export-card .primary {
background: var(--scan-accent);
color: #fff;
}
.loading {
width: min(100%, 90rem);
margin: 2rem auto;
padding: 1rem;
}
.help-dialog {
width: min(92vw, 42rem);
border: 1px solid var(--scan-line);
border-radius: 1rem;
background: var(--scan-panel);
color: var(--scan-ink);
padding: 1.2rem;
}
.help-dialog::backdrop {
background: rgb(0 0 0 / 0.52);
}
.dialog-heading {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
}
.dialog-heading h2 {
margin: 0.2rem 0;
}
.dialog-heading button {
min-width: 2.65rem;
font-size: 1.3rem;
}
@media (max-width: 72rem) {
.workspace-grid {
grid-template-columns: 14rem minmax(0, 1fr);
}
.export-card {
position: static;
grid-column: 1 / -1;
max-height: none;
grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: end;
}
.export-card > :is(.eyebrow, h2, .microcopy) {
grid-column: 1 / -1;
}
}
@media (max-width: 52rem) {
.intro-card {
align-items: stretch;
flex-direction: column;
}
.file-button {
justify-content: center;
}
.workspace-grid,
.preview-grid,
.action-panel {
grid-template-columns: 1fr;
}
.pages-card,
.export-card {
position: static;
max-height: none;
}
.controls-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 34rem) {
.workbench {
padding: 0.65rem;
}
.section-heading {
align-items: flex-start;
flex-direction: column;
}
.controls-grid,
.export-card {
grid-template-columns: 1fr;
}
.export-card > :is(.eyebrow, h2, .microcopy) {
grid-column: auto;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
transition: none !important;
}
}