/*
 * Site styles, implementing the Dropdf canvas design.
 *
 * Kept as a plain stylesheet rather than Jaspr's typed CSS: none of it is
 * computed from Dart state, and a real .css file can be edited and cached
 * without recompiling.
 *
 * Values here are taken from the design rather than invented. The design is
 * specified at fixed artboard sizes (1280 desktop, 390 mobile); this
 * translates that into a fluid layout, so the breakpoints below are where the
 * desktop artboard stops working rather than arbitrary device widths.
 */

:root {
  /* Surface. A warm off-white ground with white cards on top, rather than
     white-on-grey: the design leans on that warmth for its whole character. */
  --ground: #f5f3ee;
  --surface: #ffffff;
  --surface-sunken: #fdfdfc;

  /* Ink. Near-black rather than pure black, and two grey steps. */
  --ink: #16161a;
  --ink-secondary: #55555d;
  --ink-muted: #6c6c74;
  --ink-faint: #c8c5be;

  --line: #e6e3dd;
  --line-dashed: #cfcbc3;

  /* The green is reserved for one claim: that the work happens locally.
     Using it for ordinary emphasis would dilute the only thing it says. */
  --local: #2f6f5e;
  --local-bg: #eff5f2;
  --local-line: #c9dcd4;

  /* Failure. Not in the canvas — the design has no error state — so it is
     derived to sit in the same muted, warm register as the rest. */
  --danger: #b4532f;
  --danger-bg: #fbf1ec;

  --radius-card: 10px;
  --radius-panel: 12px;
  --radius-control: 9px;
  --radius-pill: 999px;

  /* Roboto throughout, at the project's request. One family across display,
     body and metadata, so weight and size carry the hierarchy that the
     original three-face pairing carried by contrast. */
  --font-display: Roboto, system-ui, -apple-system, sans-serif;
  --font-body: Roboto, system-ui, -apple-system, sans-serif;
  --font-mono: Roboto, system-ui, -apple-system, sans-serif;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--ink);
  text-decoration: none;
}

a:hover {
  color: var(--local);
}

/* Layout ------------------------------------------------------------------ */

.site {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.site__inner {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 64px;
}

.site__header {
  padding-top: 40px;
  padding-bottom: 28px;
}

.site__header-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.brand {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
}

.brand__name {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.brand__tag {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.site__main {
  flex: 1;
  padding-bottom: 48px;
}

.site__footer {
  padding-top: 20px;
  padding-bottom: 32px;
  border-top: 1px solid var(--line);
}

.site__footer-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
}

.site__footer p {
  margin: 0;
  font-size: 13px;
  color: var(--ink-muted);
  max-width: 640px;
}

.site__footer-links {
  display: flex;
  gap: 24px;
}

.site__footer-links a {
  font-size: 13px;
  color: var(--ink-muted);
}

/* The local-processing badge ---------------------------------------------- */

.local-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 13px;
  border: 1px solid var(--local-line);
  border-radius: var(--radius-pill);
  background: var(--local-bg);
  font-size: 13px;
  font-weight: 500;
  color: var(--local);
}

.local-badge svg {
  flex-shrink: 0;
}

.local-badge--header {
  padding: 6px 12px;
  font-size: 12.5px;
}

/* Typography -------------------------------------------------------------- */

.display {
  margin: 0;
  font-family: var(--font-display);
  /* The design's display face was a serif at weight 400, which carried its own
     presence. Roboto at 400 would read as oversized body text, so the weight
     goes up and the tracking tightens to keep the same hierarchy. */
  font-weight: 500;
  letter-spacing: -0.022em;
  line-height: 1.05;
  color: var(--ink);
}

.hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
  max-width: 700px;
  margin-bottom: 48px;
}

.hero .display {
  font-size: 60px;
}

.hero__lead {
  margin: 0;
  font-size: 17px;
  color: var(--ink-secondary);
  max-width: 560px;
}

/* Tool grid --------------------------------------------------------------- */

.tool-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.tool-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
}

a.tool-card:hover {
  border-color: var(--local);
  color: var(--ink);
}

.tool-card__name {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}

.tool-card__desc {
  font-size: 13px;
  color: var(--ink-muted);
  margin-top: 3px;
}

/* Tool page --------------------------------------------------------------- */

.tool-head {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 28px;
}

.tool-head__back {
  font-size: 13px;
  color: var(--ink-muted);
}

.tool-head .display {
  font-size: 40px;
  line-height: 1.1;
}

.tool-head__lead {
  margin: 0;
  font-size: 15px;
  color: var(--ink-secondary);
}

/* The two-column working area: files on the left, controls on the right. */
.workbench {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

.panel {
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
}

.panel--files {
  flex-grow: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.panel--controls {
  width: 300px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: sticky;
  top: 24px;
}

.panel__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.panel__count {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* File cards -------------------------------------------------------------- */

.file-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.file-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Reordering is a drag; the cursor should say so before the user tries. */
  cursor: grab;
}

.file-card--dragging {
  opacity: 0.4;
}

/* The row a failure was attributed to. */
.file-card--failed .file-card__preview {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.file-card__preview {
  position: relative;
  height: 176px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-faint);
}

/* Drop indicator: a line where the dragged card would land. */
.file-card--drop-before .file-card__preview {
  box-shadow: -7px 0 0 -3px var(--local);
}

.file-card--drop-after .file-card__preview {
  box-shadow: 7px 0 0 -3px var(--local);
}

.file-card__index {
  position: absolute;
  top: 8px;
  left: 8px;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--ground);
  border: 1px solid var(--line);
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.file-card__remove {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink-muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.12s;
}

/* Hide-until-hover only where hovering is possible. On a touch device there
   is no hover, so an opacity-0 control is simply unreachable. */
@media (hover: hover) {
  .file-card__remove {
    opacity: 0;
  }

  .file-card:hover .file-card__remove,
  .file-card:focus-within .file-card__remove {
    opacity: 1;
  }
}

.file-card__remove:hover {
  border-color: var(--danger);
  color: var(--danger);
}

.file-card__name {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-card__meta {
  font-family: var(--font-mono);
  font-size: 11.5px;
  /* Was monospaced for column alignment; Roboto is proportional, so tabular
     figures keep sizes from shifting as their digits change. */
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
  margin-top: 2px;
}

/* Add-files tile, which doubles as the drop target. */
.add-tile {
  font-family: inherit;
  height: 176px;
  width: 100%;
  border: 1px dashed var(--line-dashed);
  border-radius: 8px;
  background: none;
  color: var(--ink-muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  font-size: 13px;
  padding: 0;
}

.add-tile:hover,
.add-tile--dragging {
  border-color: var(--local);
  color: var(--local);
  background: var(--local-bg);
}

/* The empty state: one large drop zone instead of the file grid. */
.dropzone {
  font-family: inherit;
  width: 100%;
  min-height: 300px;
  border: 1px dashed var(--line-dashed);
  border-radius: 8px;
  background: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  cursor: pointer;
  padding: 40px;
  color: var(--ink-muted);
}

.dropzone:hover,
.dropzone--dragging {
  border-color: var(--local);
  background: var(--local-bg);
}

.dropzone__title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
}

.dropzone__hint {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink-muted);
}

/* The chosen document, on the split tool ---------------------------------- */

.document {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--surface-sunken);
}

.document__mark {
  flex-shrink: 0;
  color: var(--ink-faint);
  display: flex;
}

.document__body {
  min-width: 0;
}

.document__name {
  font-size: 15px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.document__meta {
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--ink-muted);
  margin-top: 2px;
}

/* Controls ---------------------------------------------------------------- */

.stat-row {
  display: flex;
  justify-content: space-between;
  font-size: 13.5px;
}

.stat-row__label {
  color: var(--ink-muted);
}

.stat-row__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.field__label {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.field__input {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13.5px;
  color: var(--ink);
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  width: 100%;
}

.field__input:focus {
  outline: 2px solid var(--local);
  outline-offset: -1px;
  border-color: transparent;
}

/* The output name, split into an editable stem and a fixed extension.

   The extension is deliberately outside the input: the tools only ever write
   PDFs, so letting someone type "report.txt" would produce a file the system
   then opens with the wrong application. Policing keystrokes inside one input
   cannot be made watertight — the caret moves, paste and mobile autocorrect
   get around it — so the extension is simply not editable text. */
.field__filename {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  overflow: hidden;
}

/* The input loses the border and background it would carry alone; the wrapper
   draws them for both parts, so the pair reads as one control. */
.field__filename .field__input {
  border: none;
  border-radius: 0;
  background: transparent;
  min-width: 0;
  flex: 1;
}

.field__filename .field__input:focus {
  outline: none;
}

/* Focus is drawn on the wrapper so the ring encloses the extension too. */
.field__filename:focus-within {
  outline: 2px solid var(--local);
  outline-offset: -1px;
  border-color: transparent;
}

.field__extension {
  display: flex;
  align-items: center;
  padding-right: 12px;
  font-family: var(--font-mono);
  font-size: 13.5px;
  color: var(--ink-muted);
  /* The name is the user's; the extension is not. Muted to say so, and
     unselectable so dragging across the field cannot pick it up. */
  user-select: none;
  white-space: nowrap;
}

/* A selection the core cannot read. Marked on the field itself, because the
   fix is to edit what is in it. */
.field__input--invalid {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.field__input--invalid:focus {
  outline-color: var(--danger);
}

/* The line under a field: either what the input means, or why it cannot be
   read. One slot for both, so the layout does not shift as it changes. */
.field__note {
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--ink-muted);
  min-height: 2.7em;
}

.field__note--error {
  color: var(--danger);
}

.control-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.button {
  font-family: inherit;
  font-size: 15px;
  text-align: center;
  padding: 15px 20px;
  border-radius: var(--radius-control);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  display: block;
}

.button:hover:not(:disabled) {
  border-color: var(--local);
  color: var(--ink);
}

.button--primary {
  font-weight: 600;
  color: var(--surface);
  background: var(--ink);
  border-color: var(--ink);
}

.button--primary:hover:not(:disabled) {
  background: #000;
  border-color: #000;
  color: var(--surface);
}

.button--quiet {
  font-size: 14px;
  color: var(--ink-muted);
  padding: 13px 20px;
}

.button:disabled {
  /* 0.6 rather than a lighter value: below about 0.55 the white label on the
     faded dark fill drops under 4.5:1 against the panel, so a disabled action
     becomes unreadable rather than merely quiet. Measured, not guessed. */
  opacity: 0.6;
  cursor: default;
}

.button--busy {
  cursor: progress;
}

.link-button {
  font-family: inherit;
  font-size: 13px;
  color: var(--ink-muted);
  background: none;
  border: none;
  padding: 8px;
  cursor: pointer;
}

.link-button:hover {
  color: var(--local);
}

/* Direction control, on the rotate tool ----------------------------------- */

.choice-group {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.choice {
  font-family: inherit;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 12px 6px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-sunken);
  color: var(--ink-muted);
  font-size: 12.5px;
  cursor: pointer;
}

.choice:hover {
  border-color: var(--local);
  color: var(--ink);
}

/* The selected option carries the ink colour rather than the green, which is
   reserved for the local-processing claim. */
.choice--selected {
  border-color: var(--ink);
  background: var(--surface);
  color: var(--ink);
  font-weight: 500;
  box-shadow: inset 0 0 0 1px var(--ink);
}

.choice:focus-visible {
  outline: 2px solid var(--local);
  outline-offset: 2px;
}

/* Rotation preview -------------------------------------------------------- */

.rotate-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 32px 16px 24px;
}

/* A page-shaped outline, turned to show the result the controls will produce.
   Sized to stay square-ish at 90 degrees so the box does not jump as the
   direction changes. */
.rotate-preview__page {
  width: 92px;
  height: 124px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface-sunken);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.25s ease;
}

/* A letter rather than an abstract mark: orientation is only legible if the
   thing being turned has an obvious right way up. */
.rotate-preview__mark {
  font-size: 40px;
  font-weight: 500;
  color: var(--ink-faint);
  line-height: 1;
}

.rotate-preview__caption {
  font-size: 13px;
  color: var(--ink-muted);
  text-align: center;
  max-width: 34ch;
}

@media (prefers-reduced-motion: reduce) {
  .rotate-preview__page {
    transition: none;
  }
}

/* Errors ------------------------------------------------------------------ */

.error {
  padding: 14px 16px;
  border: 1px solid var(--danger);
  border-radius: var(--radius-card);
  background: var(--danger-bg);
}

.error p {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink);
}

.error__password {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.error__password .field__input {
  font-family: var(--font-body);
  background: var(--surface);
}

/* Result ------------------------------------------------------------------ */

/* Once the merge is done, the page's "drag the cards to set the order" lead
   describes something that is no longer on screen. The tool marks its root
   as complete and the heading above it steps back to just the title. */
.tool-head:has(+ .is-complete) .tool-head__lead {
  display: none;
}

.result {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  padding: 72px 24px;
  text-align: center;
}

.result__mark {
  width: 52px;
  height: 52px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--local);
  color: var(--local);
  display: flex;
  align-items: center;
  justify-content: center;
}

.result__heading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.result__heading .display {
  font-size: 42px;
  line-height: 1.1;
}

.result__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  color: var(--ink-secondary);
}

.result__actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.result__actions .button {
  padding: 15px 30px;
}

/* Static supporting copy -------------------------------------------------- */

.notes {
  margin-top: 64px;
  max-width: 660px;
}

.notes h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 24px;
  letter-spacing: -0.015em;
  margin: 36px 0 8px;
  color: var(--ink);
}

.notes h3 {
  font-size: 15px;
  font-weight: 600;
  margin: 24px 0 4px;
  color: var(--ink);
}

.notes p,
.notes li {
  color: var(--ink-secondary);
  font-size: 15px;
}

.notes ol {
  padding-left: 20px;
}

.notes li {
  margin-bottom: 6px;
}

/* Responsive -------------------------------------------------------------- */

/* Below the desktop artboard width the side panel no longer fits beside the
   files, so it moves underneath and the grid loosens. */
@media (max-width: 1100px) {
  .site__inner {
    padding: 0 32px;
  }

  .workbench {
    flex-direction: column;
    align-items: stretch;
  }

  .panel--files,
  .panel--controls {
    width: 100%;
    position: static;
  }

  .tool-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .file-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* The mobile artboard: single column, larger touch targets, tighter gutters. */
@media (max-width: 640px) {
  .site__inner {
    padding: 0 20px;
  }

  .site__header {
    padding-top: 28px;
    padding-bottom: 20px;
  }

  .local-badge--header {
    display: none;
  }

  .hero .display {
    font-size: 36px;
  }

  .hero__lead {
    font-size: 15px;
  }

  .tool-head .display {
    font-size: 30px;
  }

  .tool-grid,
  .file-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .panel {
    padding: 16px;
  }

  /* Cards become rows on a phone: a 176px-tall preview per file would push
     the merge button off the screen once a few files are added. */
  .file-grid {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .file-card {
    flex-direction: row;
    align-items: center;
    gap: 13px;
    padding: 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
  }

  /* The preview box becomes a small fixed badge holding the position number
     and the document mark; the remove button leaves it and moves to the end
     of the row, where a thumb expects it. */
  .file-card__preview {
    order: 1;
    height: 40px;
    width: 40px;
    flex-shrink: 0;
    gap: 6px;
    border: none;
    background: none;
    position: static;
  }

  .file-card__index {
    position: static;
  }

  .file-card__preview svg {
    display: none;
  }

  .file-card__body {
    order: 2;
    flex-grow: 1;
    min-width: 0;
  }

  .file-card__remove {
    order: 3;
    position: static;
    opacity: 1;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    border: none;
    background: none;
  }

  .add-tile {
    height: auto;
    flex-direction: row;
    padding: 16px;
  }

  .result {
    padding: 48px 0;
  }

  .result__heading .display {
    font-size: 32px;
  }

  .result__actions {
    flex-direction: column;
    width: 100%;
  }

  .result__actions .button {
    width: 100%;
  }

  .site__footer-bar {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }
}
