@charset "UTF-8";
/* The clustering page: one long-running job, made legible.
 *
 * Everything here exists to answer "is this actually working?" for someone
 * watching a five-minute progress bar. That means: a bar that always moves, a
 * named stage, a live detail line that changes every photo, and counters that
 * prove work is happening even when the percentage is slow.
 */

.cl-wrap { max-width: 860px; margin: 0 auto; padding: 48px 20px 80px; }
.cl-head { display: flex; align-items: center; gap: 10px; margin-bottom: 26px; }
.cl-head .brand { font-size: 19px; font-weight: 650; letter-spacing: -.01em; }
.cl-head .spacer { flex: 1; }

.cl-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 14px; padding: 26px; margin-bottom: 18px;
}
.cl-card h1 { font-size: 26px; line-height: 1.2; margin: 0 0 10px; letter-spacing: -.02em; }
.cl-card h2 { font-size: 16px; margin: 0 0 12px; }
.cl-card p { margin: 0 0 12px; color: var(--muted); }
.cl-card p.tight { margin-bottom: 6px; }
.cl-card > :last-child { margin-bottom: 0; }

.cl-steps { list-style: none; padding: 0; margin: 0 0 18px; }
.cl-steps li { display: flex; gap: 11px; align-items: flex-start; margin-bottom: 11px; color: var(--muted); }
.cl-steps .n {
  flex: none; width: 21px; height: 21px; border-radius: 50%; background: var(--panel-2);
  border: 1px solid var(--border); font-size: 11px; font-weight: 700; color: var(--text);
  display: grid; place-items: center; margin-top: 1px;
}

button.primary {
  background: var(--accent); color: var(--accent-text); border-color: var(--accent);
  font-weight: 650; padding: 10px 18px; font-size: 15px;
}
button.primary:hover { background: #ffc451; border-color: #ffc451; }
button.primary:disabled { opacity: .5; cursor: not-allowed; }
button.ghost { background: transparent; border-color: var(--border); padding: 9px 16px; }
button.ghost:hover { background: var(--panel-2); }
/* Stop is not destructive -- progress is checkpointed -- so it reads as a
   plain secondary action with a red tint, not a red-filled danger button. */
button.ghost.danger { color: #ff8d90; border-color: #5a2a2c; }
button.ghost.danger:hover { background: #241a1c; border-color: #7a3a3c; }

/* ---------- progress ---------- */
.cl-stagerow { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.cl-stagerow .name { font-size: 17px; font-weight: 600; }
.cl-stagerow .pct { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--muted); font-size: 15px; }

.cl-bar {
  height: 10px; border-radius: 999px; background: var(--panel-2);
  border: 1px solid var(--border); overflow: hidden; position: relative;
}
.cl-bar > i {
  display: block; height: 100%; width: 0%; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), #ffd479);
  transition: width .25s ease;
}
/* When there is no meaningful percentage yet, sweep instead of sitting at 0. */
.cl-bar.indet > i { width: 35% !important; animation: cl-sweep 1.25s ease-in-out infinite; }
@keyframes cl-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(340%); }
}

/* One row under the bar: what is being worked on, and how long we have been at
   it. Sharing a line keeps the clock beside the bar it measures without costing
   any vertical space. */
.cl-underbar { display: flex; align-items: baseline; gap: 14px; margin-top: 9px; }
.cl-elapsed {
  flex: none; margin-left: auto; font-size: 12.5px; color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums; opacity: .85;
}
/* Escaped rather than literal: a CSS file carries no encoding of its own,
   and served as plain text/css the browser fell back to a legacy encoding
   and rendered the three UTF-8 bytes of U+23F1 as "â ±". An escape is
   immune to that regardless of how the file is served. */
.cl-elapsed::before { content: "\23F1"; margin-right: 5px; opacity: .65; }
.cl-detail {
  flex: 1; min-width: 0; font-size: 12.5px; color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* rtl truncates the START of a long path so the filename stays visible;
     plaintext keeps the characters themselves in their logical order. */
  direction: rtl; text-align: left; unicode-bidi: plaintext;
}

.cl-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 18px; }
.cl-stats .s {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 9px;
  padding: 11px 12px; text-align: center;
}
.cl-stats .s b { display: block; font-size: 19px; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.cl-stats .s span { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; }
@media (max-width: 620px) { .cl-stats { grid-template-columns: repeat(2, 1fr); } }

/* the staged checklist, so the user can see where they are in the whole job */
.cl-phases { display: flex; gap: 6px; margin: 18px 0 0; flex-wrap: wrap; }
.cl-phase {
  font-size: 11.5px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--panel-2); color: var(--muted);
}
.cl-phase.active { border-color: var(--accent); color: var(--accent); }
.cl-phase.done { border-color: #2f5b3a; color: var(--ok); }
.cl-phase.done::before { content: "\2713"; margin-right: 4px; }

.cl-log {
  margin-top: 16px; max-height: 148px; overflow-y: auto; font-size: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: #15161a; border: 1px solid var(--border); border-radius: 9px; padding: 11px 13px;
}
.cl-log div { color: var(--muted); padding: 1px 0; }
.cl-log div.warn { color: var(--accent); }

.cl-note {
  display: flex; gap: 9px; align-items: flex-start; font-size: 12.5px;
  color: var(--muted); margin-top: 14px; padding: 11px 13px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 9px;
}
.cl-note.bad { border-color: #5a2a2c; background: #241a1c; }
.cl-note.ok { border-color: #2f5b3a; background: #18211a; }
.cl-note .ico { flex: none; }

.cl-blocked h1 { color: var(--danger); }
.cl-check { list-style: none; padding: 0; margin: 14px 0 0; }
.cl-check li { padding: 7px 0; border-top: 1px solid var(--border); display: flex; gap: 9px; align-items: center; }
.cl-check li:first-child { border-top: none; }
.cl-check .mark { flex: none; width: 17px; }
.cl-check .yes { color: var(--ok); }
.cl-check .no { color: var(--danger); }

.cl-done .big { font-size: 40px; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.cl-actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 18px; }

/* The run log, kept available after the run finishes. It used to live only on
   the progress screen, which is hidden the moment the run completes -- so the
   timings and skipped-file warnings disappeared exactly when someone would
   want to read them. */
.cl-details { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 14px; }
.cl-details summary { cursor: pointer; font-size: 13px; color: var(--muted); user-select: none; }
.cl-details summary:hover { color: var(--text); }
.cl-details .cl-log { margin-top: 10px; max-height: 220px; }
.cl-details .cl-actions { margin-top: 10px; }

/* ===================================================================== */
/* Confirm, preview and unlock.                                          */
/*                                                                       */
/* The order on screen is deliberate and is the whole argument: what we   */
/* found, then their own faces, then two people they can open for        */
/* nothing, and only then the price. Money is never the first thing on   */
/* a screen the user has waited twenty minutes to reach.                 */
/* ===================================================================== */

.cl-confirm-counts {
  font-size: 15px; color: var(--text); font-variant-numeric: tabular-nums;
  margin-bottom: 14px;
}
.cl-pricenote { margin-top: 14px; }

/* What it costs, and -- just as important -- when.
   The "you only pay after it finishes" half used to be the tail of a sentence,
   where it read as small print. It is the reassurance that makes the price
   acceptable, so it gets its own line and its own tick. */
.cl-price {
  display: flex; gap: 14px; align-items: center;
  border: 1px solid #5a4a1c; background: #2a2414;
  border-radius: 12px; padding: 14px 16px; margin: 18px 0;
}
.cl-price .amount {
  flex: none; font-size: 30px; font-weight: 700; color: var(--accent);
  letter-spacing: -.03em; line-height: 1;
}
.cl-price-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cl-price-body b { font-size: 15px; font-weight: 650; color: var(--text); }
.cl-price-after {
  font-size: 12.5px; color: #ffd98a; line-height: 1.4;
}
.cl-price-after::before { content: "\2713"; font-weight: 700; margin-right: 6px; }

/* Three short lines beat one long sentence: each is a separate claim, and the
   one that matters most is the one people are scanning for. */
.cl-what { list-style: none; padding: 0; margin: 0 0 4px; }
.cl-what li {
  display: flex; gap: 10px; align-items: flex-start;
  color: var(--muted); font-size: 13.5px; line-height: 1.55; margin-bottom: 8px;
}
.cl-what .ico { flex: none; width: 18px; text-align: center; }
.cl-what strong { color: var(--text); }

button.primary.big { padding: 13px 24px; font-size: 16px; }

/* --- the face wall: their own results, as the first thing they see --- */
.cl-facewall { margin: 20px 0 22px; }
.cl-faces {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.cl-face { margin: 0; width: 72px; }
.cl-face img {
  width: 72px; height: 72px; border-radius: 50%; object-fit: cover; display: block;
  background: var(--panel-2); border: 1px solid var(--border);
}
.cl-face figcaption {
  font-size: 11px; color: var(--muted); text-align: center; margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
/* The overflow count sits IN the strip as another circle, so it lines up with
   the faces. As a paragraph under a wrapping flex row it aligned with nothing. */
.cl-more-circle {
  width: 72px; height: 72px; border-radius: 50%;
  background: var(--panel-2); border: 1px dashed var(--border);
  display: grid; place-items: center;
  font-size: 15px; font-weight: 650; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.cl-face-more figcaption { color: var(--muted); }

/* --- the two free people --- */
.cl-free {
  border-top: 1px solid var(--border); padding-top: 20px; margin: 22px 0;
}
.cl-free-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 14px; }
.cl-free-card {
  display: flex; align-items: center; gap: 12px; text-decoration: none;
  border: 1px solid var(--border); background: var(--panel-2);
  border-radius: 12px; padding: 12px 18px 12px 12px; color: var(--text);
  flex: 1 1 220px; min-width: 0;
}
.cl-free-card:hover { border-color: var(--accent); }
.cl-free-card img {
  width: 56px; height: 56px; border-radius: 50%; object-fit: cover; flex: none;
  background: var(--panel); border: 1px solid var(--border);
}
.cl-free-card span { font-size: 13px; color: var(--muted); line-height: 1.5; }
.cl-free-card b { color: var(--text); font-size: 15px; font-weight: 650; }

/* --- the ask --- */
.cl-unlock {
  border: 1px solid var(--border); background: var(--panel-2);
  border-radius: 12px; padding: 18px; margin: 22px 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
}
.cl-unlock p { margin: 0; }

/* --- the key itself --- */
.cl-keybox {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  border: 1px solid var(--border); background: var(--panel-2);
  border-radius: 12px; padding: 16px 18px; margin: 16px 0 10px;
}
.cl-keybox code {
  font-size: 19px; font-weight: 650; letter-spacing: 1.5px;
  font-variant-ligatures: none; word-break: break-all; color: var(--text);
}

@media (max-width: 560px) {
  .cl-face, .cl-face img, .cl-more-circle { width: 56px; }
  .cl-face img, .cl-more-circle { height: 56px; }
  .cl-free-card { flex-basis: 100%; }
  .cl-keybox code { font-size: 16px; letter-spacing: 1px; }
}

/* ---------- the unlock page ---------- */
.cl-buy-summary {
  display: flex; align-items: stretch; gap: 10px; flex-wrap: wrap;
  margin: 18px 0;
}
.cl-buy-stats { display: flex; gap: 10px; flex: 1 1 220px; }
.cl-buy-stats .s {
  flex: 1; background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 12px; padding: 14px 16px;
}
.cl-buy-stats .s b {
  display: block; font-size: 24px; font-weight: 700; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.cl-buy-stats .s span { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.cl-buy-price {
  flex: 0 1 200px; display: flex; align-items: center; gap: 12px;
  background: #2a2414; border: 1px solid #5a4a1c; border-radius: 12px;
  padding: 14px 18px;
}
.cl-buy-price b { font-size: 32px; font-weight: 700; color: var(--accent); letter-spacing: -.03em; line-height: 1; }
.cl-buy-price span { font-size: 12px; color: #ffd98a; line-height: 1.4; }

.cl-card .open-form label { display: block; font-size: 13.5px; margin-bottom: 6px; }
.cl-card .open-form input[type=email] { width: 100%; }
button.primary.big.block { width: 100%; margin-top: 14px; }

.cl-reassure { list-style: none; padding: 0; margin: 16px 0 0; }
.cl-reassure li {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: 12.5px; color: var(--muted); line-height: 1.5; margin-bottom: 7px;
}
.cl-reassure .ico { flex: none; }

/* "Nothing to pay, nothing to enter" was the tail of a muted sentence, which
   is where a reader stops. It is the whole offer, so it reads as a label. */
.cl-free-badge {
  display: inline-block; vertical-align: 2px; margin-left: 8px;
  background: #18211a; border: 1px solid #2f5b3a; border-radius: 999px;
  padding: 3px 11px; font-size: 11.5px; font-weight: 650; letter-spacing: .01em;
  color: #a8dcb6;
}
@media (max-width: 560px) {
  .cl-free-badge { display: block; margin: 8px 0 0; width: fit-content; }
}
