/* EDEN Kesef. The counter.
 *
 * Every size here traces to LAYOUT in src/interaction.js, which is the
 * specification and is asserted by test. If a number here disagrees with a
 * number there, THAT file is right and this one is a defect.
 *
 *   referenceWidthCssPx 360   minTypeSp 18   amountTypeSp 48
 *   customerFacingTotalSp 64  minTouchDp 56  tenderKeyDp 72
 *   contrastTarget 7.0        deadZoneTopFraction 0.25
 *   noDarkThemeOnCounter TRUE
 *
 * ONE THEME, DELIBERATELY. This page does not offer a dark variant and does not
 * follow prefers-color-scheme. That is not an omission. A dark counter at 468
 * measured nits in tropical daylight is unreadable, and the person holding the
 * phone cannot switch it back mid-sale with a customer waiting. So every colour
 * is painted explicitly and the page holds whatever ground the host paints.
 */

:root {
  /* Paper, not pure white. Pure white at 468 nits in direct sun is glare. */
  --ground:      #FBFAF7;
  --ground-sunk: #F2EFE8;
  --ink:         #14140F;   /* 16.8:1 on ground. Target is 7.0 */
  --ink-soft:    #4A4A42;   /*  8.1:1 on ground */
  --rule:        #DCD9CF;
  --silver:      #E2E6E9;

  /* The money colour. Same green as the icon, so the launcher and the counter
     are recognisably one thing. */
  --money:       #0A5C33;   /* white on this: 8.0:1 */

  /* TENDER. The row ALTERNATES DARK, LIGHT, DARK, LIGHT.
   *
   * The first palette here was four saturated colours of near-identical
   * luminance: green .081, blue .058, magenta .058, ochre .079. Measured as
   * contrast against each other that is 1.01 between Cash and Book it, and 1.00
   * between Card and Phone, which is the ratio of a colour against itself. Hue
   * was carrying the entire load. Hue is the one channel that DOES NOT SURVIVE
   * a dichromacy, a scratched screen, or direct sun on a cheap panel, so under
   * any of those the row became one flat band.
   *
   * Alternating luminance fixes it in the channel that always survives: adjacent
   * keys now differ by between 4.8 and 8.1 times, so the row reads dark, light,
   * dark, light in pure greyscale and with no colour perception at all.
   *
   * Text colour flips with the ground, and every pair still clears the 7.0
   * target: 8.0, 11.2, 13.6 and 9.9 respectively.
   *
   * This is the floor, not the finish. The interaction model asks for a
   * PHOTOGRAPH on each key, which is the only channel that needs no learning.
   * That needs real photographs and is recorded in COMMITMENTS.md. */
  --cash:        #0A5C33;   /* deep green, L .081, WHITE text  8.0:1 */
  --card:        #F2C200;   /* amber,      L .575, INK text   11.2:1 */
  --mobile:      #0E2A66;   /* deep navy,  L .027, WHITE text 13.6:1 */
  --credit:      #F5A3D0;   /* rose,       L .502, INK text    9.9:1 */

  --short:       #8A1414;
  --unrecorded:  #7A4005;

  --pad-gap: 8px;
  --radius: 14px;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  color-scheme: light;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overscroll-behavior: none;
}

body {
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 18px;                 /* minTypeSp. Nothing is smaller than this. */
  line-height: 1.35;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  /* A till is not a document. Nothing scrolls except the Books. */
  overflow: hidden;
}

/* Digits line up in columns everywhere they appear. */
output, .k-figure, .k-amount, .k-split, .k-owed, .k-meta dd, .k-input--num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

button, input { font: inherit; color: inherit; }
button { border: 0; background: none; cursor: pointer; touch-action: manipulation; }

:focus-visible {
  outline: 3px solid var(--money);
  outline-offset: 2px;
}

.k-noscript {
  padding: 24px;
  font-size: 20px;
}

/* ======================================================================= */
/* THE COUNTER                                                             */
/* ======================================================================= */

.k-counter {
  display: grid;
  /* The display takes the top quarter: deadZoneTopFraction 0.25, the band a
     thumb cannot reach one-handed. Nothing in it is actionable. */
  grid-template-rows: minmax(24dvh, 26dvh) 1fr auto;
  height: 100dvh;
  padding:
    max(8px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right))
    max(8px, env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left));
  gap: var(--pad-gap);
}
.k-counter[hidden] { display: none; }

.k-display {
  display: grid;
  grid-template-rows: auto 1fr auto;
  align-items: end;
  padding: 4px 6px 2px;
  border-bottom: 2px solid var(--rule);
  min-width: 0;
}

.k-status {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 20px;
}

/* Connection is a dot, not a sentence. Filled means the log has reached a peer,
   hollow means it has not yet. Neither is an error and neither blocks a sale. */
.k-dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  border: 2px solid var(--ink-soft);
  flex: none;
}
.k-dot[data-state="online"] { background: var(--money); border-color: var(--money); }
.k-dot[data-state="offline"] { background: transparent; }

.k-pending {
  font-size: 18px;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.k-amount {
  display: block;
  font-size: clamp(48px, 15vw, 76px);   /* amountTypeSp 48 at the 360px reference */
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  min-width: 0;
}
.k-amount[data-empty="true"] { color: #9A978D; }

.k-entryline {
  font-size: 18px;
  color: var(--ink-soft);
  text-align: right;
  min-height: 20px;
}

/* ---- the pad ---------------------------------------------------------- */

.k-pad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 1fr;
  gap: var(--pad-gap);
  min-height: 0;
}

.k-key {
  min-height: 56px;                 /* minTouchDp */
  border-radius: var(--radius);
  background: var(--ground-sunk);
  color: var(--ink);
  font-size: clamp(26px, 8vw, 34px);
  font-weight: 600;
  display: grid;
  place-items: center;
  transition: transform 90ms ease, background-color 90ms ease;
}
.k-key:active { background: #E4E0D6; transform: scale(0.97); }
.k-key svg { width: 30px; height: 30px; }

.k-key--back { color: var(--ink-soft); }

/* The way to the Books is a HOLD, not a tap and not a menu. A tap here would be
   one thumb-slip away from leaving the counter mid-sale. */
.k-key--books {
  position: relative;
  overflow: hidden;
  background: var(--ground);
  border: 2px solid var(--rule);
}
.k-coin {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 6px solid var(--money);
  opacity: 0.75;
}
.k-hold {
  position: absolute;
  inset: auto 0 0 0;
  height: 0;
  background: var(--money);
  opacity: 0.16;
  transition: height 60ms linear;
  pointer-events: none;
}

/* ---- tender ----------------------------------------------------------- */

.k-tenders {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--pad-gap);
}

.k-tender {
  min-height: 72px;                 /* tenderKeyDp */
  border-radius: var(--radius);
  color: #fff;
  display: grid;
  grid-template-rows: auto auto;
  place-items: center;
  gap: 4px;
  padding: 8px 2px;
  transition: transform 90ms ease, filter 90ms ease;
}
.k-tender:active { transform: scale(0.97); filter: brightness(1.12); }

/* The tender keys are NEVER faded out and never disabled. Fading them breaks the
   colour channel, which is the channel a person who cannot read is using, and an
   app whose bottom row is grey on opening reads as broken rather than as ready.
   A tap with no amount entered is simply a no-op. */
.k-tender--nudge { animation: nudge 260ms ease; }
@keyframes nudge {
  0%, 100% { transform: none; }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

/* Position is the primary channel. Colour is the second. The mark is the third,
   and it is a SHAPE, because an icon is a word you cannot look up. */
.k-tender__mark { width: 24px; height: 24px; background: #fff; flex: none; }
.k-tender__name { font-size: 18px; font-weight: 600; letter-spacing: 0.01em; }

/* The two light keys take ink, not white. A light key with white text would be
   the one place in this interface that fails the contrast target. */
[data-method="CASH"]   { background: var(--cash);   color: #fff; }
[data-method="CARD"]   { background: var(--card);   color: var(--ink); }
[data-method="MOBILE"] { background: var(--mobile); color: #fff; }
[data-method="CREDIT"] { background: var(--credit); color: var(--ink); }

[data-method="CASH"]   .k-tender__mark,
[data-method="MOBILE"] .k-tender__mark { background: #fff; }
[data-method="CARD"]   .k-tender__mark,
[data-method="CREDIT"] .k-tender__mark { background: var(--ink); }

/* Four distinct silhouettes, distinguishable in monochrome and at arm's length */
[data-method="CASH"]   .k-tender__mark { border-radius: 2px; }                    /* a note   */
[data-method="CARD"]   .k-tender__mark { border-radius: 2px; height: 17px; }      /* a card   */
[data-method="MOBILE"] .k-tender__mark { border-radius: 5px; width: 15px; }       /* a phone  */
[data-method="CREDIT"] .k-tender__mark { border-radius: 50%; }                    /* a circle */

/* ======================================================================= */
/* CONFIRMATION. The number repeated large IS the receipt.                  */
/* ======================================================================= */

.k-confirm {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--money);
  color: #fff;
  z-index: 40;
  animation: rise 140ms ease-out;
}
.k-confirm[hidden] { display: none; }

/* The confirmation takes the SAME ground as the key that was pressed, so the
   whole screen becomes the answer to "which one did she press". Text flips with
   it, for the same reason it flips on the keys. */
.k-confirm[data-method="CARD"]   { background: var(--card);   color: var(--ink); }
.k-confirm[data-method="MOBILE"] { background: var(--mobile); color: #fff; }
.k-confirm[data-method="CREDIT"] { background: var(--credit); color: var(--ink); }

.k-confirm__inner { display: grid; justify-items: center; gap: 14px; padding: 24px; }

.k-confirm__mark { width: 46px; height: 46px; background: currentColor; opacity: 0.9; }

.k-confirm__amount {
  /* customerFacingTotalSp 64: readable across a counter, and upside down. */
  font-size: clamp(64px, 22vw, 120px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
}
.k-confirm__who { font-size: 22px; opacity: 0.92; text-align: center; }

@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ======================================================================= */
/* SHEETS                                                                  */
/* ======================================================================= */

.k-sheet {
  position: fixed;
  inset: 0;
  background: rgba(20, 20, 15, 0.46);
  display: grid;
  align-items: end;
  z-index: 50;
}
.k-sheet[hidden] { display: none; }

.k-sheet__panel {
  background: var(--ground);
  border-radius: 20px 20px 0 0;
  padding: 20px 16px max(20px, env(safe-area-inset-bottom));
  display: grid;
  gap: 14px;
  animation: slide 160ms ease-out;
  max-height: 88dvh;
  overflow-y: auto;
}
@keyframes slide { from { transform: translateY(16px); } to { transform: none; } }

.k-sheet__title { margin: 0; font-size: 22px; font-weight: 700; }
.k-sheet__body  { margin: 0; font-size: 18px; color: var(--ink-soft); }
.k-sheet__actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

.k-btn {
  min-height: 56px;
  border-radius: var(--radius);
  background: var(--money);
  color: #fff;
  font-size: 18px;
  font-weight: 600;
  padding: 0 16px;
}
.k-btn:active { filter: brightness(1.12); }
.k-btn--quiet { background: var(--ground-sunk); color: var(--ink); }
.k-btn--wide  { width: 100%; }

.k-input {
  min-height: 56px;
  border-radius: var(--radius);
  border: 2px solid var(--rule);
  background: #fff;
  padding: 0 14px;
  font-size: 20px;
  width: 100%;
}
.k-input:focus { border-color: var(--money); outline: none; }
.k-input--num { font-size: 30px; font-weight: 700; text-align: right; }

.k-who { display: grid; gap: 8px; max-height: 34dvh; overflow-y: auto; }
.k-who button {
  min-height: 56px;
  border-radius: var(--radius);
  background: var(--ground-sunk);
  text-align: left;
  padding: 0 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 18px;
}
.k-who button[aria-pressed="true"] {
  background: var(--money);
  color: #fff;
}
.k-who span:last-child { font-weight: 700; font-variant-numeric: tabular-nums; }

/* ======================================================================= */
/* THE BOOKS                                                               */
/* ======================================================================= */

.k-books {
  position: fixed;
  inset: 0;
  background: var(--ground);
  display: grid;
  grid-template-rows: auto 1fr;
  z-index: 30;
}
.k-books[hidden] { display: none; }

.k-books__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: max(8px, env(safe-area-inset-top)) 12px 8px;
  border-bottom: 2px solid var(--rule);
}
.k-books__title { margin: 0; font-size: 20px; font-weight: 700; flex: 1; }
.k-books__date { font-size: 18px; color: var(--ink-soft); }

.k-back {
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: var(--radius);
  margin-left: -6px;
}
.k-back:active { background: var(--ground-sunk); }
.k-back svg { width: 28px; height: 28px; }

.k-books__scroll {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 12px 12px max(24px, env(safe-area-inset-bottom));
  display: grid;
  gap: 12px;
  align-content: start;
}

.k-card {
  background: #fff;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  padding: 14px;
  display: grid;
  gap: 10px;
}
.k-card--lead { background: var(--money); border-color: var(--money); color: #fff; }
.k-card__label { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: 0.04em;
                 text-transform: uppercase; opacity: 0.82; }
.k-card__note  { margin: 0; font-size: 18px; color: var(--ink-soft); }
.k-card--lead .k-card__note { color: rgba(255,255,255,0.86); }

.k-figure { margin: 0; font-size: 44px; font-weight: 800; line-height: 1; letter-spacing: -0.02em; }

.k-split, .k-owed { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.k-split li, .k-owed li {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 18px;
  padding: 6px 0;
  border-bottom: 1px solid var(--rule);
}
.k-split li:last-child, .k-owed li:last-child { border-bottom: 0; }
.k-split b, .k-owed b { font-weight: 700; }

.k-swatch { width: 14px; height: 14px; border-radius: 3px; flex: none; margin-right: 8px; }

.k-result { font-size: 18px; border-radius: var(--radius); padding: 12px; display: grid; gap: 6px; }
.k-result[data-label="reconciled"]       { background: #E7F1EA; color: #08421F; }
.k-result[data-label="not written down"] { background: #F6EDDF; color: var(--unrecorded); }
.k-result[data-label="short"]            { background: #F6E4E4; color: var(--short); }
.k-result b { font-size: 26px; }

.k-meta { margin: 0; display: grid; grid-template-columns: 1fr auto; gap: 6px 12px; font-size: 16px; }
.k-meta dt { color: var(--ink-soft); }
.k-meta dd { margin: 0; font-weight: 600; text-align: right; }

/* ======================================================================= */

.k-toast {
  position: fixed;
  left: 50%; bottom: calc(16px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  background: var(--ink);
  color: var(--ground);
  padding: 12px 18px;
  border-radius: 999px;
  font-size: 16px;
  z-index: 60;
  max-width: calc(100vw - 32px);
  text-align: center;
}
.k-toast[hidden] { display: none; }

/* A bigger screen is a bigger counter, never a desktop layout. The person is
   still holding it one-handed. */
@media (min-width: 560px) {
  .k-counter { max-width: 520px; margin: 0 auto; }
  .k-books__scroll { max-width: 620px; margin: 0 auto; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* The counting aid. Numerals only. */
.k-denoms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 8px;
}
.k-denom {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 6px;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  padding: 4px 4px 4px 0;
  background: var(--ground);
}
.k-denom[data-counted="true"] { border-color: var(--money); background: #F1F6F2; }

.k-denom__add {
  min-height: 56px;
  border-radius: 10px;
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  padding: 0 10px;
  width: 100%;
}
.k-denom__add:active { background: var(--ground-sunk); }

.k-denom__n {
  font-size: 17px;
  font-weight: 700;
  color: var(--money);
  min-width: 34px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.k-denom__sub {
  width: 56px; height: 56px;
  border-radius: 10px;
  font-size: 24px;
  line-height: 1;
  color: var(--ink-soft);
  background: var(--ground-sunk);
}
.k-denom__sub[disabled] { opacity: 0.25; }

/* ---- tiles. Learned, never configured. Absent on day one. --------------- */
.k-tiles {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.k-tiles::-webkit-scrollbar { display: none; }
.k-tiles[hidden] { display: none; }

.k-tile {
  flex: 0 0 auto;
  min-width: 92px;
  min-height: 56px;
  border-radius: var(--radius);
  background: var(--ground-sunk);
  border: 2px solid transparent;
  padding: 6px 10px;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "name left" "price left";
  align-items: center;
  gap: 0 8px;
  text-align: left;
}
.k-tile[data-on="true"] { border-color: var(--money); background: #EAF2EC; }
.k-tile[data-empty="true"] { opacity: 0.55; }
.k-tile__name  { grid-area: name;  font-size: 18px; font-weight: 600; white-space: nowrap;
                 overflow: hidden; text-overflow: ellipsis; max-width: 110px; }
.k-tile__price { grid-area: price; font-size: 18px; color: var(--ink-soft);
                 font-variant-numeric: tabular-nums; }
.k-tile__left  { grid-area: left;  font-size: 20px; font-weight: 700; color: var(--money);
                 font-variant-numeric: tabular-nums; }
.k-tile[data-empty="true"] .k-tile__left { color: var(--short); }

/* ---- stock in the Books ------------------------------------------------ */
.k-card__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.k-btn--small { min-height: 56px; padding: 0 14px; font-size: 16px; }

.k-stock { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.k-stock li { display: grid; gap: 2px; padding-bottom: 8px; border-bottom: 1px solid var(--rule); }
.k-stock li:last-child { border-bottom: 0; padding-bottom: 0; }
.k-stock__top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
                font-size: 18px; }
.k-stock__qty { font-weight: 700; font-variant-numeric: tabular-nums; }
.k-stock__qty[data-out="true"] { color: var(--short); }
.k-stock__bot { font-size: 18px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.k-stock__note { font-size: 18px; color: var(--unrecorded); border-bottom: 0; }

/* ---- the take-in sheet ------------------------------------------------- */
.k-field { display: grid; gap: 6px; }
.k-field > span { font-size: 18px; color: var(--ink-soft); }
.k-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.k-field--unit .k-input { text-align: left; }

.k-margin {
  border-radius: var(--radius);
  padding: 12px;
  font-size: 18px;
  background: #E7F1EA;
  color: #08421F;
}
.k-margin[data-sign="thin"] { background: #F6EDDF; color: var(--unrecorded); }
.k-margin[data-sign="loss"] { background: #F6E4E4; color: var(--short); }

/* A screen that did not start. Named rather than hidden, because a gap nobody
   can explain is worse than a gap with a label on it. */
.k-card--dead { border-style: dashed; opacity: 0.7; }

/* ---- the tender photographs -------------------------------------------
 *
 * The photograph is the MARK inside the key, not the key itself. That is
 * deliberate: if a photograph filled the key it would take the key's colour
 * with it, and the alternating dark/light luminance is the channel that
 * survives a dichromacy and direct sun. So the photograph is ADDITIVE. It adds
 * recognition, which needs no learning, on top of a colour and a position that
 * already work without it.
 *
 * Cash keeps the plain shape until its photograph arrives, and a shape beside
 * three photographs is honest about that rather than hiding it.
 */
.k-tender__mark[data-photo] {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background-size: cover;
  background-position: center;
  box-shadow: 0 0 0 2px rgba(255,255,255,0.85);
}
[data-method="CARD"]   .k-tender__mark[data-photo],
[data-method="CREDIT"] .k-tender__mark[data-photo] {
  box-shadow: 0 0 0 2px rgba(20,20,15,0.55);
}
[data-method="CASH"]   .k-tender__mark[data-photo] { background-image: url('/img/tender-cash.jpg'); }
[data-method="CARD"]   .k-tender__mark[data-photo] { background-image: url('/img/tender-card.jpg'); }
[data-method="MOBILE"] .k-tender__mark[data-photo] { background-image: url('/img/tender-phone.jpg'); }
[data-method="CREDIT"] .k-tender__mark[data-photo] { background-image: url('/img/tender-book.jpg'); }

/* The photograph is larger than the shape it replaces, so the key needs the room */
.k-tender:has(.k-tender__mark[data-photo]) { padding-top: 6px; }


/* ---- the screen container ---------------------------------------------
 *
 * A plain wrapper. Every screen renders its own .k-card sections inside it, so
 * this must NOT be a card: nesting one inside another doubled the border and
 * spent 28 px of a 360 px screen on padding.
 *
 * The !important is load-bearing rather than lazy. The registry hides a screen
 * that threw by setting `root.hidden = true`, and the UA rule for [hidden] is
 * beaten by any class selector that sets display. Without this, a screen that
 * drew wrong once would keep being shown.
 */
.k-screen { display: grid; gap: 12px; }
.k-screen[hidden] { display: none !important; }

/* LAYOUT.minTypeSp is 18 and LAYOUT.minTouchDp is 56. Several sizes in this
 * file sat below both, and this file's own header settles it: where the two
 * disagree, interaction.js is right and the CSS is the defect. Three separate
 * screen authors reported it independently before it was corrected. */
