/* Crossword Digitization — mobile-first, single stepper flow for all viewports.
   Stage visibility is driven purely by body[data-stage]; desktop differs only
   inside the single media query at the bottom. Logical properties only (RTL). */

:root {
    --color-bg: #fafaf9;
    --color-surface: #ffffff;
    --color-text: #1c1917;
    --color-muted: #78716c;
    --color-border: #e7e5e4;
    --color-accent: #2456a4;
    --color-accent-hover: #1c4586;
    --color-accent-soft: #eef2f8;
    --color-flag: #b45309;
    --color-flag-soft: #fdf6ec;
    --color-error: #b91c1c;
    --color-error-soft: #fdf1f1;
    --color-ok: #15803d;
    --color-paper: #f4efe2;
    --color-ink: #2a241c;
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --radius-card: 12px;
    --radius-control: 8px;
    --shadow-card: 0 1px 3px rgba(28, 25, 23, 0.07);
}

* { box-sizing: border-box; }

/* The hidden attribute must win over any display rule set by a class */
[hidden] { display: none !important; }

body {
    margin: 0;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    font-size: 16px;
    line-height: 1.5;
}

h1 { font-size: 28px; margin: 0 0 var(--space-2); }
h2 { font-size: 22px; margin: 0 0 var(--space-2); }
.hint { color: var(--color-muted); font-size: 14px; margin: 0 0 var(--space-4); }

/* --- Stage visibility: the whole flow mechanism ------------------------- */
body[data-stage="capture"] .stage:not([data-stage="capture"]) { display: none; }
body[data-stage="grid"]    .stage:not([data-stage="grid"])    { display: none; }
body[data-stage="clues"]   .stage:not([data-stage="clues"])   { display: none; }
body[data-stage="export"]  .stage:not([data-stage="export"])  { display: none; }

/* --- Stepper header ------------------------------------------------------ */
#stepper {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border-block-end: 1px solid var(--color-border);
    position: sticky;
    inset-block-start: 0;
    z-index: 10;
}
.step { display: flex; align-items: center; gap: var(--space-1); }
.step-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #d6d3d1;
}
.step-label { font-size: 13px; color: var(--color-muted); }
body[data-stage="capture"] .step[data-step="capture"] .step-dot,
body[data-stage="grid"]    .step[data-step="grid"]    .step-dot,
body[data-stage="clues"]   .step[data-step="clues"]   .step-dot,
body[data-stage="export"]  .step[data-step="export"]  .step-dot {
    background: var(--color-accent);
    outline: 3px solid var(--color-accent-soft);
}
body[data-stage="capture"] .step[data-step="capture"] .step-label,
body[data-stage="grid"]    .step[data-step="grid"]    .step-label,
body[data-stage="clues"]   .step[data-step="clues"]   .step-label,
body[data-stage="export"]  .step[data-step="export"]  .step-label {
    color: var(--color-accent);
    font-weight: 600;
}

/* --- Layout & cards ------------------------------------------------------ */
#work-layout {
    max-width: 640px;
    margin-inline: auto;
    padding: var(--space-4);
    padding-block-end: calc(var(--space-6) * 2);
}
.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    padding: var(--space-4);
    margin-block-end: var(--space-4);
}
.hero { text-align: center; padding-block: var(--space-6); }
.hero .btn-primary, .hero .btn-secondary {
    width: 100%;
    max-width: 360px;
    margin-block-start: var(--space-3);
}
.center-card { text-align: center; padding-block: var(--space-6); }

/* --- Buttons & controls -------------------------------------------------- */
button { font: inherit; }
.btn-primary, .btn-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 48px;
    padding: var(--space-2) var(--space-5);
    border-radius: var(--radius-control);
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s ease;
}
.btn-primary {
    background: var(--color-accent);
    color: #fff;
    border: none;
}
.btn-primary:hover:not(:disabled) { background: var(--color-accent-hover); }
.btn-primary:disabled { background: #a8a29e; cursor: not-allowed; }
.btn-secondary {
    background: var(--color-surface);
    color: var(--color-accent);
    border: 1px solid #b9c7dd;
}
.btn-secondary:hover:not(:disabled) { background: var(--color-accent-soft); }
.btn-link {
    background: none;
    border: none;
    color: var(--color-muted);
    font-size: 14px;
    min-height: 44px;
    cursor: pointer;
    text-decoration: underline;
}
.btn-step {
    width: 44px;
    height: 44px;
    flex: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    background: var(--color-surface);
    font-size: 20px;
    color: var(--color-accent);
    cursor: pointer;
}
.btn-step:active { background: var(--color-accent-soft); }

/* Camera button is pointless with a mouse — hide it there (CSS-only). */
@media (hover: hover) and (pointer: fine) {
    #camera-button { display: none; }
}

/* --- Capture stage ------------------------------------------------------- */
.upload-progress { display: flex; align-items: center; gap: var(--space-3); }
#upload-thumb {
    width: 48px;
    height: 64px;
    object-fit: cover;
    border-radius: var(--space-1);
    border: 1px solid var(--color-border);
    background: var(--color-bg);
}
.upload-progress-body { flex: 1; min-width: 0; font-size: 14px; color: var(--color-muted); }
.progress-bar {
    height: 4px;
    background: var(--color-border);
    border-radius: 2px;
    overflow: hidden;
    margin-block-start: var(--space-2);
}
.progress-fill {
    width: 40%;
    height: 100%;
    background: var(--color-accent);
    border-radius: 2px;
    animation: progress-slide 1.2s ease-in-out infinite;
}
@keyframes progress-slide {
    0%   { margin-inline-start: -40%; }
    100% { margin-inline-start: 100%; }
}

.alert-error {
    background: var(--color-error-soft);
    border: 1px solid #e9b6b6;
    border-radius: var(--radius-card);
    color: var(--color-error);
    padding: var(--space-4);
    margin-block-end: var(--space-4);
}
.alert-error p { margin: 0 0 var(--space-3); color: #7f1d1d; }
.alert-actions { display: flex; gap: var(--space-3); align-items: center; }

/* --- Grid stage ----------------------------------------------------------- */
/* The scan is the point of this stage: compact chrome, canvas gets the rest */
.grid-card { padding: var(--space-3); }
.grid-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
}
.grid-card h2 { font-size: 18px; margin-block-end: 0; }
.grid-card .hint { font-size: 13px; margin-block-end: var(--space-2); }
/* The scan sits in a newspaper-clipping frame: ink-thin rule border, aged
   paper tone behind the (now clip-path-cropped, see applyZoom()) canvas so
   any letterboxed margin reads as blank paper rather than stray page
   content. The rows control sits outside the frame, beside it, styled the
   same as the columns control below — a plain slider, not part of the
   "photo". */
.grid-canvas-row {
    display: flex;
    align-items: stretch;
    gap: var(--space-2);
    margin-block-end: var(--space-2);
}
.grid-frame {
    flex: 1;
    min-width: 0;
    padding: var(--space-2);
    background: var(--color-paper);
    border: 1px solid var(--color-ink);
    border-radius: 3px;
    box-shadow: 0 1px 4px rgba(28, 25, 23, 0.15);
}
/* Fixed height (not max-height): applyZoom() (grid-stage.ts) needs a stable
   viewport to compute its crop scale/offset against. */
#canvas-wrap {
    position: relative;
    height: calc(100dvh - 320px);
    overflow: hidden;
}
/* Zoomed-to-grid: applyZoom() sets position/width/height/left/top inline —
   the crop depends on live viewport + image + grid-rect dimensions, none of
   which are expressible as a static CSS rule. */
#canvas-wrap[data-zoom="false"] #canvas {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.size-control {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-block-end: var(--space-2);
}
.size-control input[type="range"] { flex: 1; min-width: 0; accent-color: var(--color-accent); }
.size-label { font-size: 13px; color: var(--color-muted); white-space: nowrap; min-width: 76px; text-align: center; }
.grid-card .btn-step { width: 38px; height: 38px; font-size: 18px; flex: none; }

/* Rows control runs vertically alongside the canvas: dragging it changes how
   many horizontal grid lines there are, which reads more naturally as an
   up/down motion than the columns slider's left/right one, and it fills the
   canvas's own height instead of squeezing in below it. Same plain styling
   as the columns control otherwise — it's a slider like any other, not part
   of the framed scan. */
.size-control[data-dim="rows"] {
    flex-direction: column;
    align-items: center;
    margin-block-end: 0;
}
.size-control[data-dim="rows"] input[type="range"] {
    writing-mode: vertical-lr;
    direction: rtl;
    flex: 1;
    min-height: 0;
    width: 6px;
    accent-color: var(--color-accent);
}
.size-control[data-dim="rows"] .size-label { min-width: 0; }

/* --- Sticky action bar ---------------------------------------------------- */
.action-bar {
    position: sticky;
    inset-block-end: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    background: color-mix(in srgb, var(--color-surface) 92%, transparent);
    backdrop-filter: blur(6px);
    border-block-start: 1px solid var(--color-border);
    margin-inline: calc(-1 * var(--space-4));
    padding: var(--space-3) var(--space-4);
    padding-block-end: calc(var(--space-3) + env(safe-area-inset-bottom));
}
.action-bar .btn-primary { width: 100%; max-width: 360px; }

/* --- Clue review: intro card, collapsible sections + filter ---------------- */
.stage-intro {
    background: var(--color-accent-soft);
    border: 1px solid #d5e0ef;
    border-radius: var(--radius-card);
    padding: var(--space-3) var(--space-4);
    font-size: 14px;
    line-height: 1.6;
    color: var(--color-text);
    margin-block-end: var(--space-4);
}
.clue-section { margin-block-end: var(--space-2); }
.clue-section > summary {
    list-style: none;
    cursor: pointer;
}
.clue-section > summary::-webkit-details-marker { display: none; }
.clue-section > summary::marker { content: ""; }
.clue-section h2 { display: flex; align-items: center; gap: var(--space-2); font-size: 18px; }
.clue-section h2::after {
    content: '▾';
    margin-inline-start: auto;
    color: var(--color-muted);
    font-size: 14px;
    transition: transform 0.15s ease;
}
.clue-section:not([open]) h2::after { transform: rotate(-90deg); }
.count-badge {
    font-size: 13px;
    font-weight: 400;
    color: var(--color-muted);
}
.clue-list { margin-block-end: var(--space-3); }

/* --- Clue cards ------------------------------------------------------------
   Compact row: the number badge sits at the inline start, vertically centered
   so it spans both the image strip and the text line — mirroring how the
   printed number leads its clue. Tight padding/margins keep many clues on
   one screen. */
.clue-card {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
    padding: var(--space-1) var(--space-2);
    margin-block-end: 6px;
}
.clue-card[data-flagged="true"] { border-inline-start: 4px solid var(--color-flag); }
.clue-card-placeholder { border-style: dashed; }

.clue-card-body { flex: 1; min-width: 0; }
.clue-card-body > .chip-flag { margin-block-end: var(--space-1); }
.clue-number {
    width: 24px;
    height: 24px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--color-accent);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
}

/* --- Chips: length / other / flag / filter toggle --------------------------
   Neutral outlined pills — visually distinct from the filled number badge. */
.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-height: 26px;
    padding-inline: var(--space-2);
    border-radius: 999px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 13px;
    border: 1px solid var(--color-border);
}
.chip-label { color: var(--color-muted); }
.chip input {
    font: inherit;
    font-size: 16px; /* ≥16px prevents iOS focus-zoom */
    color: inherit;
    background: transparent;
    border: none;
    padding: 0;
}
.chip input:focus { outline: none; }
/* Width is set inline per-input by sizeChipInput() (clue-cards.ts), sized to
   content so a longer `other` annotation isn't cut off. dir="ltr" (set in
   HTML) keeps digit-run editing natural (cursor/typing for "4,3" etc.);
   text-align: right is a deliberate exception to logical properties — it
   visually right-aligns the digits to match this RTL page's flow,
   independent of the input's own (intentionally LTR) direction. */
.chip-input-length { text-align: right; }
.chip-flag {
    background: var(--color-flag-soft);
    color: var(--color-flag);
    border-color: transparent;
}
.chip-toggle { cursor: pointer; min-height: 32px; font-size: 13px; }
.chip-toggle input { width: auto; accent-color: var(--color-accent); }
/* Length/other sit beside the text, on the same line — .clue-line is a flex
   row, so this group naturally lands on the LEFT (the row's second child in
   RTL flow), which is where a printed clue's trailing "(5)" actually appears
   ("...מצער (5)"). Borderless/transparent chips here since .clue-line
   already supplies the shared border. */
.clue-card-trailer {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex: none;
    padding-block-end: 2px;
}
.clue-card-trailer .chip {
    background: transparent;
    border-color: transparent;
    min-height: 22px;
    padding-inline: var(--space-1);
}

/* --- Image strip ------------------------------------------------------------
   The canvas keeps its intrinsic aspect ratio: never upscaled beyond the
   source pixels (a one-line strip stays one line tall), shrunk to fit the
   card width or the max height, whichever binds first. */
.clue-strip-wrap {
    width: fit-content;
    max-width: 100%;
    background: var(--color-bg);
    border-radius: var(--radius-control);
    overflow: hidden;
    margin-block-end: 2px;
}
.clue-strip {
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 96px;
}

/* --- Clue line: text + length/other read as one line, the way the length
   hint trails the text in the printed clue ("...מצער (5)") — a flex row so
   the trailer sits beside the text instead of stacked under it. ------------ */
.clue-line {
    display: flex;
    align-items: flex-end;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    background: var(--color-bg);
    overflow: hidden;
}
.clue-line:focus-within { border-color: var(--color-accent); }
.clue-card .clue-text {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
    min-height: 28px; /* fallback if the JS auto-grow hasn't run */
    resize: none;
    overflow: hidden;
    font: inherit;
    font-size: 16px; /* ≥16px prevents iOS focus-zoom */
    border: none;
    padding: 2px var(--space-2);
    background: transparent;
}
.clue-card .clue-text:focus {
    outline: none;
    background: var(--color-surface);
}
.clue-card .clue-text::placeholder { color: var(--color-flag); }

/* --- Export stage ---------------------------------------------------------- */
.spinner {
    display: inline-block;
    width: 22px;
    height: 22px;
    border: 3px solid rgba(255, 255, 255, 0.4);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spinner-rotate 0.8s linear infinite;
}
.spinner-accent {
    border-color: var(--color-accent-soft);
    border-top-color: var(--color-accent);
}
@keyframes spinner-rotate { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .spinner, .progress-fill { animation-duration: 2.5s; }
    .btn-primary, .btn-secondary { transition: none; }
}

/* --- Desktop: same DOM, same machine — just roomier ------------------------ */
@media (min-width: 1024px) {
    #work-layout {
        max-width: 1100px;
        display: grid;
        grid-template-columns: minmax(340px, 42%) 1fr;
        gap: var(--space-5);
        align-items: start;
    }
    .stage { grid-column: 1 / -1; }
    /* While reviewing clues or exporting, keep the scan visible beside them */
    body[data-stage="clues"] .stage[data-stage="grid"],
    body[data-stage="export"] .stage[data-stage="grid"] {
        display: block;
        grid-column: 1;
        position: sticky;
        inset-block-start: 70px;
    }
    body[data-stage="clues"] .stage[data-stage="clues"],
    body[data-stage="export"] .stage[data-stage="export"] { grid-column: 2; }
    /* The side-panel copy of the grid stage is read-only context: the grid is
       committed once the clue stage is entered, so its action bar AND size
       sliders stay in the DOM but don't show */
    body[data-stage="clues"]  .stage[data-stage="grid"] .action-bar,
    body[data-stage="export"] .stage[data-stage="grid"] .action-bar,
    body[data-stage="clues"]  .stage[data-stage="grid"] .size-control,
    body[data-stage="export"] .stage[data-stage="grid"] .size-control { display: none; }
}
