/* The market's pages. The palette, spacing and radius tokens are the app's
   (app/htdocs/styles/base.css) by way of the website's (www/htdocs/styles.css),
   kept to a subset, so the market and the rest of the project look like the
   same product. Dark mode is automatic via light-dark(); the icons are baked
   black in the SVG files (an <img> cannot inherit currentColor), so dark mode
   inverts them with a filter. */
:root {
  color-scheme: light dark;
  --primary-color: #007bff;
  --primary-hover-color: #0056b3;
  --background-color: light-dark(#ffffff, #1a1a1a);
  --surface-color: light-dark(#f8f9fa, #242424);
  --text-color: light-dark(#333333, #e5e7eb);
  --text-strong-color: light-dark(#1e293b, #f0f1f3);
  --text-muted-color: light-dark(#64748b, #94a3b8);
  --border-color: light-dark(#dee2e6, #3a3a3a);
  --problem-color: light-dark(#b00020, #ff6b6b);
  --good-news-color: light-dark(#0a7c2f, #4ade80);
  --icon-filter: none;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  --spacing-xxl: 3rem;
  --border-radius-md: 8px;
  --border-radius-lg: 12px;
  --content-width: 60rem;
}
@media (prefers-color-scheme: dark) {
  :root { --icon-filter: invert(0.85); }
  /* The brand hand is white fill on black strokes, not baked-black line
     art: the full inversion turns it black with a white stroke, as on the
     ai site. */
  .brand img { filter: invert(1); }
}

/* The column moves from the body to main, as on the www and verify sites:
   the body spans the viewport so the sticky header can run edge to edge,
   and main is the centered measure under it. */
body {
  font-family: system-ui, sans-serif;
  margin: 0;
  color: var(--text-color);
  background: var(--background-color);
  line-height: 1.5;
}
main {
  max-width: var(--content-width);
  margin: 0 auto;
  padding: var(--spacing-md) var(--spacing-md) var(--spacing-xl);
}

h1 { font-size: 1.4rem; color: var(--text-strong-color); }
h2 { font-size: 1.1rem; margin-top: var(--spacing-xl); color: var(--text-strong-color); }
h3 { font-size: 1rem; color: var(--text-strong-color); }
a { color: inherit; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; white-space: nowrap; }
img { max-width: 100%; height: auto; border-radius: var(--border-radius-md); }

.muted { color: var(--text-muted-color); font-size: .9rem; }
.problem { color: var(--problem-color); font-weight: 600; }
.good-news { color: var(--good-news-color); font-weight: 600; }

/* The site header: the brand, the main navigation, the language selector. */
/* The www site's bar: stuck to the viewport top, edge to edge over the page,
   the icon and the title at its left. */
.site-header {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; gap: var(--spacing-md); flex-wrap: wrap;
  padding: var(--spacing-sm) var(--spacing-lg);
  background: var(--background-color);
  border-bottom: 1px solid var(--border-color);
}
.brand { display: flex; align-items: center; gap: var(--spacing-sm); text-decoration: none;
  font-size: 1.25rem; font-weight: 700; color: var(--text-strong-color); }
.brand img { width: 32px; height: 32px; }
.site-navigation { display: flex; gap: var(--spacing-md); flex-wrap: wrap; font-size: .95rem; }
.language-selector { margin-inline-start: auto; display: flex; align-items: center; gap: .35rem; }
/* The header's two dropdowns — the citizen's menu and the language select —
   are one visual species: the same box, the same height. Their chevron is
   the shared popup-menu rule with the form selects', below. */
.language-selector select, .user-menu summary {
  /* border-box, because a select is one by default and the heights must be
     the same number for the same reason the rule is shared. */
  box-sizing: border-box; height: 2rem;
  padding-block: .2rem; padding-inline: .45rem 1.75rem; font-size: .9rem;
  border: 1px solid var(--border-color); border-radius: .35rem;
  color: inherit; }
/* The signed-in citizen's own menu, at the header's right edge just before
   the language selector: a native <details>, their picture and name as the
   trigger, holding what is theirs — Post, My account, Sign out. The auto
   margin that pushed the language selector right moves to it, so the two sit
   together. */
.user-menu { position: relative; margin-inline-start: auto; }
/* Signed out, the Sign in button stands where the menu would: the primary
   color at the shared controls' height, the one call to action in the bar. */
.site-header .sign-in { margin-inline-start: auto; display: flex; align-items: center;
  box-sizing: border-box; height: 2rem; padding: .2rem .7rem; font-size: .9rem;
  background: var(--primary-color); color: #ffffff;
  border-radius: .35rem; text-decoration: none; }
.site-header .sign-in:hover { background: var(--primary-hover-color); }
.user-menu + .language-selector, .sign-in + .language-selector { margin-inline-start: 0; }
/* The trigger's own layout on top of the shared box above; the list mirrors
   the popup the app's Settings/Language select opens — the browser's own:
   the surface grey behind flat items at the trigger's width, a neutral grey
   as the hover highlight, never an accent color. */
.user-menu summary { display: flex; align-items: center;
  gap: .35rem; list-style: none; }
.user-menu summary::-webkit-details-marker { display: none; }
.user-menu-list { position: absolute; inset-inline-end: 0; top: calc(100% + .25rem); z-index: 10;
  display: flex; flex-direction: column; min-width: 100%; width: max-content;
  padding: .25rem; background: var(--surface-color);
  border: 1px solid var(--border-color); border-radius: .5rem;
  box-shadow: 0 .35rem 1rem rgba(0, 0, 0, .2); }
/* border-box, so width: 100% means the frame's width for both kinds of item:
   the links are content-box by default and their padding rode on top of the
   100%, hovering wider than the frame, while the born-border-box Sign out
   button fit exactly. */
.user-menu-list a, .user-menu-list button { display: block; box-sizing: border-box;
  width: 100%; text-align: start;
  padding: .3rem .6rem; border: none; background: none; font: inherit;
  color: var(--text-color); text-decoration: none; border-radius: .25rem; cursor: pointer; }
.user-menu-list a:hover, .user-menu-list a:focus-visible,
.user-menu-list button:hover, .user-menu-list button:focus-visible {
  background: light-dark(rgba(15, 23, 42, .08), rgba(255, 255, 255, .14)); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* The QR is the control that copies the URL it encodes, so it is a button —
   drawn as nothing but the code itself, and told apart from an image only by
   the cursor and by the outline the keyboard gives it. Same shape and colors
   as the agora's, so a citizen who knows one service reads the other. */
.qr { width: min(260px, 70vw); margin: var(--spacing-md) 0; }
.qr svg { width: 100%; height: auto; background: #fff; padding: .4rem; border-radius: .35rem; }
.qr-button { display: block; width: 100%; padding: 0; border: none; background: none; cursor: pointer; }
/* The generic button hover would paint a frame behind the code's own white. */
.qr-button:hover { background: none; }
.qr-button:focus-visible { outline: 2px solid var(--primary-color); outline-offset: 3px; border-radius: .35rem; }
/* The same copy said as a word, under the code at its start edge — the
   counterpart of the demist app's Copy button under its own QR codes. */
.qr-copy-button { margin-top: .5rem; }
.copy-confirmation {
  position: fixed; z-index: 20; padding: 3px 8px;
  font-size: 12px; font-weight: 500; white-space: nowrap;
  color: #ffffff; background: #22a06b; border-radius: 6px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, .25);
  /* Placed by its bottom center, so the point it is given is the pointer
     itself: the box sits above the cursor and centered on it. */
  transform: translate(-50%, -100%);
  pointer-events: none;
}
.copy-confirmation-failed { background: #b00020; }
.copy-confirmation[hidden] { display: none; }

/* A citizen shown as a person rather than 64 hex characters: a small avatar
   and their name, linking to their page on the indexer — where a reader checks
   the claim against the chain rather than against this service. */
.citizen { display: inline-flex; align-items: center; gap: .5rem; text-decoration: none; min-width: 0; }
.citizen:hover .citizen-name { text-decoration: underline; }
.citizen-avatar { flex: none; border-radius: .3rem; object-fit: cover;
  background: light-dark(#dddddd, #333333); }
.citizen-avatar-empty { display: inline-block; }
.citizen-name { min-width: 0; overflow-wrap: anywhere; }
.signed-in { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
form.inline { display: inline; }

/* Where the reader is in the koinon and in the tag tree: a breadcrumb of
   links, and the nodes one level in as chips they can walk into. Both are
   server-rendered links — every navigation is a new listing. */
.browse-path { font-size: .95rem; margin: .3rem 0; }
.browse-path strong { font-weight: 600; }
.browse-children { list-style: none; margin: .35rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .4rem; }
.browse-children a {
  display: inline-block; padding: .25rem .6rem; font-size: .9rem;
  text-decoration: none; border: 1px solid var(--border-color);
  border-radius: 999px; background: var(--surface-color);
}
.browse-children a:hover { border-color: var(--primary-color); color: var(--primary-color); }
/* The reader's own area heads its level, marked so they know why. */
.browse-children a.home-area { border-color: var(--primary-color); }

/* The listing: announcement cards in a responsive grid, thumbnail first. The
   thumbnail box is square and the image covers it — a listing aligns or it
   does not read as one. */
ul.announcements { list-style: none; margin: var(--spacing-md) 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--spacing-md); }
.announcement-card { display: block; text-decoration: none;
  border: 1px solid var(--border-color); border-radius: var(--border-radius-lg);
  background: var(--surface-color); overflow: hidden; }
.announcement-card:hover { border-color: var(--primary-color); }
.announcement-card .card-photo { aspect-ratio: 1; width: 100%; object-fit: cover;
  border-radius: 0; display: block; background: light-dark(#eeeeee, #2e2e2e); }
.announcement-card .card-photo-empty { aspect-ratio: 1; width: 100%; display: flex;
  align-items: center; justify-content: center; background: light-dark(#eeeeee, #2e2e2e); }
.announcement-card .card-photo-empty img { width: 3rem; height: 3rem; opacity: .35;
  filter: var(--icon-filter); }
.announcement-card .card-body { padding: .6rem .7rem .7rem; }
.announcement-card .card-title { display: block; font-weight: 600;
  color: var(--text-strong-color); overflow-wrap: anywhere; }
.announcement-card .card-price { display: block; margin-top: .15rem; font-weight: 600;
  font-variant-numeric: tabular-nums; }
.announcement-card .card-place { display: block; margin-top: .15rem;
  font-size: .85rem; color: var(--text-muted-color); }

/* One announcement's page: the photo gallery, then what is asked for it. */
.photo-gallery { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); margin: var(--spacing-md) 0; }
.photo-gallery a { flex: 0 1 10rem; }
.photo-gallery img { width: 100%; aspect-ratio: 1; object-fit: cover; }
/* Like the form rules below, the gallery's flex display out-ranks the
   browser's own [hidden], so hidden must be said again — the post form's
   upload preview is hidden until photos are chosen. */
.photo-gallery[hidden] { display: none; }
.price { font-size: 1.25rem; font-weight: 700; color: var(--text-strong-color);
  font-variant-numeric: tabular-nums; }
.additional-price { font-size: .95rem; }
/* The description keeps its author's line breaks, exactly as written. */
.announcement-description { white-space: pre-wrap; overflow-wrap: anywhere; }
.announcement-facts { display: grid; grid-template-columns: max-content 1fr;
  gap: .45rem 1.2rem; margin: var(--spacing-md) 0; }
.announcement-facts dt { font-weight: 600; }
.announcement-facts dd { margin: 0; min-width: 0; overflow-x: auto; }
/* The seller's tally reads as a footnote to the chip, not a continuation of
   it: its own line, under the name. */
.announcement-facts .confirmed-sales { display: block; margin-top: .2rem; }

/* Questions and their answers: the question a citizen chip and a paragraph,
   the answer indented under it, marked as the seller's. */
ul.questions { list-style: none; margin: 0; padding: 0; }
ul.questions > li { padding: .6rem 0; border-top: 1px solid var(--border-color); }
.question-text, .answer-text { white-space: pre-wrap; overflow-wrap: anywhere; margin: .25rem 0; }
.answer { margin-block: .4rem 0; margin-inline: var(--spacing-lg) 0; padding-inline-start: var(--spacing-md);
  border-inline-start: 3px solid var(--primary-color); }

/* The forms fill the page's own column; the body's max-width keeps the
   measure readable. */
form.market-form { display: flex; flex-direction: column; gap: .7rem; max-width: 34rem; }
form.market-form label, form.market-form .field {
  display: flex; flex-direction: column; gap: .25rem; font-size: .9rem; }
/* The `display: flex` rules above out-rank the browser's own `[hidden]` rule,
   which is a plain `display: none` on the element name. Anything given a
   display here must therefore say what hidden means for it, or the hidden
   attribute silently does nothing. */
form.market-form[hidden], form.market-form label[hidden], form.market-form .field[hidden] { display: none; }
/* The row that is a checkbox and its sentence — accepting the Terms — lies
   flat rather than stacking like the other fields. */
form.market-form label.terms { flex-direction: row; align-items: center; gap: .4rem; }
/* A photo on the post form — existing on the edit form, or chosen for upload
   in the preview — as a thumbnail with its delete button under it. The flex
   display out-ranks the browser's [hidden] (see the form rules below), and a
   photo marked for deletion hides until the save deletes it, so hidden must
   be said again. */
.photo-gallery .photo-upload { display: flex; flex-direction: column;
  align-items: flex-start; flex: 0 1 10rem; font-size: .85rem; gap: .25rem; }
.photo-gallery .photo-upload[hidden] { display: none; }
form.market-form textarea { font-family: inherit; font-size: 14px; padding: 8px 10px;
  border: 1px solid var(--border-color); border-radius: var(--border-radius-md);
  background: inherit; color: inherit; resize: vertical; }
/* Controls wear the app's own recipe (app/htdocs/styles/buttons.css and its
   form fields) in this market's palette, so a press looks and feels the same
   across the product. */
input, select {
  margin: 0;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
  background: inherit;
  color: inherit;
}
button {
  margin: 0;
  padding: 10px 14px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  color: inherit;
  background: var(--background-color);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-md);
  cursor: pointer;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
button:hover { background: var(--surface-color); border-color: var(--text-muted-color); }
button:disabled { opacity: .6; cursor: not-allowed; }
button.primary { background: var(--primary-color); border-color: var(--primary-color); color: #ffffff; }
button.primary:hover { background: var(--primary-hover-color); border-color: var(--primary-hover-color); }
/* A destructive act's button: outlined in the problem color rather than
   filled with it — the light and dark problem reds both keep their contrast
   against the page, neither does against white text. */
button.danger { color: var(--problem-color); border-color: var(--problem-color); }

/* Every popup menu wears the app's chevron (styles/settings.css there): no
   native arrow, the slate polyline — legible in either color scheme — drawn
   inside the right edge: the form selects with the header's two dropdowns.
   appearance: none hides the select's native arrow, the one part a sibling
   control could never imitate; it is harmless on the summary. After the
   input rule above, so its background shorthand cannot blank the image. */
select, .user-menu summary {
  appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .5rem center;
}
/* No focus ring (the browser draws one even for mouse opens): a focused
   menu keeps its resting frame, and the chevron alone tells the open state. */
select { padding-inline-end: 1.75rem; outline: none; }
/* While a picker is open, its chevron points up. The :open rule stands
   alone: a browser too old for the pseudo-class drops only this rule, and
   the citizen menu below keeps its flip. */
select:open {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 6.5 6 1.5 11 6.5' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); }
.user-menu[open] summary {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 6.5 6 1.5 11 6.5' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); }

/* The confirmation a destructive act asks for (market.js askConfirmation):
   the browser's confirm() in the page's own clothes. */
dialog.confirm { border: 1px solid var(--border-color); border-radius: .5rem;
  background: var(--background-color); color: var(--text-color);
  padding: var(--spacing-lg); max-width: 22rem; }
dialog.confirm::backdrop { background: rgba(0, 0, 0, .45); }
dialog.confirm p { margin: 0 0 var(--spacing-md); }
dialog.confirm form { display: flex; gap: var(--spacing-sm); justify-content: flex-end; }

/* The leaf tags of the post form, grouped under their branch's path. Columns
   because fifty leaves in one column is a corridor. */
.tag-choices { columns: 14rem; gap: var(--spacing-lg); }
.tag-branch { break-inside: avoid; margin-bottom: var(--spacing-md); }
.tag-branch h3 { margin: 0 0 .25rem; font-size: .9rem; }
/* Qualified like label.terms above: the bare `.tag-choices label` loses to
   `form.market-form label`'s column stacking on specificity, and the checkbox
   then sits above its text instead of beside it. */
form.market-form .tag-choices label { display: flex; flex-direction: row; align-items: center;
  gap: .4rem; font-size: .9rem; padding: .1rem 0; }
.tag-choices input[type="checkbox"] { padding: 0; }
/* An announcement's own tags, shown as the same chips the browser uses. */
.tag-list { display: flex; flex-wrap: wrap; gap: .4rem; padding: 0; margin: .35rem 0; list-style: none; }
.tag-list li { display: inline-block; padding: .25rem .6rem; font-size: .9rem;
  border: 1px solid var(--border-color); border-radius: 999px; background: var(--surface-color); }

/* The area picker: a breadcrumb of where you are, and the areas one level in.
   Wherever you have navigated to is what is chosen, so there is no separate
   control to miss. */
.area-picker { border: 1px solid var(--border-color); border-radius: .35rem; padding: .45rem .55rem; }
.area-path { font-size: .9rem; }
.area-path strong { font-weight: 600; }
.area-up { padding: 0; border: none; background: none; font: inherit; color: inherit;
  text-decoration: underline; cursor: pointer; }
/* A link-styled button: the generic button hover must not box it. */
.area-up:hover { background: none; }
.area-children { list-style: none; margin: .45rem 0 0; padding: 0; max-height: 11rem; overflow-y: auto; }
.area-children li { border-top: 1px solid var(--border-color); }
.area-node { display: block; width: 100%; text-align: start; padding: .3rem .2rem; border: none;
  border-radius: 0; background: none; font: inherit; color: inherit; cursor: pointer; }
/* The hover background is light in both schemes, so the text must be stated
   rather than inherited: in dark mode the inherited color is near-white, and
   the row would read as blank. */
.area-node:hover { background: light-dark(#f0f0f0, #2a2a2a); }
.area-message { padding: .3rem .2rem; font-size: .85rem; color: var(--text-muted-color); }

/* The moderation queue and the account's tables. */
table.rows { border-collapse: collapse; width: 100%; }
table.rows th, table.rows td { text-align: start; padding: .4rem .6rem;
  border-top: 1px solid var(--border-color); vertical-align: top; }
table.rows th { color: var(--text-muted-color); font-size: .85rem; font-weight: 600; }

/* The policy page: the trust model first, then the sector table. */
table.policy { border-collapse: collapse; }
table.policy th, table.policy td { text-align: start; padding: .4rem .6rem;
  border-top: 1px solid var(--border-color); vertical-align: top; }
table.policy th { white-space: nowrap; }

.pagination { display: flex; gap: var(--spacing-md); align-items: baseline; flex-wrap: wrap; }

/* The www site's footer: the centered measure, muted and centered text,
   generous air above and below. Outside main (site_header opens main, every
   page closes it before its footer), so it states the column itself. */
footer { max-width: var(--content-width); margin: 0 auto;
  padding: var(--spacing-xl) var(--spacing-lg) var(--spacing-xxl);
  color: var(--text-muted-color); text-align: center; }
footer p { margin: var(--spacing-sm) 0; }

/* Under a right-to-left language the chevron follows the padding-inline-end
   to the left; background-position is physical and needs saying explicitly. */
select:dir(rtl), .user-menu summary:dir(rtl) { background-position: left .5rem center; }
