/*
 * THE SHELL THE OWNER'S PAGES SHARE.
 *
 * The console and the every-map list are the same furniture: a narrow column,
 * a heading with a way back, cards, rows, pills, and the locked-out notice for
 * anybody who is not the owner. They are a different job from the measuring
 * app, which is why they are separate pages -- but they are the same job as
 * each other, which is why they are not separate stylesheets.
 *
 * This file exists because they were. The console kept all of this inside its
 * own <style> block, so the every-map page linked styles.css, asked for
 * .card and .entry, and got nothing -- a list of maps rendered as a wall of
 * unstyled text. The classes were right and the rules were somewhere else.
 *
 * Load order: after styles.css, before a page's own <style>. The app's
 * stylesheet defines .pill and .sub for the measuring app and these override
 * them here; a page's own block overrides both, which is where anything that
 * belongs to one page only should live.
 */

body { background: var(--bg); }

.console { max-width: 760px; margin: 0 auto; padding: 16px 16px 40px; }

.conhead {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 14px;
}
.conhead h1 { font-size: 19px; margin: 0; }
.conhead a { font-size: 13px; color: var(--green-dark); }

.locked-out {
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  padding: 20px; text-align: center;
}

.card {
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  padding: 14px; margin-top: 12px;
}
.card h2 { font-size: 14px; margin: 0 0 10px; }

.pill {
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
  padding: 1px 7px; border-radius: 999px; background: #e4f2e5; color: #1f5b22;
}
.pill.free { background: #eef0ee; color: var(--muted); }
/* Amber, so "the photo is not the one they drew on" is spottable while
   flipping through candidates rather than something you have to read. */
.pill.warn { background: #fdf3e0; color: #8a5a00; }

.actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.actions button, .actions input {
  font: inherit; font-size: 12.5px; padding: 6px 10px;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; cursor: pointer;
}
.actions input { width: 76px; cursor: text; }
.actions button:hover { border-color: var(--green); }
/* A note beside the buttons rather than under them: "saved here" belongs to
   the field it describes, and a row of its own reads as a separate fact. */
.actions small { align-self: center; color: var(--muted); font-size: 11.5px; }

.entry { border-top: 1px solid var(--line); padding: 9px 0; font-size: 12.5px; }
.entry:first-of-type { border-top: 0; }
.entry .top { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.entry b { font-size: 13px; }
.entry .meta { color: var(--muted); font-size: 11.5px; }
.entry .note { margin: 4px 0 0; padding: 6px 9px; background: var(--bg); border-radius: 7px; }

.empty { color: var(--muted); font-size: 13px; }

/*
 * ------------------------------------------------- the every-map list only
 *
 * Dense on purpose: that page is for scanning a pile, not for reading one
 * entry.
 */
.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: var(--muted); word-break: break-all; margin-top: 2px;
}
/* A duplicate group is one thing with several rows in it, so it gets one
   border rather than each row getting its own. */
.dupe-group {
  border: 1px solid #e0a4a4; border-radius: 8px; padding: 6px 8px; margin-bottom: 10px;
  background: #fff8f8;
}
/* The copy that is probably not the keeper. Dimmed, never hidden: "probably"
   is doing real work in that sentence. */
.entry.dim { opacity: 0.62; }

/* The stored photograph with its outlines on it. */
.shot {
  display: block; width: 100%; max-width: 320px; height: auto;
  margin-top: 8px; border-radius: 6px; background: #e7ebe7;
}
.ghost.small { padding: 5px 10px; font-size: 13px; margin-top: 6px; }

/*
 * A VERDICT FROM THE LIST, in the colours the console's review card uses for
 * the same two decisions. The same act should not look like a different one
 * because it was reached from a different page.
 */
.verdict-row button.no { background: #f6eceb; border-color: #d3a9a4; color: #7d2d22; }
.verdict-row button.yes { background: #e4f2e5; border-color: #9ec5a1; color: #1f5b22; }
/*
 * ARMED: the first tap on Reject, waiting for the second.
 *
 * Two taps rather than one, because this is a long scrolling list on a
 * touchscreen and a stray thumb should not be able to drop a map out of the
 * training set. It changes colour as well as wording -- a button that only
 * changed its label would be read as having done something already.
 */
.verdict-row button.armed {
  background: #b3261e; border-color: #b3261e; color: #fff; font-weight: 650;
}
.verdict-row { align-items: center; }

/*
 * -------------------------------------- the outline the detector drew
 *
 * The rendering fills its row rather than sitting at thumbnail size. The
 * page's whole purpose is judging whether a shape could be fixed by hand, and
 * a 320px square is too small to see whether an edge is crisp or crumbly.
 */
.shot.pred { max-width: 100%; border-radius: 8px; }

/*
 * THE LEGEND IS LOAD-BEARING. Two colours carry the entire meaning of every
 * picture below, and a reader who guesses them backwards takes away the
 * opposite conclusion. Swatches rather than words alone, so the mapping is
 * checked by eye against the image rather than remembered.
 */
/*
 * WHICH RUN, AND WHICH OF ITS TWO PICTURES.
 *
 * Wraps rather than scrolls, because on a phone the picker holds a date, a
 * model name and a score and there is no width where all three and a button
 * fit on one line. The button drops under the picker and both stay full-sized
 * targets instead of being squeezed into a row nobody can hit.
 */
.runbar {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end;
  margin: 12px 0 8px;
}
.runpick { display: flex; flex-direction: column; gap: 4px; flex: 1 1 220px; }
.runpick span { font-size: 12.5px; color: var(--muted); }
.runpick select {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: #fff; color: var(--ink); font: inherit; font-size: 14px;
  max-width: 100%;
}
.runbar .ghost { border-radius: 8px; white-space: nowrap; }
/* Pressed reads as "the mask is what you are looking at", so it has to be
   unmistakable at a glance -- the two pictures are similar enough that the
   button is the only thing saying which one is on screen. */
.runbar .ghost[aria-pressed="true"] {
  background: #fdeee9; border-color: var(--ai, #e2725b); color: #9c3b22;
  font-weight: 600;
}
.runbar .ghost:disabled { opacity: .55; }

.legend {
  display: grid; gap: 5px; margin: 10px 0 4px;
  font-size: 12.5px; color: var(--muted);
}
.legend span { display: flex; align-items: center; gap: 7px; }
.sw {
  flex: none; width: 15px; height: 15px; border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, .15);
}
/* The property line. White on a photograph, so the swatch needs a darker
   surround to be visible against this page's own background. */
.sw-parcel { background: #fff; border-color: #6b7770; box-shadow: inset 0 0 0 3px #47524c; }
/* The same values tools/render-prediction.js paints with, which are in turn
   the console's own REVIEW_COLOURS. If one moves, the others have to: a legend
   that disagrees with the picture is worse than none. */
.sw-trace { background: rgb(226, 114, 91); }
/* The wash, so the swatch is the weight it is drawn at rather than the flat
   colour -- a solid green square would read as "this is filled in". */
.sw-truth { background: rgb(78, 194, 106); opacity: .45; }
.sw-inf { background: transparent; border: 2px solid rgb(179, 136, 255); }
.sw-out { background: #6b736b; }

/* The editing cost, in the row's second line: pieces and handles. Monospaced
   digits so a column of them can be compared by eye while scrolling. */
.cost { font-variant-numeric: tabular-nums; }

.empty-state { margin-top: 12px; }

/*
 * ------------------------------------------- opening a rendering full size
 *
 * WHY THIS EXISTS. The published PNG is 1280 px and the column on a phone is
 * about 360, so the list shows roughly a quarter of the detail in each
 * direction -- and everything worth arguing about on this page lives at that
 * scale: whether an edge is crisp or crumbly, whether a patch of canopy is one
 * tree or three, whether a stitched frame has a seam down it.
 */
.shotwrap { position: relative; }

/* The two controls sit ON the picture rather than under it, because a row of
   buttons per entry down a list of thirty-three is more furniture than list. */
.shotopen, .shotwrap .ghost.tiny {
  position: absolute; bottom: 8px;
  font: inherit; font-size: 12px; line-height: 1;
  padding: 6px 9px; border-radius: 8px; cursor: pointer;
  background: rgba(255, 255, 255, .92); border: 1px solid rgba(0, 0, 0, .18);
  color: var(--ink);
}
.shotopen { right: 8px; font-size: 15px; padding: 5px 9px; }
/* THIS LAWN'S OWN FLIP. The page-wide one at the top is a long scroll away
   when the thing you are comparing is a single picture. */
.shotwrap .ghost.tiny { left: 8px; font-weight: 600; }
.shotwrap .ghost.tiny[aria-pressed="true"] {
  background: rgba(253, 238, 233, .95); border-color: var(--ai, #e2725b); color: #9c3b22;
}
.shot.pred { cursor: zoom-in; }

.lightbox {
  position: fixed; inset: 0; z-index: 90;
  background: #0d100e; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  /* The browser must not claim the gestures -- every one of them is ours. */
  touch-action: none; overscroll-behavior: contain;
}
.lightshot {
  max-width: 100vw; max-height: 100vh;
  /* Crisp on purpose past 1:1. Smoothing a mask's edge is smoothing the exact
     thing somebody opened this to look at. */
  image-rendering: pixelated;
  transform-origin: center center; will-change: transform;
  user-select: none; -webkit-user-drag: none;
}
.lightclose {
  position: absolute; top: max(10px, env(safe-area-inset-top)); right: 10px;
  width: 42px; height: 42px; border-radius: 999px; cursor: pointer;
  font-size: 17px; line-height: 1;
  background: rgba(255, 255, 255, .92); border: 0; color: #1d2320;
}
.lighthint {
  position: absolute; bottom: max(12px, env(safe-area-inset-bottom));
  left: 0; right: 0; text-align: center; pointer-events: none;
  font-size: 11.5px; color: rgba(255, 255, 255, .62);
}
/* The page behind must not scroll while a picture is open, or closing it
   leaves you somewhere else in the list. */
body.lightbox-open { overflow: hidden; }

/* ------------------------------------------------ predictions: the layers */
.layerbar { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.layerbar label {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12.5px; padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: #fff; color: var(--muted);
}
.layerbar label.on { color: #1d2320; border-color: #9aa39d; font-weight: 600; }
.layerbar input { margin: 0; }
.layerbar i { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }
.layerbar .allnone { font-size: 12px; }
.stack { position: relative; width: 100%; line-height: 0; }
.stack > img { display: block; width: 100%; height: auto; }
.stack > .layer {
  position: absolute; inset: 0; background-repeat: no-repeat; pointer-events: none;
}
.shot.pred.stack { cursor: zoom-in; border-radius: 8px; overflow: hidden; }
.lightshot.stack {
  width: min(100vw, calc(100vh * var(--ar)));
  max-width: none; max-height: none;
}
.lightshot.stack > .layer, .lightshot.stack > img { image-rendering: pixelated; }
.coords { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.coords .ghost.tiny { margin: 0; padding: 2px 8px; font-size: 11.5px; }
