/* Kaliputih Resto — web app styles.
 *
 * Loaded LAST, after the vendored tokens/components and kp-overrides. Every value here
 * resolves to a design token: there should be no raw hex and no px font-size in this file
 * except the documented 16px control floor (iOS Safari zooms anything smaller on focus).
 *
 * Class names are a frozen contract — ~70 of them are emitted from JS string literals and
 * nine are used in querySelector/closest (.seg-menu .seg-items .seg-item .seg-label
 * .seg-pax .seg-del .seg-row .addseg .field). Renaming one produces an unstyled element,
 * not an error. So the names stay and only the values move onto the brand.
 *
 * Interactive controls are --control-h-md (44px) tall. The design system sets
 * --tap-min:44px "comfortable for on-coach thumbs"; before this pass 24 of 25 controls
 * were under it.
 */

/* ─── base ───────────────────────────────────────────────────────────────── */
body {
  font: var(--type-body);
  background: var(--surface-page);
  color: var(--text-body);
}

/* ─── login ──────────────────────────────────────────────────────────────── */
.wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: var(--space-5); }
.card {
  background: var(--surface-card);
  width: 100%; max-width: 380px;
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  box-shadow: var(--shadow-md);
}
h1 { font: var(--type-heading-1); color: var(--text-heading); margin: 0 0 var(--space-1); }
/* Mark + wordmark side by side — the same lockup the topbar uses, for the same reason:
   the stacked lockup's "RESTO" is illegible small (see .logo .wordmark at the bottom of
   this file). Left-aligned, not centred: p.sub, every label and every input in this card
   are left-aligned, and a centred lockup above them reads as two unrelated blocks. Nearly
   twice the topbar's 22x28, to carry the visual weight of the 30px heading it replaces:
   the login card is the brand moment and has the room, whereas the topbar is a 60px strip
   that also has to carry a screen title. */
h1.brand { display: flex; align-items: center; gap: var(--space-3); margin: 0 0 var(--space-3); }
h1.brand .mark     { flex: none; width: 40px;  height: 52px; display: block; }
h1.brand .wordmark { flex: none; height: 34px; width: auto;  display: block; }
p.sub { margin: 0 0 var(--space-3); color: var(--text-muted); font: var(--type-body-sm); }

/* Field labels carry the brand's small-caps signal: uppercase, wide tracking. */
label {
  display: block;
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-heading);
  margin: var(--space-4) 0 var(--space-2);
}

/* ─── controls ───────────────────────────────────────────────────────────── */
/* One rule, one height token. Height is explicit rather than derived from padding +
   line-height, which is why date/time no longer need their old 41px pin to line up.
   16px is the iOS Safari zoom-on-focus floor — never lower it. */
input, select, textarea,
.c-search,
.form input, .form select, .form textarea,
.d-act input, .d-act select,
.seg-row input, .seg-row select,
.bar input[type=date] {
  width: 100%;
  height: var(--control-h-md);
  padding: 0 var(--space-3);
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--text-body);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-md);
  transition: var(--transition-control);
}
textarea, .form textarea {
  height: auto;
  min-height: calc(var(--control-h-md) * 1.6);
  padding: var(--space-3);
  line-height: var(--leading-normal);
  font-family: var(--font-body);
  resize: vertical;
}
input:hover:not(:disabled), select:hover:not(:disabled) { border-color: var(--kp-sand-400); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--kp-rust);
  box-shadow: 0 0 0 3px var(--kp-rust-050);
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-sunken);
  color: var(--text-muted);
  cursor: not-allowed;
}
/* date/time render with native metrics on mobile Safari and ignore height unless
   appearance is reset; scoped off <select> so it keeps its arrow. */
.form input[type="date"], .form input[type="time"], .bar input[type=date] {
  -webkit-appearance: none; appearance: none; min-width: 0;
}
/* The dish selects are emitted bare from JS, so they get the caret drawn on themselves. */
.form select, .seg-row select, .d-act select {
  -webkit-appearance: none; appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%231b1b60' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
}

/* ─── buttons ────────────────────────────────────────────────────────────── */
button {
  width: 100%;
  margin-top: var(--space-4);
  height: var(--control-h-md);
  padding: 0 var(--space-5);
  font-family: var(--font-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-on-accent);
  background: var(--kp-rust);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: var(--transition-control);
}
button:hover:not(:disabled) { background: var(--kp-rust-700); }
button:active:not(:disabled) { transform: translateY(1px); }
button:disabled { opacity: .38; cursor: not-allowed; transform: none; }

/* The back button on every screen. It was ~16px tall — the negative margin keeps it
   optically aligned to the content edge while the hit box reaches 44px. */
button.link {
  background: none; color: var(--text-heading);
  width: auto; margin: 0;
  min-height: var(--tap-min);
  display: inline-flex; align-items: center;
  padding: 0 var(--space-3); margin-left: calc(var(--space-3) * -1);
  font-size: var(--text-xs);
  text-transform: uppercase; letter-spacing: var(--tracking-wide);
}
button.link:hover { background: var(--kp-navy-050); }

button.ghost { background: transparent; color: var(--kp-navy); border-color: var(--kp-navy); }
button.ghost:hover:not(:disabled) { background: var(--kp-navy); color: var(--text-on-dark); }
button.danger { background: transparent; color: var(--status-danger); border-color: var(--kp-rust-100); }
button.danger:hover:not(:disabled) { background: var(--status-danger-soft); }
/* Compact nav buttons: still 44px tall (tap target), just narrower. */
.newbtn { width: auto; margin: 0; padding: 0 var(--space-4); font-size: var(--text-2xs); }
.newbtn.secondary { background: transparent; color: var(--kp-navy); border-color: var(--border-subtle); }
.newbtn.secondary:hover:not(:disabled) { background: var(--kp-navy-050); border-color: var(--kp-navy); }

/* ─── messages ───────────────────────────────────────────────────────────── */
.err, .d-err { color: var(--status-danger); font: var(--type-body-sm); margin-top: var(--space-3); min-height: 18px; }
.warn {
  background: var(--status-warning-soft);
  border: var(--border-width) solid var(--status-warning);
  color: var(--status-warning);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  font: var(--type-body-sm);
  margin-top: var(--space-3);
}
.warn b { display: block; margin-bottom: var(--space-1); color: inherit; }
.warn ul { margin: 0; padding-left: var(--space-5); }
.warn li { margin: 2px 0; }
.cap-ok, .hint { color: var(--text-muted); font: var(--type-caption); margin-top: var(--space-2); }
/* "Tidak menerima kode?" + the resend button on one line, wrapping on a narrow phone.
   The button keeps its own 44px tap target; the row only supplies the alignment. */
.resend { display: flex; align-items: center; justify-content: center; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-3); }
.resend .hint { margin-top: 0; }
.resend button.link { margin-top: 0; }
/* While counting down the button is disabled, so it must not read as tappable. */
.resend button.link:disabled { opacity: .55; cursor: default; background: transparent; }

/* ─── topbar ─────────────────────────────────────────────────────────────── */
.topbar {
  display: flex; justify-content: space-between; align-items: center; gap: var(--space-3);
  padding: 0 var(--gutter-mobile);
  height: 60px;
  background: var(--surface-card);
  border-bottom: var(--border-width) solid var(--border-subtle);
  position: sticky; top: 0; z-index: 5;
}
/* On the dashboard this holds the brand name; on the other screens it holds the screen
   title ("Reservasi baru", "Kontak"), so the text can never be hidden — it has to fit.
   nowrap + ellipsis: the title truncates rather than pushing the row to two lines. */
.logo {
  display: flex; align-items: center; gap: var(--space-2);
  font-family: var(--font-display); font-weight: var(--weight-bold);
  font-size: var(--text-sm); color: var(--text-heading);
  letter-spacing: var(--tracking-display);
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.logo .mark { flex: none; width: 22px; height: 28px; display: block; }
.user { display: flex; align-items: center; gap: var(--space-2); flex: none; }
/* The role chip wrapped to three lines at 375px. Show the role only — the full number is
   in the title attribute — and drop it entirely on the narrowest phones so the screen
   title keeps its room. */
.chip {
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border-subtle);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
@media (max-width: 430px) { .chip { display: none; } }

/* Panduan is an <a> and Keluar a <button>, but in the topbar they are the same thing —
   two nav links. --text-link is rust, which made one shout and the other stay quiet. */
.topbar .d-link { color: var(--text-heading); font-size: var(--text-2xs); padding: 0 var(--space-2); }
.topbar .d-link:hover { color: var(--text-accent); }
.topbar button.link { font-size: var(--text-2xs); padding: 0 var(--space-2); margin-left: 0; }

/* ─── page + date bar ────────────────────────────────────────────────────── */
.page { max-width: var(--container-narrow); margin: 0 auto; padding: var(--space-4); }
.bar { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-bottom: var(--space-4); }
.seg {
  display: inline-flex; gap: var(--space-1);
  background: var(--surface-sunken);
  border-radius: var(--radius-pill);
  padding: var(--space-1);
}
.seg button {
  /* 44px, not the 36px a pill tab would normally take — this is a phone-first tool and
     --tap-min applies to the day switcher as much as anything else. */
  width: auto; margin: 0; height: var(--control-h-md); padding: 0 var(--space-4);
  background: transparent; color: var(--text-muted);
  border-radius: var(--radius-pill); border: 0;
}
.seg button:hover:not(.active) { color: var(--kp-navy); background: transparent; }
.seg button.active, .seg button.active:hover { background: var(--kp-navy); color: var(--text-on-dark); }
/* No margin-left:auto. .page caps this bar at 688px while its controls need ~954px on one
   line, so it wraps at EVERY width — there is no single row for an auto margin to
   right-align against. All it did was strand the date input behind a void on whichever
   wrapped row it landed on, and the void's width changed with the operator's ROLE
   (73/96/187px at 375px) because the Laporan and Function Order buttons are permission-
   gated. Every other gap in the bar is 8px. */
.bar input[type=date] { width: auto; flex: 0 0 auto; }
.sumhead { margin: 0 0 var(--space-3); font: var(--type-heading-2); color: var(--text-heading); }

/* ─── stat tiles ─────────────────────────────────────────────────────────── */
.stats { display: flex; gap: var(--space-3); margin-bottom: var(--space-5); }
.stat {
  flex: 1; background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4);
}
.stat .n { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); color: var(--text-heading); line-height: 1; }
.stat .k, .avail h4, .money .k {
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  margin-top: var(--space-2);
}

/* ─── availability strip ─────────────────────────────────────────────────── */
.avail {
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-5);
}
.avail h4 { margin: 0 0 var(--space-2); font-weight: var(--weight-semibold); }
.av-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-1) 0; font: var(--type-body-sm); }
.av-lab { flex: 0 0 118px; color: var(--text-muted); }
.av-bar { flex: 1; display: block; height: 7px; background: var(--surface-sunken); border-radius: var(--radius-pill); overflow: hidden; }
/* block, not inline — an inline span ignores height/width and the bar stays empty */
.av-fill { display: block; height: 100%; min-width: 2px; background: var(--kp-forest-300); border-radius: var(--radius-pill); }
.av-fill.hot { background: var(--status-warning); }
.av-fill.full { background: var(--status-danger); }
.av-num { flex: 0 0 auto; font-variant-numeric: tabular-nums; font-weight: var(--weight-semibold); color: var(--text-heading); }
.av-num small { font-weight: var(--weight-regular); color: var(--text-muted); }

/* ─── reservation cards ──────────────────────────────────────────────────── */
#list { display: grid; gap: var(--space-3); }
.res {
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-left: 4px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  cursor: pointer;
  transition: var(--transition-control);
}
.res:hover { box-shadow: var(--shadow-md); border-color: var(--kp-navy-100); }
.res.ok { border-left-color: var(--status-success); }
.res.wait { border-left-color: var(--status-warning); }
/* Two rows, not one: group names here are school names ("SMK Muhammadiyah 2 Kertosono")
   and wrapping one inside a flex row shoved the time and badge apart vertically. Time and
   status share the top line; the name gets the full width below. */
.res-top {
  display: grid; grid-template-columns: auto 1fr;
  column-gap: var(--space-3); row-gap: var(--space-1); align-items: center;
}
.time { grid-column: 1; grid-row: 1; font-weight: var(--weight-bold); color: var(--text-heading); font-variant-numeric: tabular-nums; font-size: var(--text-sm); }
.res-top .badge { grid-column: 2; grid-row: 1; justify-self: end; }
.grp { grid-column: 1 / -1; grid-row: 2; font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-md); color: var(--text-heading); letter-spacing: var(--tracking-display); min-width: 0; }
.badge {
  flex: none;
  font-family: var(--font-secondary);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.badge.ok { background: var(--status-success-soft); color: var(--status-success); }
.badge.wait { background: var(--status-warning-soft); color: var(--status-warning); }
.meta { font: var(--type-body-sm); color: var(--text-muted); margin-top: var(--space-2); }
.menu { margin-top: var(--space-2); display: flex; flex-wrap: wrap; gap: var(--space-2); }
.item, .tag, .crow .ct span {
  font-size: var(--text-xs);
  color: var(--text-body);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-3);
}
/* Split gap: the 20px column gutter is right between Total/DP/Sisa, but as a shorthand it
   also became the ROW gap, and this row wraps constantly — a Rp7.500.000 trio already
   wraps at 375px, and at 360px even a Rp2.500.000 trio does. Wrapped rows then sat 63px
   apart. Tightening the column gutter cannot avoid the wrap (even 8px still overflows), so
   the row gap is the thing to fix. NOT row-gap 0 as in .d-docs: these children carry no
   built-in slack (.money .k zeroes its top margin), so 0 would butt the second row's label
   straight against the first row's figure. */
.money { margin-top: var(--space-3); padding-top: var(--space-3); border-top: var(--border-width) dashed var(--border-subtle); display: flex; column-gap: var(--space-5); row-gap: var(--space-2); flex-wrap: wrap; }
.money .k { margin-top: 0; }
.money b { display: block; font-size: var(--text-sm); font-variant-numeric: tabular-nums; margin-top: 2px; color: var(--text-heading); }
.tags { margin-top: var(--space-3); display: flex; gap: var(--space-2); flex-wrap: wrap; }
.tag { color: var(--text-muted); background: var(--surface-sunken); border-color: transparent; }
.empty {
  color: var(--text-muted); font: var(--type-body-sm);
  padding: var(--space-10) var(--space-4); text-align: center;
  background: var(--surface-card);
  border: var(--border-width) dashed var(--border-subtle);
  border-radius: var(--radius-lg);
}

/* ─── detail sheet ───────────────────────────────────────────────────────── */
.overlay { position: fixed; inset: 0; background: rgba(16,16,56,.6); display: none; align-items: flex-end; justify-content: center; z-index: 50; }
@media (min-width: 560px) { .overlay { align-items: center; padding: var(--space-5); } }
.sheet {
  background: var(--surface-card); width: 100%; max-width: 480px;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  padding: var(--space-6); max-height: 92vh; overflow: auto;
  box-shadow: var(--shadow-overlay);
}
@media (min-width: 560px) { .sheet { border-radius: var(--radius-xl); } }
.d-head { display: flex; align-items: flex-start; gap: var(--space-3); justify-content: space-between; margin-bottom: var(--space-4); }
.d-grp { font: var(--type-heading-2); color: var(--text-heading); }
.d-sub { color: var(--text-muted); font: var(--type-caption); margin-top: 3px; }
.d-rows { border-top: var(--border-width) solid var(--border-subtle); }
.d-row { display: flex; justify-content: space-between; gap: var(--space-4); padding: var(--space-2) 0; border-bottom: var(--border-width) solid var(--border-subtle); font: var(--type-body-sm); }
.d-k { color: var(--text-muted); }
.d-v { text-align: right; font-weight: var(--weight-semibold); color: var(--text-heading); }
.d-row.long { display: block; }
.d-row.long .d-v { display: block; text-align: left; font-weight: var(--weight-regular); color: var(--text-body); margin-top: 3px; white-space: pre-wrap; }
.d-items { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: flex-end; }
/* row-gap 0, not --space-4. Each .d-link is already a 44px tap target (--tap-min) around
   12px text, so a symmetric gap stacked a further 16px on top of ~32px of built-in dead
   space and pushed wrapped rows 60px apart. The tap targets alone separate the rows. */
.d-docs { display: flex; column-gap: var(--space-4); row-gap: 0; flex-wrap: wrap; margin-top: var(--space-3); }
.d-link {
  display: inline-flex; align-items: center; min-height: var(--tap-min);
  font-family: var(--font-secondary); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  font-weight: var(--weight-medium); color: var(--text-link);
  text-decoration: none; border-bottom: 0;
}
.d-link:hover { color: var(--text-link-hover); }
.d-act { margin-top: var(--space-4); background: var(--surface-raised); border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-lg); padding: var(--space-4); }
.d-actt { font-family: var(--font-secondary); font-size: var(--text-2xs); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--text-heading); margin-bottom: var(--space-3); }
.d-act select, .d-act input { margin-bottom: var(--space-3); }
.d-act button, .d-foot button { margin: 0; }
/* A .d-act that is a message + a button (Selesai) has no select/input to carry the
   rhythm, and the rule above zeroes the button's own margin — so the gap comes from
   here. Must stay AFTER that rule: both selectors are (0,1,1), so source order decides. */
.d-actm + button { margin-top: var(--space-3); }
/* flex-wrap, because these never shrink below min-content and so OVERFLOW rather than
   wrap. The contact card's footer (Ubah kontak / Aktifkan lagi / Tutup) runs 15px past the
   sheet at 360px. flex-basis must be min-content, not auto: flexbox decides wrapping on
   the basis, and `auto` resolves to max-content, which would wrap that footer onto two
   rows even at 430px. width:auto is needed too, or the basis inherits the width:100% the
   bare `button` rule sets. */
.d-foot { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); }
/* nowrap matches .kp-btn: a button label never breaks across lines. Without it,
   flex-basis:min-content shrinks the button to its longest WORD and "Ubah kontak" splits
   over two lines inside a 44px pill. With it, min-content is the whole label, so the row
   wraps instead of the text — which is the right thing to give up when space runs out. */
.d-foot button { flex-grow: 1; flex-shrink: 1; flex-basis: min-content; width: auto; white-space: nowrap; }

/* ─── marketing report ───────────────────────────────────────────────────── */
.rep-month { font-family: var(--font-secondary); font-size: var(--text-2xs); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--text-accent); margin: var(--space-5) 0 var(--space-2); }
.rep-table { background: var(--surface-card); border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-lg); overflow: hidden; }
.rep-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-bottom: var(--border-width) solid var(--border-subtle); font: var(--type-body-sm); }
.rep-row:last-child { border-bottom: 0; }
.rep-mkt { flex: 1; font-weight: var(--weight-semibold); color: var(--text-heading); }
.rep-n { color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rep-total { background: var(--surface-sunken); font-weight: var(--weight-bold); }
.rep-total .rep-n { color: var(--text-heading); }

/* ─── contacts ───────────────────────────────────────────────────────────── */
.c-search { margin-bottom: var(--space-4); }
.crow { background: var(--surface-card); border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-lg); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-2); cursor: pointer; transition: var(--transition-control); }
.crow:hover { box-shadow: var(--shadow-md); border-color: var(--kp-navy-100); }
.crow .cn { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-md); color: var(--text-heading); }
.crow .cm { font: var(--type-caption); color: var(--text-muted); margin-top: 3px; }
.crow .ct { margin-top: var(--space-2); display: flex; gap: var(--space-2); flex-wrap: wrap; }
.crow .ct span { color: var(--text-muted); background: var(--surface-sunken); border-color: transparent; }
.fu { margin-top: var(--space-4); }
.fu .d-actt { margin-bottom: var(--space-2); }

/* ─── CRM: reservation history on a contact card ─────────────────────────── */
.hrow { border-bottom: var(--border-width) solid var(--border-subtle); padding: var(--space-3) 0; }
.hrow:last-child { border-bottom: 0; }
/* A cancelled reservation stays in the history — it is part of the customer's
   record — but must never read as a visit. */
.hrow.off .hd, .hrow.off .hm { color: var(--text-muted); }
/* `font` shorthand first — it resets font-weight, so the weight must follow it. */
.hrow .hd { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; font: var(--type-body-sm); font-weight: var(--weight-semibold); color: var(--text-heading); }
.hrow .hm { font: var(--type-caption); color: var(--text-muted); margin-top: 3px; }
.hrow .hx { margin-top: var(--space-1); display: flex; gap: var(--space-4); align-items: center; flex-wrap: wrap; }
.hrow .hx span { font: var(--type-caption); color: var(--text-body); font-variant-numeric: tabular-nums; }
.hrow .hx .d-link { min-height: 0; }
.badge.off { background: var(--status-danger-soft); color: var(--status-danger); }

/* ─── CRM: markers, notes ────────────────────────────────────────────────── */
/* An excluded subject stays findable — it is dimmed, never hidden. */
.crow.muted { opacity: 0.6; }
/* Name left, state badges right — the same shape .res-top gives a reservation card.
   Before this the segment chip wrapped onto a line of its own in every single row. */
.crow-top { display: flex; align-items: flex-start; gap: var(--space-3); justify-content: space-between; }
.crow-top .cn { min-width: 0; }
.crow-badges { display: flex; gap: var(--space-1); flex-wrap: wrap; justify-content: flex-end; flex: none; }
/* A segment is state, so it is a Badge (per the design system, Tag is for descriptive
   labels). Bare .badge is the neutral tone; .ok/.wait/.off carry the semantic ones. */
.badge { background: var(--kp-sand-200); color: var(--kp-sand-800); }

/* Segment filter chips: ONE row that scrolls sideways. Five chips wrapped to two rows
   on a 375px screen, so the whole viewport above the fold was chrome. */
#c-filters {
  margin: var(--space-3) 0 var(--space-4);
  flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* full-bleed so a chip scrolled to the edge doesn't look clipped mid-card */
  padding-inline: var(--gutter-mobile); margin-inline: calc(-1 * var(--gutter-mobile));
}
#c-filters::-webkit-scrollbar { display: none; }
#c-filters .tag { cursor: pointer; white-space: nowrap; flex: none; }
#c-filters .tag.on { background: var(--kp-navy); color: var(--text-on-dark); border-color: transparent; }

/* The tab strip is the vendored .kp-tabs. Two deviations for a 375px phone: the
   system's --space-6 gap makes "Tindak lanjut" wrap to a second line (which breaks the
   shared baseline and the underline), and the strip must never wrap or clip — so a
   tighter gap, nowrap labels, and sideways scroll as insurance on narrower handsets. */
#crm-tabs {
  margin-bottom: var(--space-2);
  gap: var(--space-4);
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
#crm-tabs::-webkit-scrollbar { display: none; }
/* Undo the bare `button` rule in this file, which is a full-width rust PILL — a tab is
   neither. `.kp-tab` already wins on background/padding at rest (0,1,0 beats 0,0,1), but
   `button:hover:not(:disabled)` is (0,2,1) and beats it, so hovering painted a rust pill
   behind the label while `.kp-tab:hover` kept the text navy: navy on dark rust, and the
   pill radius on a text-width box made it a blob. The :hover selector here is (1,2,0),
   which is what actually settles it. */
#crm-tabs .kp-tab,
#crm-tabs .kp-tab:hover,
#crm-tabs .kp-tab:active {
  white-space: nowrap; flex: none;
  width: auto; margin: 0; height: auto; padding: 0 0 12px;
  background: transparent; border: 0; border-radius: 0; transform: none;
}
.note-item { padding: var(--space-2) 0; border-bottom: var(--border-width) solid var(--border-subtle); font: var(--type-body-sm); color: var(--text-body); white-space: pre-wrap; }
.note-item:last-child { border-bottom: 0; }
.note-when { font: var(--type-caption); color: var(--text-muted); margin-bottom: 2px; }

/* ─── CRM: loyalty rewards ───────────────────────────────────────────────── */
/* Pending reward = something the customer is owed, so it reads as an action. */
.rw {
  background: var(--surface-raised);
  border: var(--border-width) solid var(--status-warning);
  border-radius: var(--radius-md);
  padding: var(--space-3); margin-bottom: var(--space-2);
  font: var(--type-body-sm); color: var(--text-heading);
}
.rw .rw-m { font: var(--type-caption); color: var(--text-muted); margin-top: 2px; }
.rw button { margin: var(--space-3) 0 0; height: var(--control-h-md); }
/* Already handed over: a record, not a call to action. */
.rw.done { border-color: var(--border-subtle); background: var(--surface-sunken); color: var(--text-muted); }
/* WhatsApp is a first-class channel; the system gives it its own token. */
.wa {
  display: flex; align-items: center; justify-content: center;
  height: var(--control-h-md);
  text-align: center; text-decoration: none; border-bottom: 0;
  font-family: var(--font-secondary); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  border-radius: var(--radius-pill); margin-bottom: var(--space-2);
  background: var(--channel-whatsapp); color: var(--kp-white);
  border: var(--border-width) solid transparent;
  transition: var(--transition-control);
}
.wa:hover { background: #186139; color: var(--kp-white); }
/* Message templates are secondary shortcuts, so they are chips, not full-width bars.
   The design system reserves the block treatment for the sticky mobile bar and allows
   exactly one primary per view — "Chat WhatsApp" above is it. Five identical full-width
   pills stacked 8px apart read as one undifferentiated wall and pushed the rest of the
   sheet below the fold. Sizes follow .kp-btn--sm (36px tall, 11px caps). */
.fu-tpls { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* flex-grow 1, so each row of chips fills the width the way the primary button above it
   does. Left-aligned chips under a full-bleed button left a ragged void down the right of
   the block. They still never shrink below their own text (basis auto, shrink 1 only
   applies once a row is over-full), so nothing truncates. */
.wa.tpl {
  display: inline-flex; width: auto; flex: 1 1 auto;
  height: var(--control-h-sm); padding: 0 var(--space-4);
  font-size: var(--text-2xs); margin-bottom: 0;
  background: var(--channel-whatsapp-soft); color: var(--channel-whatsapp);
  border-color: var(--channel-whatsapp);
}
.wa.tpl:hover { background: var(--kp-white); color: var(--channel-whatsapp); }
/* The thank-you chip doubles as "tandai Selesai", so it is locked until the event has
   ended and the invoice is Lunas. It renders as a <span> (an <a> cannot be :disabled), and
   this makes it read as inert rather than merely pale. Placed AFTER .wa.tpl:hover on
   purpose: that selector is also three classes deep, so a tie would be settled by source
   order — the :hover pair here has to win outright. */
.wa.tpl.off, .wa.tpl.off:hover {
  background: var(--surface-sunken);
  color: var(--text-muted);
  border-color: var(--border-subtle);
  cursor: not-allowed;
}

/* ─── create-booking form ────────────────────────────────────────────────── */
.form { background: var(--surface-card); border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-lg); padding: var(--space-5); }
.form .field { margin-bottom: var(--space-3); }
.form label { margin: 0 0 var(--space-2); }
/* checkbox rows read as one line, not a stacked label + full-width control */
.form .check label { display: flex; align-items: center; gap: var(--space-2); margin: 0; min-height: var(--tap-min); font-size: var(--text-sm); text-transform: none; letter-spacing: normal; font-family: var(--font-body); color: var(--text-body); cursor: pointer; }
.form .check input { width: auto; height: auto; flex: 0 0 auto; accent-color: var(--kp-rust); transform: scale(1.3); margin-right: var(--space-1); }
.row2 { display: flex; gap: var(--space-3); }
.row2 .field { flex: 1; }
/* Stacking every pair doubles the form height on a phone, and with 44px controls that
   hurts. Only the two text pairs stack; short numeric pairs stay side by side — at 375px
   each column is ~163px, comfortably enough for 30/07/2026. */
@media (max-width: 430px) {
  .row2:not(.row2--tight) { flex-direction: column; gap: 0; }
}
.seg-row { border: var(--border-width) solid var(--border-subtle); background: var(--surface-raised); border-radius: var(--radius-lg); padding: var(--space-3); margin-bottom: var(--space-3); }
/* Two rows: label + delete, then pax + paket. The paket select was flex:2 1 150px and
   truncated "Paket Istimewa · Ikan Fillet Asam Manis". */
/* Row 1: label + delete.  Row 2: pax + paket.
   The paket select was flex:2 1 150px and truncated "Paket Istimewa · Ikan Fillet Asam
   Manis"; giving it most of a row fixes that. Explicit grid-area on all four, because
   auto-placement put the delete button on a row of its own. */
.seg-head { display: grid; grid-template-columns: 96px 1fr var(--control-h-md); gap: var(--space-2); align-items: center; }
.seg-row .seg-label { grid-area: 1 / 1 / 2 / 3; }
.seg-row .seg-del   { grid-area: 1 / 3 / 2 / 4; }
.seg-row .seg-pax   { grid-area: 2 / 1 / 3 / 2; }
.seg-row .seg-menu  { grid-area: 2 / 2 / 3 / 4; }
/* Collapsed by default. display:none, never removed from the DOM — collectForm() reads
   row.querySelectorAll(".seg-item") whether the grid is open or shut, so the submit path
   is identical either way. That is the whole reason to do it this way. */
.seg-sum { display: flex; align-items: flex-start; gap: var(--space-2); margin-top: var(--space-3); }
.seg-chips { flex: 1; display: flex; flex-wrap: wrap; gap: var(--space-1); min-width: 0; }
.seg-chips .item { font-size: var(--text-2xs); padding: 2px var(--space-2); background: var(--surface-sunken); border-color: transparent; color: var(--text-muted); }
.seg-toggle { flex: none; }
.seg-itemsL, .seg-items { display: none; }
.seg-row.open .seg-itemsL { display: block; font-family: var(--font-secondary); font-size: var(--text-2xs); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--text-muted); margin: var(--space-3) 0 var(--space-2); }
.seg-row.open .seg-items { display: grid; grid-template-columns: 1fr; gap: var(--space-2); }
.seg-row.open .seg-sum .seg-chips { display: none; }
.seg-del {
  width: var(--control-h-md); height: var(--control-h-md);
  margin: 0; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--status-danger);
  border: 0; border-radius: var(--radius-pill);
  font-size: var(--text-lg); line-height: 1;
}
.seg-del:hover { background: var(--status-danger-soft); }
.addseg { margin: var(--space-1) 0 var(--space-3); }
.pv { margin-top: var(--space-4); border-top: var(--border-width) dashed var(--border-subtle); padding-top: var(--space-4); }
.pv .li { display: flex; justify-content: space-between; gap: var(--space-3); font: var(--type-body-sm); margin-bottom: var(--space-1); }
.pv .tot { display: flex; justify-content: space-between; font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-lg); color: var(--text-heading); margin-top: var(--space-2); padding-top: var(--space-2); border-top: var(--border-width) solid var(--border-subtle); }
.pv .dp { font: var(--type-body-sm); color: var(--text-muted); margin-top: var(--space-2); }

/* ─── toasts ─────────────────────────────────────────────────────────────── */
/* z-index 70 sits above the confirm dialog's scrim (60) and the detail sheet (50). */
#toasts {
  position: fixed; left: 0; right: 0;
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  z-index: 70; pointer-events: none; padding: 0 var(--space-4);
}

.seg-chips .item.more { color: var(--text-accent); background: var(--kp-rust-050); }

/* The brand name is artwork, not type. Alegreya is the display face; the wordmark has
   its own drawn letterforms (the system reserves --font-logo "Rions" for it, which we
   do not ship). The full lockup is stacked — mark over KALIPUTIH over RESTO — and its
   "RESTO" is illegible below ~48px, so a 60px topbar uses mark + wordmark side by side.
   Only the dashboard shows it; the other screens put a page title in that slot. */
.logo .wordmark { flex: none; height: 20px; width: auto; display: block; }
