/* ============================================================
   Layra — the manager's dashboard (admin.html)

   Loaded *after* app.css and holding only what that file has no
   class for. No new tokens and no new colours: every value here
   is one of app.css's variables, so the manager's page ages with
   the salon's rather than drifting away from it.

   The shape this file is built around: a page that is read in
   one pass once a month. The queue at the top has to be
   scannable without opening anything, and a salon row has to
   answer "is anything wrong here" while it is still shut — which
   is why the summary line carries badges and money, and why the
   detail below it is a stack of blocks rather than a form.
   ============================================================ */

.admin-section { margin-bottom: 2rem; }

/* Heading on the left, the thing that acts on the section on the right —
   a count for the queue, the search box for the list. Wraps rather than
   squeezing the input, because a search box narrower than the text in it
   is worse than one on its own line. */
.admin-section__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; flex-wrap: wrap; margin-bottom: .35rem;
}
.admin-section__head h2 { font-size: 1.05rem; font-weight: 700; }

.admin-search {
  min-width: 16rem; flex: 0 1 22rem;
  border: 1px solid var(--line); border-radius: 8px;
  padding: .45rem .7rem; font-size: .87rem;
  background: var(--card);
}
.admin-search:focus { border-color: var(--azure); outline: none; }

.admin-card { padding: .5rem 1rem; margin-top: .75rem; }

/* ---- čaka na številko ------------------------------------------------
   Four columns that collapse to one: who, when, the input, and an error
   line that spans the row. The input is given a fixed, generous width
   because a phone number is the thing being typed and a field that
   resizes with the salon's name would be a different width on every row. */
.queue-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto;
  align-items: center; gap: .75rem 1rem;
  padding: .8rem .25rem;
}
.queue-row + .queue-row { border-top: 1px solid var(--line-soft); }

.queue-row__who { display: flex; flex-direction: column; gap: .1rem; min-width: 0; font-size: .9rem; }
.queue-row__who span { font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.queue-row__when { display: flex; flex-direction: column; gap: .1rem; font-size: .8rem; }

.queue-row__assign { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.queue-row__assign input {
  width: 12rem;
  border: 1px solid var(--line); border-radius: 8px;
  padding: .45rem .6rem; font-size: .88rem;
  font-variant-numeric: tabular-nums;
  background: var(--card);
}
.queue-row__assign input:focus { border-color: var(--azure); outline: none; }

/* The error line is the server's own sentence — it names the salon that
   already holds a duplicated number — so it gets the whole width rather
   than being truncated into the column it was triggered from. */
.queue-row .form-error { grid-column: 1 / -1; margin: 0; }

/* ---- the salon list --------------------------------------------------- */

.salon-row { margin-bottom: .6rem; }

.salon-row__summary {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) auto;
  align-items: center; gap: .5rem 1rem;
  padding: .85rem 1.1rem;
  cursor: pointer;
  list-style: none;
}
/* The default triangle is dropped on purpose: with three columns and a row
   of badges it lands in the middle of the name, and the whole summary is
   the click target anyway. */
.salon-row__summary::-webkit-details-marker { display: none; }
.salon-row__summary::marker { content: ''; }
.salon-row__summary:hover { background: var(--line-soft); border-radius: var(--radius); }
.salon-row[open] .salon-row__summary { border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0; }

.salon-row__name { display: flex; flex-direction: column; gap: .1rem; min-width: 0; font-size: .92rem; }
.salon-row__name span { font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.salon-row__meta { display: flex; flex-direction: column; gap: .1rem; font-size: .8rem; min-width: 0; }
.salon-row__meta span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.salon-row__flags { text-align: right; white-space: nowrap; }
.salon-row__flags .badge + .badge { margin-left: .3rem; }

.salon-row__body { padding: 1.1rem 1.1rem .25rem; }
.salon-row__body .form-error { margin-bottom: .8rem; }

/* ---- one decision per block ------------------------------------------
   Each block is one endpoint: buyer details, number, plan, add-on, usage,
   invoices. Separated by a rule rather than nested in cards, because a
   card inside a card inside a details reads as three levels of nothing. */
.admin-block { padding-bottom: 1.1rem; margin-bottom: 1.1rem; border-bottom: 1px solid var(--line-soft); }
.admin-block:last-child { border-bottom: none; margin-bottom: 0; }
.admin-block h3 { font-size: .9rem; font-weight: 700; margin-bottom: .4rem; }
.admin-block .field-hint { line-height: 1.5; max-width: 72ch; }
.admin-block .warn-box { margin: .6rem 0; }

/* `auto-fit` rather than a fixed column count: the same grid holds five
   buyer fields and three subscription selects, and neither should be told
   how many columns it has. */
.admin-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0 1rem; margin-top: .8rem;
}
.admin-fields .field { margin-bottom: .8rem; }

.admin-inline { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: .6rem; }
.admin-inline input[type="tel"] {
  width: 12rem;
  border: 1px solid var(--line); border-radius: 8px;
  padding: .45rem .6rem; font-size: .88rem;
  font-variant-numeric: tabular-nums;
  background: var(--card);
}
.admin-inline input[type="tel"]:focus { border-color: var(--azure); outline: none; }

/* app.css's `.kv` is a two-column list built for a narrow side panel; in a
   full-width row its pairs end up a hand's width apart. Two per line at
   this width, and the label stops being a lonely word on the left. */
.admin-kv { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); margin: .7rem 0; }
.admin-kv > div { gap: .5rem; }

/* ---- invoices ---------------------------------------------------------- */

.inv-list { margin-top: .9rem; }

.inv-row { padding: .6rem 0; }
.inv-row + .inv-row { border-top: 1px solid var(--line-soft); }
.inv-row__head { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; font-size: .87rem; }
.inv-row__number { font-variant-numeric: tabular-nums; }
.inv-row__amount { font-weight: 700; font-variant-numeric: tabular-nums; }
.inv-row__due { font-size: .82rem; }
.inv-row__pay { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.inv-row__pay input[type="date"] {
  border: 1px solid var(--line); border-radius: 8px;
  padding: .35rem .5rem; font-size: .85rem;
  background: var(--card);
}
.inv-row .field-hint { margin-top: .3rem; }

/* ---- the UPN payload ---------------------------------------------------
   Payload on the left, the four fields a human types on the right. The
   textarea is monospace and does not wrap: the record is addressed by
   position (see src/billing/upn.js), so a soft-wrapped line looks like a
   field that is not there, and every empty line in it is meaningful. */
.upn-slip {
  margin-top: .7rem; padding: .8rem .9rem;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--line-soft);
}
.upn-slip__grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 1rem; margin: .7rem 0; }
.upn-slip__payload {
  width: 100%; resize: vertical;
  border: 1px solid var(--line); border-radius: 8px;
  padding: .55rem .65rem;
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
  font-size: .78rem; line-height: 1.45;
  white-space: pre; overflow-x: auto;
  background: var(--card); color: var(--ink);
}
.upn-slip .kv b { overflow-wrap: anywhere; white-space: normal; }

/* The banner names environment variables, and a variable name run together
   with the sentence around it is a variable name nobody copies correctly. */
#issuer-banner code {
  background: var(--card); border-radius: 5px; padding: .1rem .35rem;
  font-size: .85em; word-break: break-all;
}

@media (max-width: 720px) {
  .queue-row, .salon-row__summary { grid-template-columns: 1fr; }
  .salon-row__flags { text-align: left; }
  .upn-slip__grid { grid-template-columns: 1fr; }
  .inv-row__pay { margin-left: 0; }
}
