/* Generated from src/shared/style.ts. */

:root {
  /* Note what is NOT toned down with the rest: --surface stays #ffffff, so a
     page stays the brightest thing on the screen and the desk sits under it.
     Every other neutral here is a low-saturation grey, so it never competes
     with a highlighter ink it has to sit behind. */
  --ground:   #f3f4f4;   /* the desk */
  --panel:    #fafbfc;   /* the tool's own surfaces sit on it */
  --surface:  #ffffff;   /* paper, and nothing else */
  --ink:      #1c1e1b;
  --muted:    #616460;
  --faint:    #616460;
  --rule:     #e2e4e5;
  --rule-2:   #8e928f;
  --accent:   #3d4657;   /* graphite */
  --accent-2: #5c6472;

  --alarm:    #8a3a2a;   /* the only place this palette raises its voice */

  /* Paper on a desk, not a floating card. A single crisp line, no blur: the
     sheet reads as a sheet because the ground behind it is a real mid-tone,
     which is what was doing the work all along. */
  --lift:     0 0 0 1px var(--rule-2);

  /* The one number that makes a control thumb-sized. */
  --tap:      44px;

  --sans: "Source Sans 3", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono: "Source Code Pro", ui-monospace, SFMono-Regular, Menlo, monospace;
}

* { box-sizing: border-box; }

html, body { background: var(--ground); color: var(--ink); }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

::selection { background: var(--accent); color: #fff; }

/* The bottom padding used to be 5rem, which was room for nothing. On a phone
   the download bar is fixed to the viewport and the shell reserves its measured
   height instead, through --bar-h. */
.shell { max-width: 48rem; margin: 0 auto; padding: 1.5rem 1.25rem 3rem; }

/* ------------------------------- typography ------------------------------- */

h1 {
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0 0 0.2rem;
}
@media (min-width: 40rem) { h1 { font-size: 1.6rem; } }

/* Sans and a gentle tracking rather than letterspaced mono. The mono
   uppercase read as machine output; these are just section labels. */
.eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 0.55rem;
}

a { color: var(--accent); text-decoration: underline; text-decoration-color: var(--rule-2); text-underline-offset: 3px; transition: text-decoration-color .15s; }
a:hover { text-decoration-color: var(--accent); }

/* Reduced, not removed. With the sub-header gone these rules are the only thing
   separating the regions, so the line stays and the air around it shrinks. */
.section { border-top: 1px solid var(--rule); padding-top: 1rem; margin-top: 1.1rem; }
header.masthead { padding-bottom: 0.1rem; }

/*
 * The one thing an engine below the floor is shown.
 *
 * The head script puts .too-old on the root element when it cannot compile a
 * class static block, which is where pdf.js stops being parseable and where no
 * polyfill can reach. The rest of the tool goes away with the same class: a
 * drop zone that will reject every file is worse than saying so plainly.
 */
.too-old-note { display: none; }
html.too-old .too-old-note { display: block; margin: 0.6rem 0 0; color: var(--muted); max-width: 46ch; }
html.too-old .section,
html.too-old .download,
html.too-old .bar-spacer { display: none; }

/* -------------------------------- controls ------------------------------- */

/* An invitation, not a boundary: a light dash with air around it. The radius
   is 8px, the ceiling for this family; 12px started to read as a bubble. */
.drop {
  display: block;
  border: 1px dashed var(--rule-2);
  border-radius: 8px;
  background: var(--panel);
  padding: 1.5rem 1.25rem;
  text-align: center;
  color: var(--muted);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.drop:hover, .drop.over { border-color: var(--accent); background: #fbf9f8; }
.drop strong { display: block; font-size: 1.05rem; font-weight: 600; color: var(--ink); margin-bottom: 0.3rem; }
.drop small { display: block; max-width: 34rem; margin: 0 auto; font-size: 0.88rem; line-height: 1.5; color: var(--muted); }
input[type=file] { display: none; }

/* Every button clears 44px. These were 34-41px, which is under a fingertip on
   the device this tool is mostly used on: a phone. */
.action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  font-family: var(--sans);
  font-size: 0.92rem;
  font-weight: 600;
  border-radius: 6px;
  padding: 0 1.25rem;
  cursor: pointer;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform .1s ease, background .15s, border-color .15s, color .15s;
}
/* The tactile press. Transform only, so it never triggers layout. */
.action:active:not(:disabled) {
  transform: scale(0.98);
}
.action { background: var(--accent); color: #fff; border: 1px solid var(--accent); }
.action:hover:not(:disabled) { background: var(--accent-2); border-color: var(--accent-2); color: #fff; }
.action:disabled { background: transparent; color: var(--faint); border-color: var(--rule-2); cursor: not-allowed; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* -------------------------------- progress ------------------------------- */

.status { display: flex; align-items: center; gap: 0.55rem; font-size: 0.9rem; color: var(--muted); margin-top: 0.9rem; }
.spinner { width: 0.8rem; height: 0.8rem; flex: none; border-radius: 50%; border: 2px solid var(--rule-2); border-top-color: var(--accent); animation: spin .9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 3s; } * { scroll-behavior: auto !important; } }

.note { font-size: 0.85rem; color: var(--faint); margin: 0.7rem 0 0; max-width: 62ch; }
.error { border-left: 2px solid var(--alarm); background: #f6e3dd; color: var(--ink); padding: 0.65rem 0.85rem; font-size: 0.9rem; margin-top: 0.9rem; border-radius: 0 4px 4px 0; }

/* ------------------------------ a page on screen -------------------------- */

/*
 * A page and the marks on it, at any of four rotations.
 *
 * .shot is the slot: it reserves the footprint the page occupies AFTER the
 * rotation, so a portrait page turned sideways widens its box instead of
 * spilling out of it. --ar is that footprint's width over height.
 *
 * .shot-inner is the page itself, centred in the slot and turned by --rot. The
 * image and every highlight live inside it, so they turn together and a mark
 * never has to be re-computed for a rotation. Its width and height are set
 * inline, because for a quarter turn they are the slot's own two numbers
 * swapped.
 *
 * touch-action: none belongs ONLY to the slot that is being drawn on, which is
 * .shot.drawing in the marking view. Without it a touch drag scrolls the page
 * instead of drawing.
 *
 * It must NOT reach the thumbnails. The same .shot markup builds both, and a
 * page tile has nothing to draw on, so there the rule only cancels scrolling:
 * a finger landing anywhere on a page in the strip does nothing at all, and
 * most of a phone screen is page. Reported from a real phone as "like I'm
 * clicking a button that doesn't do anything", which is exactly right.
 *
 * The two beside it cover what touch-action does not, and are scoped the same
 * way. Holding a finger still on an image for about half a second pops the iOS
 * Save Image sheet and cancels the drag, and touch-action has no say in that;
 * -webkit-touch-callout is what turns it off. user-select stops a slow drag
 * selecting the page around it instead of drawing on it. On a thumbnail both
 * are ordinary browser behaviour worth keeping.
 */
.shot {
  position: relative; width: 100%; margin: 0 auto; aspect-ratio: var(--ar);
}
.shot.drawing {
  cursor: crosshair;
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.shot-inner { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) rotate(var(--rot)); line-height: 0; }
.shot-inner img { width: 100%; height: 100%; display: block; }

.hl { position: absolute; border-radius: 1px; pointer-events: none; mix-blend-mode: multiply; }
.hl.on { outline-width: 3px; }
.hl.flash { animation: flash 1.1s ease-out 2; }
@keyframes flash { 0%,100% { opacity: 1; } 50% { opacity: .2; } }
.ghost-box { position: absolute; border: 1px dashed var(--ink); background: rgba(36,31,22,.08); pointer-events: none; }

/* ---------------------------- combiner page grid -------------------------- */

/* The minimum went from 10.5rem to 12.5rem to fit five footer buttons. At
   10.5rem five buttons came out around 30px each, which is not a fingertip. */
.sheets { display: grid; grid-template-columns: repeat(auto-fill, minmax(12.5rem, 1fr)); gap: 0.9rem; align-items: stretch; }
.sheet { border: 1px solid var(--rule-2); border-radius: 4px; background: var(--surface); overflow: hidden; box-shadow: var(--lift); display: flex; flex-direction: column; }
.sheet-head { display: flex; justify-content: space-between; gap: 0.4rem; align-items: baseline; font-size: 11px; color: var(--faint); padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--rule); background: #fbfaf9; }
.sheet-head .n { color: var(--ink); font-weight: 500; }
.sheet-head .from { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; letter-spacing: 0; }
/* The desk colour, not paper. It shows only where the page does not reach: a
   page far off square once it is capped below, and a short page sharing a row
   with a tall one. Paper there would read as part of the page. */
.sheet-body { line-height: 0; flex: 1; background: var(--ground); position: relative; }

/*
 * The marking button, over the page's top right corner.
 *
 * It sits on top of the page, so it cannot borrow the page's colours: a white
 * receipt and a dark scan are both underneath it. Panel fill plus a rule
 * border, the same pair the footer buttons use, keeps it legible on either.
 *
 * 44px square, the tap floor, and far enough from the page edge that a thumb
 * reaching for it does not catch the tile border instead.
 */
.sheet-edit {
  position: absolute; z-index: 2; top: 0.4rem; right: 0.4rem;
  width: var(--tap); height: var(--tap);
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--rule-2); border-radius: 4px;
  background: var(--panel); color: var(--faint);
  font-size: 1rem; font-family: var(--sans); line-height: 1;
  cursor: pointer; box-shadow: var(--lift);
  -webkit-tap-highlight-color: transparent;
}
.sheet-edit:hover { color: var(--accent); border-color: var(--accent); }
/* A page carrying marks says so from the strip, without opening anything. */
.sheet-edit.on { color: var(--accent); border-color: var(--accent); background: var(--surface); }
/*
 * A page can be any shape, and a till-roll scan really is about 1 by 32.
 *
 * The slot takes its height from its width and its aspect ratio, so left alone
 * one such page is eleven thousand pixels of tile on a phone: its own buttons
 * are thirteen screens below it, and so is every page after it. The cap is on
 * the WIDTH, worked back from the height allowed and the page's own ratio,
 * which is the idiom the marking view already uses. Capping the height instead
 * would leave the slot wide and the page stretched, and every mark on it would
 * be drawn against a frame that is no longer the page's shape.
 *
 * Anything close to a normal page is far under this and never notices.
 */
.sheet-body .shot { max-width: min(100%, calc(60vh * var(--ar))); }
.sheet-foot { display: flex; flex-wrap: wrap; gap: 0.2rem; padding: 0.35rem; border-top: 1px solid var(--rule); background: #fbfaf9; }
.sheet-foot button { flex: 1 1 2.1rem; min-height: var(--tap); border: 1px solid var(--rule-2); background: var(--panel); border-radius: 3px; font-size: 0.9rem; cursor: pointer; color: var(--faint); font-family: var(--sans); -webkit-tap-highlight-color: transparent; }
.sheet-foot button:hover:not(:disabled) { color: var(--accent); border-color: var(--accent); }
.sheet-foot button:disabled { opacity: .35; cursor: not-allowed; }

/* The way to add more once there are pages. Same width, same height and the
   same corner as a sheet, dashed rather than solid so it reads as an opening
   rather than a page.

   Two mechanisms, because the grid only offers one. align-self: stretch takes
   the full row height wherever the tile shares a row with a sheet. Where it
   does not, which is the whole of a one-column phone layout, there is no row
   to match and --sheet-h carries the measured height of the sheet above it. */
.plus-tile {
  align-self: stretch;
  min-height: var(--sheet-h, 9rem);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.2rem;
  border: 1px dashed var(--rule-2); border-radius: 4px; background: var(--panel);
  color: var(--muted); cursor: pointer; text-align: center; padding: 1rem 0.75rem;
  transition: border-color .15s, background .15s, color .15s;
}
.plus-tile:hover, .plus-tile.over { border-color: var(--accent); color: var(--accent); background: #fbfcfd; }
.plus-tile b { font-size: 1.7rem; font-weight: 400; line-height: 1; }
.plus-tile span { font-size: 0.82rem; line-height: 1.35; }

/* -------------------------------- download -------------------------------- */

/*
 * One control, and on a phone it stays on screen.
 *
 * Fixed rather than sticky on purpose: Chromium's position: sticky stops
 * tracking once anything in its subtree picks up a transform or an overflow,
 * and the page thumbnails are turned with transform: rotate(). A fixed bar has
 * no such failure mode, and the space it would have taken is given back by a
 * spacer whose height is measured off the bar itself and written to --bar-h.
 */
.download { margin-top: 1.4rem; }
.download .action { width: 100%; }
.bar-spacer { height: 0; }
@media (max-width: 39.99rem) {
  .download {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    margin: 0; padding: 0.6rem 1.25rem calc(0.6rem + env(safe-area-inset-bottom));
    background: var(--ground); border-top: 1px solid var(--rule-2);
  }
  .download .note { margin-top: 0.35rem; }
  .download .error { margin-top: 0.5rem; max-height: 4.5rem; overflow: auto; }
  .bar-spacer { height: var(--bar-h, 0px); }
}

/* --------------------------------- modal ---------------------------------- */

.modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center; padding: 0.75rem; background: rgba(20,22,20,.55); }
.modal-card { background: var(--ground); border-radius: 8px; width: 100%; max-width: 46rem; max-height: 100%; overflow: auto; padding: 0.75rem; box-shadow: 0 12px 40px rgba(0,0,0,.3); }
.modal-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; }
.modal-head .who { font-size: 0.85rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.modal-head .close { margin-left: auto; flex: none; min-width: var(--tap); min-height: var(--tap); border: 1px solid var(--rule-2); background: var(--panel); border-radius: 6px; font-size: 1.1rem; cursor: pointer; color: var(--muted); font-family: var(--sans); }
.modal-head .close:hover { color: var(--accent); border-color: var(--accent); }
.modal-stage { background: var(--surface); border: 1px solid var(--rule-2); border-radius: 4px; padding: 0.4rem; }
/* The slot is as wide as the card allows, then as tall as the viewport allows.
   --ar is a plain number, so it works in both places. */
.modal-stage .shot { max-width: min(100%, calc((100svh - 15rem) * var(--ar))); }

.inks { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin: 0.6rem 0; }
.inks .ink { width: var(--tap); height: var(--tap); border-radius: 6px; border: 1px solid var(--rule-2); cursor: pointer; padding: 0; -webkit-tap-highlight-color: transparent; }
.inks .ink.on { border-color: var(--ink); border-width: 3px; }
.inks .hint { font-size: 0.82rem; color: var(--muted); margin-left: 0.2rem; }

.marks { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.6rem; }
.marks .mark { display: inline-flex; align-items: center; gap: 0.4rem; min-height: var(--tap); padding: 0 0.5rem 0 0.55rem; border: 1px solid var(--rule-2); border-radius: 6px; background: var(--panel); font-family: var(--sans); font-size: 0.85rem; color: var(--ink); cursor: pointer; }
.marks .mark.on { border-color: var(--ink); }
.marks .mark i { width: 0.75rem; height: 0.75rem; border-radius: 2px; flex: none; }
.marks .mark b { font-weight: 400; color: var(--muted); }
.marks .drop-mark { border: 0; background: transparent; font-size: 1.05rem; line-height: 1; color: var(--muted); cursor: pointer; padding: 0 0.25rem; min-height: var(--tap); font-family: var(--sans); }
.marks .drop-mark:hover { color: var(--alarm); }

footer { border-top: 1px solid var(--rule); margin-top: 2.5rem; padding-top: 1rem; font-size: 0.82rem; color: var(--faint); line-height: 1.6; }

/* Footer links were 18px tall, which is not a target on a phone. They are 44px
   rows now, laid out as a wrapping list so the row height cannot squeeze them
   back down. */
footer .links { display: flex; flex-wrap: wrap; align-items: center; gap: 0 0.25rem; margin-top: 0.25rem; }
footer a { color: var(--muted); }
footer a:hover { color: var(--accent); }
footer .links a {
  display: inline-flex; align-items: center; min-height: var(--tap);
  padding-inline: 0.5rem; margin-inline: -0.5rem; border-radius: 6px;
}

/* ------------------------------ prose pages ------------------------------ */

.prose h1 { margin-bottom: 1.1rem; }
.prose h2 { font-size: 1rem; font-weight: 600; margin: 1.6rem 0 0.4rem; }
.prose p, .prose li { color: var(--muted); font-size: 0.95rem; }
.prose ul { padding-left: 1.1rem; }
