/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/*
 * Lisa 1982 theme (see docs/THE_REAL_DEAL.md "Theme / UI").
 *
 * Bored has exactly one theme for v1, ported from the reference implementation
 * in ../chess-app (search that repo for `data-theme="lisa"`). Since there is no
 * other theme to switch away from, these rules apply globally instead of being
 * scoped behind a `data-theme` attribute the way the reference app does it.
 *
 * Style: strict monochrome (black on white), dithered gray desktop background,
 * Geneva/Chicago bitmap system font stack, no border-radius, crisp black
 * borders, hard flat drop-shadow (no soft shadows/gradients), striped/hatched
 * title bars.
 */

/*
 * Design tokens. These resolve to the exact literals the theme used before the
 * tokens existed, so the rendered look is unchanged; they just remove the
 * font-stack (was duplicated 4x), dither gradient (3x) and color repeats.
 */
:root {
  --ink: #000000;
  --paper: #ffffff;
  --gray-desktop: #aaaaaa;
  --muted: #666666;
  --rule: #cccccc;
  --shadow-hard: #888888;

  --font-system: "Geneva", "Charcoal", "Chicago", Arial, sans-serif;

  /* Hatched title/bottom bars (repeating-linear-gradient) and the dithered
     desktop dot pattern (radial-gradient), previously inlined per rule. */
  --stripe: repeating-linear-gradient(
    180deg,
    var(--ink) 0px, var(--ink) 1px,
    var(--paper) 1px, var(--paper) 3px
  );
  --desktop-dither: radial-gradient(circle, var(--shadow-hard) 1px, transparent 1px);

  /* Small spacing scale (4px base) matching the paddings already in use. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;

  /* Card #100: the pipeline-status dot is the first non-monochrome element
     in this theme. Muted/desaturated so it doesn't clash with the black on
     white look; kept as tokens rather than inline hex per-template.
     Card #148: --status-error updated to a brighter, more saturated red. */
  --status-waiting: #c9a227;
  --status-running: #4f8f5b;
  --status-error: #e53935;
  --status-done: #7d5ba6;
}

* {
  box-sizing: border-box;
}

html {
  background-color: var(--gray-desktop);
  background-image: var(--desktop-dither);
  background-size: 4px 4px;
  overflow-anchor: none;
  /* Card #176: suppress double-tap-to-zoom on Android Chrome and iOS
     Safari. Does not affect one-finger scrolling or mouse input, so no
     media query is needed. */
  touch-action: manipulation;
}

body {
  margin: 0;
  padding: 0;
  background-color: var(--gray-desktop);
  background-image: var(--desktop-dither);
  background-size: 4px 4px;
  color: var(--ink);
  font-family: var(--font-system);
  font-size: 13px;
  overflow-anchor: none;
}

a {
  color: var(--ink);
}

button,
input[type="submit"],
input[type="button"] {
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 0;
  font-family: var(--font-system);
  font-size: 13px;
  padding: 4px 10px;
  cursor: pointer;
}

button:hover,
input[type="submit"]:hover,
input[type="button"]:hover {
  background: var(--ink);
  color: var(--paper);
}

input[type="text"],
input[type="email"],
input[type="number"],
input[type="checkbox"],
select,
textarea {
  border: 1px solid var(--ink);
  border-radius: 0;
  font-family: var(--font-system);
  font-size: 13px;
  background: var(--paper);
  color: var(--ink);
}

.card-full-width-field {
  display: block;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* Desktop icon grid (the home page, see app/views/home/index.html.erb) */
.lisa-desktop-area {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
}

.lisa-desktop-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
}

.lisa-desktop-title {
  text-align: center;
  font-size: 40px;
  font-weight: bold;
  color: var(--ink);
  line-height: 1.1;
  text-shadow: 2px 2px 0 var(--shadow-hard);
  letter-spacing: 0.02em;
  user-select: none;
}

.lisa-icons {
  display: grid;
  grid-template-columns: repeat(4, 100px);
  gap: 24px;
}

@media (max-width: 640px) {
  .lisa-icons {
    grid-template-columns: repeat(2, 100px);
  }
}

.lisa-icon {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100px;
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  text-decoration: none;
  color: var(--ink);
  user-select: none;
}

.lisa-icon-box {
  width: 64px;
  height: 64px;
  background: var(--paper);
  border: 1px solid var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  margin-bottom: 4px;
}

.lisa-icon:hover .lisa-icon-box {
  background: var(--ink);
  color: var(--paper);
}

.lisa-icon-label {
  font-size: 12px;
  color: var(--ink);
  text-align: center;
  background: var(--gray-desktop);
  padding: 1px 3px;
}

.lisa-icon:hover .lisa-icon-label {
  background: var(--ink);
  color: var(--paper);
}

/* Window frame (wraps every non-home page, see
   app/views/layouts/application.html.erb and
   app/views/shared/_window_bar.html.erb) */
.lisa-window-frame {
  max-width: 900px;
  margin: 40px auto;
  border: 3px solid var(--ink);
  background: var(--paper);
  box-shadow: 4px 4px 0 var(--shadow-hard);
  overflow: hidden;
}

.lisa-window-content {
  padding: 20px;
}

.lisa-window-bar {
  display: flex;
  align-items: center;
  height: 22px;
  min-height: 22px;
  background: var(--paper);
  border-bottom: 2px solid var(--ink);
  font-size: 12px;
  font-weight: bold;
  color: var(--ink);
  user-select: none;
}

.lisa-window-bar-stripe {
  flex: 1;
  height: 100%;
  background-image: var(--stripe);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0 4px;
}

.lisa-window-title {
  white-space: nowrap;
  padding: 0 10px;
  background: var(--paper);
  color: var(--ink);
  flex-shrink: 0;
}

.lisa-window-close {
  width: 14px;
  height: 14px;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-size: 9px;
  text-align: center;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  line-height: 1;
  padding: 0;
}

.lisa-window-close:hover {
  background: var(--ink);
  color: var(--paper);
}

/* Full-screen variant of the window frame, used for the board show page so
   the kanban columns get the full viewport while keeping the same Lisa
   title-bar/bottom-bar chrome as every other window. */
.lisa-window-frame--fullscreen {
  max-width: none;
  width: calc(100vw - 30px);
  height: calc(100vh - 30px);
  margin: 15px;
  display: flex;
  flex-direction: column;
  box-shadow: 4px 4px 0 var(--shadow-hard);
}

.lisa-window-content--fullscreen {
  flex: 1;
  min-height: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

/* Kanban board (see app/views/boards/show.html.erb): columns run left to
   right, Jira-style, each scrolling its own card list independently so the
   column headers stay put. */
.board-page {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.board-page-header {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 2px solid var(--ink);
  flex-shrink: 0;
}

.board-page-header h1 {
  margin: 0;
  font-size: 18px;
}

/* Card #53: the board header's keyword search form, sitting between "Add
   card" and the running-status indicator. */
.board-search-form {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* Card #47: the global running-status indicator, pushed to the right edge
   of the header row via the auto margin on its flex item. */
.board-running-status {
  margin-left: auto;
}

.board-running-badge {
  display: inline-block;
  padding: 4px 10px;
  border: 1px solid var(--ink);
  border-radius: 0;
  font-size: 13px;
  background: #fff8dc;
}

.board-columns {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 0;
  overflow-x: auto;
  overflow-y: hidden;
}

.board-column {
  flex: 1 0 208px;
  min-width: 208px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--ink);
}

/* Collapse/expand control for the accordion behavior below 1000px; hidden
   above that width since columns are never collapsed side by side. */
.board-column-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 0;
  font-family: var(--font-system);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

.board-column-toggle svg {
  width: 14px;
  height: 14px;
  pointer-events: none;
}

/* Below 1000px there isn't room for four side-by-side columns without
   horizontal scrolling, so stack them vertically instead. */
@media (max-width: 999px) {
  .board-page-header {
    flex-wrap: wrap;
  }

  .board-running-status {
    flex-basis: 100%;
    margin-left: 0;
  }

  .board-columns {
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
  }

  .board-column {
    flex: none;
    width: 100%;
    min-width: 0;
  }

  /* Stacked columns behave as an accordion: a collapsed column hides its
     card list, toggled by board_column_controller.js. */
  .board-column-cards.collapsed {
    display: none;
  }

  .board-column-toggle {
    display: inline-flex;
  }
}

.board-column-header {
  flex-shrink: 0;
  padding: 8px 10px;
  background-color: var(--paper);
  background-image: var(--desktop-dither);
  background-size: 4px 4px;
  border-bottom: 2px solid var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.board-column-header h2 {
  margin: 0;
  font-size: 13px;
  font-weight: bold;
  background: var(--paper);
  display: inline-block;
  padding: 1px 6px;
}

.board-column-cards {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.board-card {
  display: block;
  border: 1px solid var(--ink);
  background: var(--paper);
  box-shadow: 2px 2px 0 var(--shadow-hard);
  padding: 8px;
  color: var(--ink);
  text-decoration: none;
  transition: transform 180ms ease, box-shadow 180ms ease;
}

.board-card:hover {
  background: var(--ink);
  color: var(--paper);
}

.board-card-title {
  font-weight: bold;
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Card #100: pipeline-status dot next to a card title (board tile, backlog
   tile, card detail). Colors are the muted status tokens defined in :root;
   state accessibility comes from the title/aria-label set in the
   status_dot helper, not from color alone. */
.status-dot {
  display: inline-block;
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.status-dot-waiting {
  background: var(--status-waiting);
}

.status-dot-running {
  background: var(--status-running);
}

.status-dot-error {
  background: var(--status-error);
}

.status-dot-done {
  background: var(--status-done);
}

.board-card-meta {
  font-size: 11px;
  color: inherit;
  margin-top: 4px;
}

.board-card-label {
  margin-top: 6px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.board-card-label-pill,
.board-card-points-pill,
.board-card-loe-pill,
.board-card-environment-pill {
  display: inline-block;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: bold;
  line-height: 1.4;
  background: var(--ink);
  color: var(--paper);
  border-radius: 0;
}

/* Keep the pills legible when the card inverts on hover. */
.board-card:hover .board-card-label-pill,
.board-card:hover .board-card-points-pill,
.board-card:hover .board-card-loe-pill,
.board-card:hover .board-card-environment-pill {
  background: var(--paper);
  color: var(--ink);
}

.board-column-add-card {
  flex-shrink: 0;
  padding: 8px;
  border-top: 1px solid var(--ink);
}

.board-card[draggable="true"] {
  cursor: grab;
}

.board-card-title,
.board-card-meta,
.board-card-label {
  pointer-events: none;
}

li[data-board-drag-target="card"].dragging .board-card {
  transform: scale(1.03) rotate(-1deg);
  box-shadow: 6px 10px 16px rgba(0, 0, 0, 0.35);
  opacity: 0.85;
  cursor: grabbing;
}

.board-column-cards {
  transition: background 150ms ease;
}

.board-column-cards.drag-over {
  background: #eeeeee;
}

/* FLIP-style settle animation applied by board_drag_controller.js when
   sibling cards shift to make room for the card being dragged over a
   column, so the reflow eases into place instead of snapping instantly. */
li[data-board-drag-target="card"].settling {
  transition: transform 200ms ease;
}

/* Shared button treatment for the board page (Add card, Move, Delete,
   Comment): same base button look as the rest of the app, but with a
   thicker border to stand out against the dense kanban layout. */
.board-btn,
.board-column-add-card .board-btn {
  display: inline-block;
  background: var(--paper);
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 0;
  font-family: var(--font-system);
  font-size: 13px;
  padding: 4px 10px;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
}

.board-btn:hover {
  background: var(--ink);
  color: var(--paper);
}

/* Reports page (app/views/reports/show.html.erb): a plain table of daily
   aggregates, styled to match the rest of the board chrome. */
.reports-page {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px;
}

.reports-table {
  border-collapse: collapse;
  width: 100%;
  max-width: 720px;
}

.reports-table th,
.reports-table td {
  border: 1px solid var(--ink);
  padding: 6px 10px;
  text-align: left;
  font-size: 13px;
}

.reports-table th {
  background-color: var(--paper);
  background-image: var(--desktop-dither);
  background-size: 4px 4px;
  font-weight: bold;
}

/* Markdown-rendered tables in card descriptions and comment bodies.
   Scoped to .card-field-value and .comment-body to avoid affecting the
   hand-authored .reports-table on the reports page. */
.card-field-value table,
.comment-body table {
  border-collapse: collapse;
}

.card-field-value th,
.card-field-value td,
.comment-body th,
.comment-body td {
  border: 1px solid var(--ink);
  padding: 6px 10px;
}

.reports-charts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.reports-chart-block h2 {
  font-size: 13px;
  margin: 0 0 var(--space-1);
}

.reports-chart {
  width: 320px;
  height: 110px;
  border: 1px solid var(--ink);
  background: var(--paper);
}

/* Enlarged chart page (app/views/reports/chart.html.erb): scale the chart up
   to fill the fullscreen window instead of staying at thumbnail size. The
   SVG's viewBox (640x220) preserves the aspect ratio as the CSS size grows,
   so only width/height need to change here; the thumbnail rule above is
   untouched. Capped by max-height so a tall/narrow window never overflows
   the viewport. */
.reports-page--chart .reports-chart {
  width: 100%;
  height: auto;
  max-height: calc(100vh - 160px);
}

.reports-chart-axis {
  stroke: var(--rule);
  stroke-width: 1;
}

.reports-chart-label {
  font-family: var(--font-system);
  font-size: 9px;
  fill: var(--muted);
}

.reports-chart-line {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
}

.reports-chart-line-created {
  stroke-dasharray: 5 3;
}

.reports-chart-line-done {
  stroke-dasharray: none;
}

.reports-chart-line-average {
  stroke-dasharray: 5 3;
}

.reports-chart-line-median {
  stroke-dasharray: none;
}

.reports-chart-legend {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 12px;
  color: var(--muted);
}

.reports-chart-legend span {
  display: inline-block;
  width: 20px;
  height: 0;
  border-top: 2px solid var(--ink);
}

.reports-chart-legend span.reports-chart-line-created {
  border-top-style: dashed;
}

.reports-chart-legend span.reports-chart-line-average {
  border-top-style: dashed;
}

/* Time to Done section (app/views/reports/show.html.erb): lifetime
   card-completion stats, below the daily aggregate table. */
.reports-time-to-done-summary {
  font-size: 13px;
  margin: var(--space-2) 0;
}

.reports-time-to-done-unmeasurable {
  font-size: 12px;
  color: var(--muted);
  margin: 0 0 var(--space-2);
}

.card-delete-btn {
  border: none;
  padding: 4px;
}

.card-cancel-btn,
.new-card-cancel-btn {
  border-width: 1px;
}

.delete-icon {
  width: 14px;
  height: 14px;
  fill: currentColor;
  vertical-align: middle;
}

/* Card #337: shown next to the LOE pill/value wherever it appears, only for
   cards with high or extra_high LOE (see Card#high_effort?). */
.loe-weed-icon {
  width: 14px;
  height: 14px;
  vertical-align: middle;
}

/* Card screen (app/views/cards/show.html.erb and new.html.erb): the full
   detail view for a single card. show.html.erb toggles between a read-only
   view and an editable form via the card-editor Stimulus controller, which
   adds/removes .is-editing on .card-screen. */
.card-screen {
  max-width: 640px;
  overflow-anchor: none;
}

.card-screen-header {
  margin-bottom: 12px;
}

.card-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
}

.card-field-label {
  display: block;
  font-size: 11px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 2px;
}

.card-field-value {
  font-size: 14px;
}

.card-field-empty {
  color: var(--muted);
  font-style: italic;
}

.card-title {
  font-size: 18px;
  font-weight: bold;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Plain (always-editable) card form fields, used on cards/new.html.erb. */
.card-field {
  margin-bottom: 12px;
}

.card-field label {
  display: block;
  font-size: 11px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 2px;
}

.label-radios {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 16px;
  margin: 2px 0 6px;
}

/* Radio option rows. The higher specificity overrides the uppercase, block
   `.card-field label` heading style so option text reads as a normal choice. */
.card-field .label-radio,
.label-radio {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: normal;
  text-transform: none;
  letter-spacing: normal;
  margin-bottom: 0;
}

.label-radio input {
  width: auto;
}

.dependency-checkboxes {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 2px 0 6px;
  max-height: 200px;
  overflow-y: auto;
}

.dependency-checkboxes label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: normal;
  text-transform: none;
  letter-spacing: normal;
}

.dependency-checkboxes input {
  width: auto;
}

.card-actions {
  margin-top: 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.card-actions-right {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

/* Toggle: edit fields are hidden until .is-editing is present on the card
   screen; view fields hide once editing starts. new.html.erb's plain
   .card-field rows are unaffected since they don't carry either class. */
.card-screen:not(.is-editing) .card-edit-field {
  display: none;
}

.card-screen.is-editing .card-view-field {
  display: none;
}

.card-screen.is-editing .card-row {
  cursor: default;
}

.card-screen:not(.is-editing) .card-cancel-btn {
  display: none;
}

.comment-list {
  margin-bottom: 16px;
}

.comment {
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
}

.comment-meta {
  display: flex;
  gap: 8px;
  align-items: baseline;
  margin-bottom: 4px;
}

.comment-author {
  font-weight: bold;
}

.comment-timestamp {
  font-size: 12px;
  color: var(--muted);
}

.comment-delete-btn {
  display: inline-flex;
  align-items: center;
  margin-left: auto;
  color: var(--muted);
  text-decoration: none;
}

.comment-delete-btn:hover {
  color: var(--ink);
}

.comment-delete-btn .delete-icon {
  width: 13px;
  height: 13px;
}

/* Team screen (app/views/memberships/index.html.erb): each member's name
   and their admin actions share a single row. */
.membership-list {
  padding-left: 0;
  list-style: none;
}

.membership-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px solid var(--rule);
}

.membership-actions {
  display: flex;
  gap: 12px;
}

.lisa-window-bottom-bar {
  height: 18px;
  min-height: 18px;
  border-top: 2px solid var(--ink);
  background-image: var(--stripe);
}

.alert {
  color: var(--ink);
  border: 1px solid var(--ink);
  background: var(--paper);
  padding: 6px 10px;
}

.notice {
  color: var(--ink);
  border: 1px solid var(--ink);
  background: var(--paper);
  padding: 6px 10px;
}

/* Validation errors (shared/_errors, used by cards/new, cards/show,
   onboarding/new). The class was referenced everywhere but never defined, so
   errors had no visual signal. Monochrome treatment: a heavy black-bordered
   box, matching the theme's crisp borders and hard-edged look. */
.errors {
  margin: 0 0 var(--space-3) 0;
  padding: var(--space-2) var(--space-4);
  border: 2px solid var(--ink);
  background: var(--paper);
  list-style: square;
}

.errors li {
  color: var(--ink);
  font-weight: bold;
}

/* Keyboard focus affordance. There was none before; a solid black outline
   reads clearly against the white surfaces without adding color to the
   strictly-monochrome theme. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}

/* Card #76: floating window shown when a user highlights a span of the
   rendered card description, letting them add a comment that gets written
   into the description markdown source. Positioned in document flow (top/
   left set inline by description_comment_controller.js from the selection's
   bounding rect), not viewport-fixed, so it scrolls with the page. */
.description-comment-popup {
  position: absolute;
  z-index: 20;
  width: 650px;
  max-width: calc(100vw - 16px);
  padding: var(--space-3);
  border: 2px solid var(--ink);
  background: var(--paper);
  box-shadow: 2px 2px 0 var(--shadow-hard);
}

.description-comment-popup-textarea {
  width: 100%;
  box-sizing: border-box;
  font-family: inherit;
  font-size: 14px;
  resize: vertical;
}

.description-comment-popup-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* Card #254: the trigger button and upload form for the card's photos. */
.card-photos {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-3);
}

/* Card #256: the "N Photos Attached" view takes over the card screen's
   content area (in normal document flow, using the page's own scrolling)
   instead of floating over the rest of the card's fields in a small,
   fixed-height popup. */
.card-photos-view {
  margin-top: var(--space-3);
}

.card-photos-view[hidden] {
  display: none;
}

.card-photos-view-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.card-photos-view-title {
  font-weight: bold;
}

/* Photos stack vertically, one under the other. */
.card-photo {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.card-photo-image {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--ink);
}

.card-photo-delete-form {
  margin: 0;
}

.card-photo-upload {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}
