/* ============================================================================
   Design-system component layer (SRS §46) — the app-* components that had no
   definition anywhere: app-section, app-summary-card, app-resource-card,
   app-checkbox, app-switch, app-btn-icon, app-loading, app-modal, app-confirm,
   app-popover, app-tooltip, app-cart, app-calendar, app-credit-balance,
   app-usage-meter, app-timeline. Specs: docs/design-system/03–06.

   WHY PLAIN CSS: the same two constraints documented at the top of app-util.css.
   Styles/app.css is compiled by the Tailwind CLI and no Node toolchain is
   installed, so new @apply rules would never reach wwwroot/css/app.css; and the
   CSP (style-src 'self') drops every style="" attribute.

   DYNAMIC SIZES (meter fills, calendar blocks): never write style="" in Razor.
   Either use a native element that carries its own value (<meter>, <progress>),
   or bind with Alpine's OBJECT syntax — :style="{ width: pct + '%' }" — which
   goes through the CSSOM and is allowed by the CSP. Alpine's STRING syntax
   (:style="'width:' + pct + '%'") sets the style attribute and is blocked.

   PALETTE: the literal values already used across app.css / app-util.css —
   text #0F172A / #475569 / #64748B, border #E2E8F0, tint #F8FAFC / #F1F5F9,
   brand #9E4323 (hover #85361A, 50 #FDF6F3, 200 #F3D1C3), and the status
   colours of .app-seat / .app-resource-status so a state reads the same
   everywhere: available #047857, reserved #B54D00, occupied #0C66E4,
   maintenance #475569, blocked #BE123C, danger #D1242F.

   Components that were already defined elsewhere are NOT redefined here:
   app-drawer, app-seat-map, app-resource-status (app-util.css); app-card,
   app-stat-card, app-btn-*, app-input, app-badge-*, app-status, app-skeleton,
   app-empty-state, app-modal-backdrop / app-modal-panel (app.css).
   ============================================================================ */


/* --- Shared: visually hidden text for icon-only controls and spinners ------- */
.app-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}


/* ============================================================================
   LAYOUT — app-section (02)
   A titled block inside a page: header row (title, optional sub-line, actions
   on the right) then body. Sections stack with consistent vertical rhythm.
   <section class="app-section">
     <header class="app-section-header">
       <div><h2 class="app-section-title">…</h2><p class="app-section-sub">…</p></div>
       <div class="app-section-actions">…buttons…</div>
     </header>
     <div class="app-section-body">…</div>
   </section>
   ============================================================================ */
.app-section { display: flex; flex-direction: column; gap: 1rem; }
.app-section + .app-section { margin-top: 2rem; }
.app-section-header {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: .75rem 1rem;
}
.app-section-title { margin: 0; font-size: 1.25rem; line-height: 1.75rem; font-weight: 600; color: #0F172A; }
.app-section-sub { margin: .125rem 0 0; font-size: .8125rem; color: #64748B; }
.app-section-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.app-section-body { display: flex; flex-direction: column; gap: 1rem; }
/* A section drawn as a card rather than sitting on the page background. */
.app-section-boxed {
  padding: 1.25rem; background: #FFFFFF; border: 1px solid #E2E8F0; border-radius: .75rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .04);
}


/* ============================================================================
   CARDS — app-summary-card, app-resource-card (03)
   ============================================================================ */

/* Compact label/value summary (a cart review step, an upcoming booking).
   <div class="app-summary-card">
     <p class="app-summary-card-title">Booking summary</p>
     <dl class="app-summary-list"><dt>Resource</dt><dd>Meeting Room 1</dd>…</dl>
     <div class="app-summary-total"><span>Total</span><span>₹2,360.00</span></div>
   </div> */
.app-summary-card {
  display: flex; flex-direction: column; gap: .75rem;
  padding: 1rem 1.125rem; background: #FFFFFF;
  border: 1px solid #E2E8F0; border-radius: .75rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .04);
}
.app-summary-card-title {
  margin: 0; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #475569;
}
/* The label column is capped at half the width so a narrow card never squeezes
   the value down to one character per line. */
.app-summary-list {
  display: grid; grid-template-columns: fit-content(50%) minmax(0, 1fr); gap: .5rem 1rem; margin: 0; font-size: .8125rem;
}
.app-summary-list dt { color: #64748B; }
.app-summary-list dd { margin: 0; color: #0F172A; font-weight: 500; text-align: right; word-break: break-word; }
.app-summary-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-top: .75rem; border-top: 1px dashed #E2E8F0;
  font-size: .9375rem; font-weight: 700; color: #0F172A; font-variant-numeric: tabular-nums;
}
.app-summary-card-empty { margin: 0; font-size: .8125rem; color: #64748B; }
/* A totals card pinned to the right under a line-item table. */
.app-summary-card-end { max-width: 22rem; margin-left: auto; }

/* A bookable resource tile for selection grids. Use a <button> (or give the
   element role="button" + tabindex) and aria-pressed for selection, so it is
   keyboard-operable; state is never colour alone — the status badge carries text.
   <div class="app-resource-grid-select">
     <button type="button" class="app-resource-card" aria-pressed="false">
       <span class="app-resource-card-icon">…svg…</span>
       <span class="app-resource-card-name">Meeting Room 1</span>
       <span class="app-resource-card-meta">8 seats · Floor 2</span>
       <span class="app-resource-card-foot"><span class="app-badge-success">Available</span></span>
     </button>
   </div> */
.app-resource-grid-select { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: .75rem; }
.app-resource-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: .375rem;
  width: 100%; padding: .875rem 1rem; text-align: left; font: inherit;
  background: #FFFFFF; border: 1px solid #E2E8F0; border-radius: .75rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .04); cursor: pointer;
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.app-resource-card:hover { border-color: #CBD5E1; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, .06); }
.app-resource-card:focus-visible { outline: 2px solid #9E4323; outline-offset: 2px; }
/* Also usable as a <label> wrapping a visually hidden radio/checkbox (keeps native arrow-key
   radio behaviour): the ring follows the input's keyboard focus, the fill follows :checked. */
.app-resource-card:has(input:focus-visible) { outline: 2px solid #9E4323; outline-offset: 2px; }
.app-resource-card:has(input:checked) {
  border-color: #9E4323; background: #FDF6F3; box-shadow: 0 0 0 3px rgba(158, 67, 35, .15);
}
.app-resource-card[aria-pressed="true"],
.app-resource-card.is-selected {
  border-color: #9E4323; background: #FDF6F3; box-shadow: 0 0 0 3px rgba(158, 67, 35, .15);
}
.app-resource-card[aria-disabled="true"],
.app-resource-card:disabled,
.app-resource-card.is-disabled {
  cursor: not-allowed; opacity: .6; box-shadow: none; background: #F8FAFC;
}
.app-resource-card-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; border-radius: .5rem; background: #F1F5F9; color: #475569;
}
.app-resource-card[aria-pressed="true"] .app-resource-card-icon,
.app-resource-card.is-selected .app-resource-card-icon { background: #F3D1C3; color: #9E4323; }
.app-resource-card-name { font-size: .875rem; font-weight: 700; color: #0F172A; }
.app-resource-card-meta { font-size: .75rem; color: #64748B; }
.app-resource-card-foot { display: flex; align-items: center; justify-content: space-between; gap: .5rem; width: 100%; margin-top: .25rem; }


/* ============================================================================
   FORMS — app-checkbox, app-switch (03)
   Styled NATIVE inputs — never divs pretending to be checkboxes — so keyboard
   and screen-reader behaviour comes free.
   <label class="app-check-label"><input type="checkbox" class="app-checkbox"> Send receipt</label>
   <label class="app-check-label"><input type="checkbox" role="switch" class="app-switch"> Active</label>
   ============================================================================ */
.app-check-label {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .8125rem; color: #0F172A; cursor: pointer; user-select: none;
}
.app-check-label:has(input:disabled) { cursor: not-allowed; color: #94A3B8; }
.app-check-hint { display: block; font-size: .75rem; color: #64748B; }

.app-checkbox {
  width: 1rem; height: 1rem; flex: none; margin: 0;
  accent-color: #9E4323; cursor: pointer;
}
.app-checkbox:focus-visible { outline: 2px solid #9E4323; outline-offset: 2px; }
.app-checkbox:disabled { cursor: not-allowed; }

.app-switch {
  appearance: none; -webkit-appearance: none;
  position: relative; flex: none; margin: 0;
  width: 2.25rem; height: 1.25rem; border-radius: 9999px;
  background: #CBD5E1; cursor: pointer; transition: background-color .15s;
}
.app-switch::before {
  content: ""; position: absolute; top: .125rem; left: .125rem;
  width: 1rem; height: 1rem; border-radius: 9999px; background: #FFFFFF;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .25); transition: transform .15s;
}
.app-switch:checked { background: #9E4323; }
.app-switch:checked::before { transform: translateX(1rem); }
.app-switch:focus-visible { outline: 2px solid #9E4323; outline-offset: 2px; }
.app-switch:disabled { cursor: not-allowed; opacity: .5; }
@media (prefers-reduced-motion: reduce) {
  .app-switch, .app-switch::before { transition: none; }
}


/* ============================================================================
   BUTTONS — app-btn-icon (03)
   Square icon-only button. aria-label is MANDATORY (docs/design-system/10).
   <button type="button" class="app-btn-icon" aria-label="Remove line">…svg…</button>
   ============================================================================ */
.app-btn-icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 2.25rem; height: 2.25rem; padding: 0;
  border: 1px solid #E2E8F0; border-radius: .5rem; background: #FFFFFF;
  color: #475569; cursor: pointer; transition: background-color .15s, color .15s, border-color .15s;
}
.app-btn-icon:hover:not(:disabled) { background: #F1F5F9; border-color: #CBD5E1; color: #0F172A; }
.app-btn-icon:focus-visible { outline: 2px solid #9E4323; outline-offset: 2px; }
.app-btn-icon:disabled { cursor: not-allowed; opacity: .5; }
.app-btn-icon svg { width: 1rem; height: 1rem; }
.app-btn-icon-sm { width: 1.75rem; height: 1.75rem; border-radius: .375rem; }
.app-btn-icon-sm svg { width: .875rem; height: .875rem; }
/* Extra-small round variant for remove buttons inside chips and pills; inherits the chip's colour. */
.app-btn-icon-xs { width: 1.25rem; height: 1.25rem; border-radius: 9999px; border-color: transparent; background: transparent; color: inherit; }
.app-btn-icon-xs svg { width: .75rem; height: .75rem; }
.app-btn-icon-ghost { border-color: transparent; background: transparent; }
.app-btn-icon-danger:hover:not(:disabled) { background: #FFF1F2; border-color: #FDA4AF; color: #D1242F; }


/* ============================================================================
   DATA — app-loading (05)
   Small inline spinner for button-loading and partial refreshes. Initial page
   loads use app-skeleton instead. Always pair with text for screen readers:
   <span class="app-loading" role="status"><span class="app-sr-only">Loading…</span></span>
   <button class="app-btn-primary" disabled><span class="app-loading app-loading-on-brand"></span> Saving…</button>
   ============================================================================ */
.app-loading {
  display: inline-block; flex: none; vertical-align: -.125em;
  width: 1rem; height: 1rem; border-radius: 9999px;
  border: 2px solid #E2E8F0; border-top-color: #9E4323;
  animation: app-loading-spin .7s linear infinite;
}
.app-loading-sm { width: .75rem; height: .75rem; border-width: 2px; }
.app-loading-lg { width: 1.75rem; height: 1.75rem; border-width: 3px; }
/* On a filled brand/danger button the track must be light on dark. */
.app-loading-on-brand { border-color: rgba(255, 255, 255, .35); border-top-color: #FFFFFF; }
.app-loading-inline { display: inline-flex; align-items: center; gap: .5rem; font-size: .8125rem; color: #64748B; }
@keyframes app-loading-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .app-loading { animation: app-loading-pulse 1.4s ease-in-out infinite; }
  @keyframes app-loading-pulse { 50% { opacity: .35; } }
}


/* ============================================================================
   OVERLAY — app-modal, app-confirm (04)
   Pair with the existing .app-modal-backdrop (app.css). The backdrop closes the
   modal only for non-destructive, no-unsaved-input modals (04 §17).
   <div class="app-modal-backdrop" x-show="open"></div>
   <div class="app-modal app-modal-md" role="dialog" aria-modal="true" aria-labelledby="m-title" x-show="open">
     <div class="app-modal-header"><h2 id="m-title" class="app-modal-title">…</h2>
       <button class="app-btn-icon app-btn-icon-ghost" aria-label="Close">×</button></div>
     <div class="app-modal-body">…</div>
     <div class="app-modal-footer">…buttons…</div>
   </div>
   ============================================================================ */
.app-modal {
  position: fixed; left: 50%; top: 50%; z-index: 50;
  transform: translate(-50%, -50%);
  display: flex; flex-direction: column;
  width: calc(100% - 2rem); max-width: 32rem; max-height: calc(100vh - 2rem);
  background: #FFFFFF; border: 1px solid #DFE3E8; border-radius: .75rem;
  box-shadow: 0 10px 25px -5px rgba(16, 24, 40, .18), 0 8px 10px -6px rgba(16, 24, 40, .10);
}
.app-modal-sm { max-width: 24rem; }
.app-modal-md { max-width: 32rem; }
.app-modal-lg { max-width: 48rem; }
.app-modal-xl { max-width: 56rem; }
.app-modal-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: 1.125rem 1.25rem .75rem;
}
.app-modal-title { margin: 0; font-size: 1rem; font-weight: 700; color: #0F172A; }
.app-modal-sub { margin: .125rem 0 0; font-size: .8125rem; color: #64748B; }
.app-modal-body { flex: 1; overflow-y: auto; padding: .25rem 1.25rem 1rem; font-size: .8125rem; color: #334155; }
.app-modal-footer {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem;
  padding: .875rem 1.25rem; border-top: 1px solid #F1F5F9;
}
/* Mobile: the same modal becomes a bottom sheet (docs/design-system/08). */
@media (max-width: 640px) {
  .app-modal {
    top: auto; bottom: 0; left: 0; transform: none;
    width: 100%; max-width: none; max-height: 90vh;
    border-radius: 1rem 1rem 0 0; border-bottom: 0;
  }
}

/* Confirmation dialog — fixed structure, always the same shape (04 §26):
   title "<Verb> <entity>?", a consequence statement, an optional mandatory
   reason, then [Cancel][<Verb>]. Disable the danger button until a required
   reason is filled — a convenience only; the server re-validates.
   <div class="app-modal app-confirm" role="alertdialog" aria-modal="true" aria-labelledby="c-title" aria-describedby="c-body">
     <div class="app-confirm-icon" aria-hidden="true">!</div>
     <h2 id="c-title" class="app-confirm-title">Cancel booking?</h2>
     <p id="c-body" class="app-confirm-body">This releases the seat for other members.</p>
     <div class="app-confirm-reason app-field"><label class="app-label" for="c-reason">Reason</label>
       <textarea id="c-reason" class="app-textarea" required></textarea></div>
     <div class="app-confirm-actions">
       <button class="app-btn-secondary">Keep booking</button>
       <button class="app-btn-danger" :disabled="!reason.trim()">Cancel booking</button></div>
   </div> */
.app-confirm {
  max-width: 26rem; padding: 1.5rem 1.5rem 1.25rem; gap: .5rem;
}
.app-confirm-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; margin-bottom: .25rem; border-radius: 9999px;
  background: #FFF1F2; color: #D1242F; font-size: 1.125rem; font-weight: 800;
}
.app-confirm-icon svg { width: 1.25rem; height: 1.25rem; }
.app-confirm-title { margin: 0; font-size: 1.0625rem; font-weight: 700; color: #0F172A; }
.app-confirm-body { margin: 0; font-size: .8125rem; line-height: 1.5; color: #475569; }
.app-confirm-reason { margin-top: .5rem; }
.app-confirm-reason textarea { min-height: 4.5rem; width: 100%; }
.app-confirm-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; margin-top: 1rem; }
@media (max-width: 640px) {
  .app-confirm-actions { flex-direction: column-reverse; }
  .app-confirm-actions > * { width: 100%; }
}


/* ============================================================================
   OVERLAY — app-popover (04)
   A small anchored panel (row menus, filter pickers). The anchor is the
   positioning context; open/close is Alpine state (@click.outside + Escape).
   <div class="app-popover-anchor" x-data="{ open:false }" @keydown.escape="open=false">
     <button class="app-btn-icon" aria-haspopup="menu" :aria-expanded="open" @click="open=!open" aria-label="Row actions">⋯</button>
     <div class="app-popover app-popover-end" role="menu" x-show="open" @click.outside="open=false">
       <button class="app-popover-item" role="menuitem">Edit</button>
       <div class="app-popover-divider"></div>
       <button class="app-popover-item app-popover-item-danger" role="menuitem">Disable</button>
     </div>
   </div>
   ============================================================================ */
.app-popover-anchor { position: relative; display: inline-flex; }
.app-popover {
  position: absolute; top: 100%; left: 0; z-index: 45; margin-top: .375rem;
  min-width: 11rem; max-width: min(20rem, calc(100vw - 2rem));
  padding: .375rem; background: #FFFFFF;
  border: 1px solid #DFE3E8; border-radius: .625rem;
  box-shadow: 0 10px 25px -5px rgba(16, 24, 40, .18), 0 8px 10px -6px rgba(16, 24, 40, .10);
}
.app-popover-end { left: auto; right: 0; }
.app-popover-top { top: auto; bottom: 100%; margin-top: 0; margin-bottom: .375rem; }
/* Long menus (e.g. a template-placeholder list) scroll inside the popover instead of off-screen. */
.app-popover-scroll { max-height: 18rem; overflow-y: auto; }
.app-popover-body { padding: .5rem .625rem; font-size: .8125rem; color: #334155; }
.app-popover-item {
  display: flex; align-items: center; gap: .5rem; width: 100%;
  padding: .5rem .625rem; border: 0; border-radius: .375rem; background: none;
  font: inherit; font-size: .8125rem; color: #0F172A; text-align: left; cursor: pointer;
}
.app-popover-item:hover, .app-popover-item:focus-visible { background: #F1F5F9; outline: none; }
.app-popover-item:disabled { color: #94A3B8; cursor: not-allowed; background: none; }
.app-popover-item svg { width: 1rem; height: 1rem; flex: none; }
a.app-popover-item { text-decoration: none; }
.app-popover-item-danger { color: #D1242F; }
.app-popover-item-success { color: #047857; }
.app-popover-item-success:hover, .app-popover-item-success:focus-visible { background: #ECFDF5; }
.app-popover-item-danger:hover, .app-popover-item-danger:focus-visible { background: #FFF1F2; }
.app-popover-divider { height: 1px; margin: .25rem 0; background: #F1F5F9; }


/* ============================================================================
   OVERLAY — app-tooltip (04)
   CSS-only: shows on hover AND keyboard focus. Short supplementary text only —
   never the sole carrier of essential information. Wire aria-describedby.
   <span class="app-tooltip">
     <button class="app-btn-icon" aria-label="GST" aria-describedby="t1">i</button>
     <span id="t1" role="tooltip" class="app-tooltip-text">Tax is 18% (CGST 9% + SGST 9%)</span>
   </span>
   ============================================================================ */
.app-tooltip { position: relative; display: inline-flex; }
.app-tooltip-text {
  position: absolute; bottom: calc(100% + .5rem); left: 50%; z-index: 55;
  transform: translate(-50%, .25rem);
  width: max-content; max-width: 16rem; padding: .375rem .625rem;
  border-radius: .375rem; background: #0F172A; color: #FFFFFF;
  font-size: .75rem; font-weight: 500; line-height: 1.4; text-align: center; white-space: normal;
  pointer-events: none; opacity: 0; visibility: hidden;
  transition: opacity .12s, transform .12s, visibility .12s;
}
.app-tooltip-text::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: #0F172A;
}
.app-tooltip:hover .app-tooltip-text,
.app-tooltip:focus-within .app-tooltip-text {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
.app-tooltip-bottom .app-tooltip-text { bottom: auto; top: calc(100% + .5rem); transform: translate(-50%, -.25rem); }
.app-tooltip-bottom .app-tooltip-text::after { top: auto; bottom: 100%; border-top-color: transparent; border-bottom-color: #0F172A; }
@media (prefers-reduced-motion: reduce) { .app-tooltip-text { transition: none; } }


/* ============================================================================
   OPERATIONAL — app-cart (06 §30)
   The persistent POS cart panel. Included credit is shown separately from the
   chargeable part on every line (SRS §25) — never folded into one number.
   <aside class="app-cart">
     <header class="app-cart-header"><h2 class="app-cart-title">Cart</h2><span class="app-badge-warning">Draft</span></header>
     <ul class="app-cart-lines">
       <li class="app-cart-line">
         <div class="app-cart-line-main">
           <span class="app-cart-line-desc">Printing</span>
           <span class="app-cart-line-split"><span class="is-included">Plan credit 30</span><span class="is-chargeable">Chargeable 20 × ₹2.00</span></span>
         </div>
         <span class="app-cart-line-total">₹40.00</span>
         <button class="app-btn-icon app-btn-icon-sm app-btn-icon-ghost app-btn-icon-danger" aria-label="Remove Printing">×</button>
       </li>
     </ul>
     <dl class="app-cart-totals"><dt>Subtotal</dt><dd>₹2,080.00</dd><dt>GST</dt><dd>₹374.40</dd></dl>
     <div class="app-cart-grand"><span>Grand total</span><span>₹2,454.40</span></div>
     <button class="app-btn-primary app-cart-checkout">Checkout — ₹2,454.40</button>
   </aside>
   ============================================================================ */
.app-cart {
  display: flex; flex-direction: column; gap: .875rem;
  padding: 1.125rem; background: #FFFFFF;
  border: 1px solid #E2E8F0; border-radius: .75rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .04);
}
/* Desktop POS: the cart stays in view while the left panel scrolls. */
.app-cart-sticky { position: sticky; top: 1rem; }
.app-cart-header { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.app-cart-title { margin: 0; font-size: .9375rem; font-weight: 700; color: #0F172A; }
.app-cart-lines { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.app-cart-line {
  display: grid; grid-template-columns: 1fr auto auto; align-items: start; gap: .25rem .75rem;
  padding: .625rem 0; border-bottom: 1px solid #F1F5F9;
}
.app-cart-line:last-child { border-bottom: 0; }
.app-cart-line-main { display: flex; flex-direction: column; gap: .125rem; min-width: 0; }
.app-cart-line-desc { font-size: .8125rem; font-weight: 600; color: #0F172A; word-break: break-word; }
.app-cart-line-qty { font-size: .75rem; color: #64748B; }
.app-cart-line-split { display: flex; flex-wrap: wrap; gap: .25rem .5rem; font-size: .6875rem; }
.app-cart-line-split .is-included {
  padding: .0625rem .375rem; border-radius: .25rem; background: #ECFDF5; color: #047857; font-weight: 600;
}
.app-cart-line-split .is-chargeable {
  padding: .0625rem .375rem; border-radius: .25rem; background: #FFFBEB; color: #B54D00; font-weight: 600;
}
.app-cart-line-total { font-size: .8125rem; font-weight: 600; color: #0F172A; font-variant-numeric: tabular-nums; white-space: nowrap; }
.app-cart-empty { margin: 0; padding: 1.5rem .5rem; text-align: center; font-size: .8125rem; color: #64748B; }
.app-cart-totals {
  display: grid; grid-template-columns: 1fr auto; gap: .375rem 1rem; margin: 0;
  padding-top: .75rem; border-top: 1px solid #E2E8F0; font-size: .8125rem;
}
.app-cart-totals dt { color: #64748B; }
.app-cart-totals dd { margin: 0; color: #0F172A; text-align: right; font-variant-numeric: tabular-nums; }
.app-cart-grand {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  font-size: 1.0625rem; font-weight: 800; color: #0F172A; font-variant-numeric: tabular-nums;
}
.app-cart-checkout { width: 100%; height: 2.75rem; font-size: .8125rem; }
/* A cart that already sits inside an app-card: no second border/shadow/padding. */
.app-cart-flush { padding: 0; border: 0; box-shadow: none; background: transparent; }
/* Checkout next to a secondary button (e.g. "Cancel cart") instead of full-width. */
.app-cart-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
.app-cart-actions .app-cart-checkout { width: auto; flex: 1 1 14rem; }
/* Tablet/mobile: collapsed summary bar pinned to the bottom (docs 06 §30). */
.app-cart-mobilebar { display: none; }
@media (max-width: 1024px) {
  .app-cart-sticky { position: static; }
  .app-cart-mobilebar {
    position: sticky; bottom: 0; z-index: 30;
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: .75rem 1rem; background: #FFFFFF; border-top: 1px solid #E2E8F0;
    box-shadow: 0 -6px 16px -8px rgba(15, 23, 42, .2);
    font-weight: 700; font-variant-numeric: tabular-nums;
  }
}


/* ============================================================================
   OPERATIONAL — app-calendar (06 §27)
   Three layouts sharing one view switcher and one event block:
   · Month — 7-column grid of days with a booking count / short list.
   · Time grid (Day/Week) — hour rows; an event spans rows via Alpine
       :style="{ gridRow: startRow + ' / span ' + rowSpan }"   (object syntax!)
   · Resource — one lane per resource, events placed along a day axis via
       :style="{ left: leftPct + '%', width: widthPct + '%' }"
   Clicking an event opens the booking drawer (app-drawer), never navigates.
   ============================================================================ */
.app-calendar { display: flex; flex-direction: column; gap: .75rem; }
.app-calendar-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .75rem; }
.app-calendar-range { margin: 0; font-size: 1rem; font-weight: 700; color: #0F172A; }

/* Segmented view switcher: <div class="app-calendar-views" role="group">
   <button aria-pressed="true">Day</button>… */
.app-calendar-views {
  display: inline-flex; padding: .1875rem; gap: .125rem;
  background: #F1F5F9; border: 1px solid #E2E8F0; border-radius: .5rem;
}
.app-calendar-views button {
  height: 1.875rem; padding: 0 .75rem; border: 0; border-radius: .375rem; background: none;
  font: inherit; font-size: .75rem; font-weight: 600; color: #475569; cursor: pointer;
}
.app-calendar-views button:hover { color: #0F172A; }
.app-calendar-views button[aria-pressed="true"] { background: #FFFFFF; color: #9E4323; box-shadow: 0 1px 2px rgba(15, 23, 42, .12); }
.app-calendar-views button:focus-visible { outline: 2px solid #9E4323; outline-offset: 1px; }

/* Month */
.app-calendar-month {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  border: 1px solid #E2E8F0; border-radius: .75rem; overflow: hidden; background: #E2E8F0; gap: 1px;
}
.app-calendar-weekday {
  padding: .5rem; background: #F8FAFC; text-align: center;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #64748B;
}
.app-calendar-day {
  display: flex; flex-direction: column; gap: .25rem; min-height: 6rem; padding: .375rem .5rem;
  background: #FFFFFF; font-size: .75rem; color: #0F172A;
}
.app-calendar-day-num { font-weight: 700; font-variant-numeric: tabular-nums; }
.app-calendar-day.is-outside { background: #F8FAFC; color: #94A3B8; }
.app-calendar-day.is-today .app-calendar-day-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; border-radius: 9999px; background: #9E4323; color: #FFFFFF;
}
.app-calendar-day-count {
  align-self: flex-start; padding: .0625rem .375rem; border-radius: .25rem;
  background: #FDF6F3; color: #9E4323; font-size: .6875rem; font-weight: 700;
}
.app-calendar-more { font-size: .6875rem; color: #64748B; }

/* Day / Week time grid: first column hour labels, then one column per day. */
.app-calendar-timegrid {
  display: grid; grid-auto-rows: 3rem; position: relative;
  border: 1px solid #E2E8F0; border-radius: .75rem; overflow: auto; background: #FFFFFF;
}
.app-calendar-timegrid-day { grid-template-columns: 4rem 1fr; }
.app-calendar-timegrid-week { grid-template-columns: 4rem repeat(7, minmax(7rem, 1fr)); }
.app-calendar-hour {
  grid-column: 1; padding: .25rem .5rem 0 0; text-align: right;
  font-size: .6875rem; color: #94A3B8; border-right: 1px solid #F1F5F9; font-variant-numeric: tabular-nums;
}
.app-calendar-slot { border-bottom: 1px solid #F1F5F9; border-right: 1px solid #F8FAFC; }

/* Resource (Gantt) view */
.app-calendar-resource { display: flex; flex-direction: column; border: 1px solid #E2E8F0; border-radius: .75rem; overflow: hidden; }
.app-calendar-lane { display: grid; grid-template-columns: 11rem 1fr; min-height: 2.75rem; border-bottom: 1px solid #F1F5F9; }
.app-calendar-lane:last-child { border-bottom: 0; }
.app-calendar-lane-label {
  display: flex; flex-direction: column; justify-content: center; padding: .375rem .75rem;
  background: #F8FAFC; border-right: 1px solid #E2E8F0; font-size: .75rem; font-weight: 600; color: #0F172A;
}
.app-calendar-lane-label small { font-weight: 400; color: #64748B; }
.app-calendar-lane-track { position: relative; }
.app-calendar-lane-track > .app-calendar-event { position: absolute; top: .25rem; bottom: .25rem; }

/* The event block — one look in every view, coloured by booking status.
   Always a <button> so it is focusable and opens the drawer on Enter. */
.app-calendar-event {
  display: flex; flex-direction: column; justify-content: flex-start; gap: .0625rem;
  min-width: 0; margin: 1px 2px; padding: .25rem .375rem; overflow: hidden;
  border: 0; border-left: 3px solid #0C66E4; border-radius: .375rem;
  background: #EFF6FF; color: #1E3A8A; text-align: left; font: inherit; font-size: .6875rem; line-height: 1.3;
  cursor: pointer;
}
.app-calendar-event:hover { filter: brightness(.97); }
.app-calendar-event:focus-visible { outline: 2px solid #9E4323; outline-offset: 1px; }
.app-calendar-event-title { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.app-calendar-event-meta { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: .85; }
.app-calendar-event.is-confirmed { border-left-color: #0C66E4; background: #EFF6FF; color: #1E3A8A; }
.app-calendar-event.is-checkedin { border-left-color: #047857; background: #ECFDF5; color: #064E3B; }
.app-calendar-event.is-pending { border-left-color: #B54D00; background: #FFFBEB; color: #78350F; }
.app-calendar-event.is-completed { border-left-color: #64748B; background: #F1F5F9; color: #334155; }
.app-calendar-event.is-cancelled,
.app-calendar-event.is-noshow,
.app-calendar-event.is-expired { border-left-color: #BE123C; background: #FFF1F2; color: #881337; text-decoration: line-through; }
.app-calendar-event.is-plan { border-left-color: #9E4323; background: #FDF6F3; color: #6E2B13; }
@media (max-width: 640px) {
  .app-calendar-day { min-height: 3.5rem; padding: .25rem; }
  .app-calendar-weekday { padding: .375rem 0; font-size: 10px; letter-spacing: 0; }
  .app-calendar-lane { grid-template-columns: 7rem 1fr; }
  /* Month on a phone is a count-per-day summary (docs 06 §27): each event shrinks to a
     status-coloured bar — still a button, still opens the drawer on tap, its accessible
     name comes from the title text, which stays in the DOM. */
  .app-calendar-day .app-calendar-event { height: .375rem; margin: 1px 0; padding: 0; border-left-width: 0; font-size: 0; }
  .app-calendar-day .app-calendar-event.is-confirmed { background: #0C66E4; }
  .app-calendar-day .app-calendar-event.is-checkedin { background: #047857; }
  .app-calendar-day .app-calendar-event.is-pending { background: #B54D00; }
  .app-calendar-day .app-calendar-event.is-completed { background: #64748B; }
  .app-calendar-day .app-calendar-event.is-cancelled,
  .app-calendar-day .app-calendar-event.is-noshow,
  .app-calendar-day .app-calendar-event.is-expired { background: #BE123C; }
  .app-calendar-day .app-calendar-event.is-plan { background: #9E4323; }
  .app-calendar-day-count { padding: 0 .25rem; font-size: 10px; }
  .app-calendar-more { font-size: 10px; }
}


/* ============================================================================
   OPERATIONAL — app-credit-balance (07)
   One benefit/credit balance. The number is the hero; the unit and source
   are secondary. State modifiers are paired with text, never colour alone.
   <div class="app-credit-balance is-low">
     <span class="app-credit-balance-name">Printing</span>
     <span class="app-credit-balance-value">12<span class="app-credit-balance-unit">pages</span></span>
     <span class="app-credit-balance-meta">Low balance · from Monthly Desk plan</span>
   </div>
   ============================================================================ */
/* align-content: start — in a taller container the cards keep their own height instead of stretching. */
.app-credit-balance-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); align-content: start; gap: .75rem; }
.app-credit-balance {
  display: flex; flex-direction: column; gap: .125rem;
  padding: .875rem 1rem; background: #FFFFFF;
  border: 1px solid #E2E8F0; border-left: 3px solid #047857; border-radius: .625rem;
}
.app-credit-balance-name { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #475569; }
.app-credit-balance-value {
  display: flex; align-items: baseline; gap: .25rem;
  font-size: 1.5rem; font-weight: 800; line-height: 1.2; color: #0F172A; font-variant-numeric: tabular-nums;
}
.app-credit-balance-unit { font-size: .75rem; font-weight: 500; color: #64748B; }
.app-credit-balance-meta { font-size: .75rem; color: #64748B; }
.app-credit-balance.is-low { border-left-color: #B54D00; }
.app-credit-balance.is-low .app-credit-balance-value { color: #B54D00; }
.app-credit-balance.is-empty { border-left-color: #BE123C; background: #FFFBFB; }
.app-credit-balance.is-empty .app-credit-balance-value { color: #BE123C; }
.app-credit-balance.is-unlimited { border-left-color: #9E4323; }
.app-credit-balance.is-unlimited .app-credit-balance-value { color: #9E4323; }


/* ============================================================================
   OPERATIONAL — app-usage-meter (07)
   "Used X of Y" bar. Two CSP-safe ways to render the bar:
   1) Server-rendered: a native <meter> (value/min/max carry the size):
      <meter class="app-usage-meter-bar" min="0" max="100" low="75" high="90" optimum="0" value="42">42 of 100</meter>
      The browser colours it green/amber/red from low/high/optimum.
   2) Alpine: a track + fill bound with OBJECT :style:
      <span class="app-usage-meter-track"><span class="app-usage-meter-fill" :class="pct >= 90 && 'is-danger'" :style="{ width: pct + '%' }"></span></span>
   Wrap either one:
   <div class="app-usage-meter">
     <div class="app-usage-meter-head"><span class="app-usage-meter-label">Meeting room hours</span><span class="app-usage-meter-value">3 of 4 used</span></div>
     …bar…
     <p class="app-usage-meter-note">1 hour left this month</p>
   </div>
   ============================================================================ */
.app-usage-meter { display: flex; flex-direction: column; gap: .375rem; }
.app-usage-meter-head { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; font-size: .8125rem; }
.app-usage-meter-label { font-weight: 600; color: #0F172A; }
.app-usage-meter-value { color: #475569; font-variant-numeric: tabular-nums; white-space: nowrap; }
.app-usage-meter-note { margin: 0; font-size: .75rem; color: #64748B; }

/* 1) Native <meter> */
meter.app-usage-meter-bar {
  -webkit-appearance: none; appearance: none; display: block;
  width: 100%; height: .5rem; border: 0; border-radius: 9999px; background: #E2E8F0; overflow: hidden;
}
meter.app-usage-meter-bar::-webkit-meter-bar { height: .5rem; border: 0; border-radius: 9999px; background: #E2E8F0; }
meter.app-usage-meter-bar::-webkit-meter-optimum-value { border-radius: 9999px; background: #047857; }
meter.app-usage-meter-bar::-webkit-meter-suboptimum-value { border-radius: 9999px; background: #B54D00; }
meter.app-usage-meter-bar::-webkit-meter-even-less-good-value { border-radius: 9999px; background: #D1242F; }
meter.app-usage-meter-bar::-moz-meter-bar { border-radius: 9999px; background: #047857; }
meter.app-usage-meter-bar:-moz-meter-sub-optimum::-moz-meter-bar { background: #B54D00; }
meter.app-usage-meter-bar:-moz-meter-sub-sub-optimum::-moz-meter-bar { background: #D1242F; }

/* 2) Track + fill */
.app-usage-meter-track { display: block; width: 100%; height: .5rem; border-radius: 9999px; background: #E2E8F0; overflow: hidden; }
.app-usage-meter-fill {
  display: block; height: 100%; width: 0; max-width: 100%;
  border-radius: 9999px; background: #047857; transition: width .3s ease-out;
}
.app-usage-meter-fill.is-brand { background: #9E4323; }
.app-usage-meter-fill.is-warning { background: #B54D00; }
.app-usage-meter-fill.is-danger { background: #D1242F; }
.app-usage-meter-fill.is-info { background: #0C66E4; }
/* Secondary brand tones used by the customer dashboard's meter row. */
.app-usage-meter-fill.is-sand { background: #CA9057; }
.app-usage-meter-fill.is-ink { background: #282C2A; }
.app-usage-meter-fill.is-blush { background: #CFA995; }
.app-usage-meter-compact .app-usage-meter-head { font-size: .75rem; }
.app-usage-meter-compact .app-usage-meter-track,
.app-usage-meter-compact meter.app-usage-meter-bar { height: .375rem; }
@media (prefers-reduced-motion: reduce) { .app-usage-meter-fill { transition: none; } }


/* ============================================================================
   OPERATIONAL — app-timeline (07)
   Vertical history: booking lifecycle, benefit ledger, visitor pass events.
   Newest first unless the context is a lifecycle read top-to-bottom.
   <ol class="app-timeline">
     <li class="app-timeline-item is-success">
       <time class="app-timeline-time" datetime="2026-09-29T10:02">29 Sep, 10:02</time>
       <p class="app-timeline-title">Checked in</p>
       <p class="app-timeline-body">by Front Desk · Priya</p>
     </li>
   </ol>
   ============================================================================ */
.app-timeline { position: relative; margin: 0; padding: 0; list-style: none; }
.app-timeline-item { position: relative; padding: 0 0 1.125rem 1.5rem; }
.app-timeline-item:last-child { padding-bottom: 0; }
/* the connecting rail */
.app-timeline-item::before {
  content: ""; position: absolute; left: .3125rem; top: .875rem; bottom: -.125rem;
  width: 2px; background: #CBD5E1;
}
.app-timeline-item:last-child::before { display: none; }
/* the node */
.app-timeline-item::after {
  content: ""; position: absolute; left: 0; top: .25rem;
  width: .75rem; height: .75rem; border-radius: 9999px;
  background: #FFFFFF; border: 2px solid #94A3B8;
}
.app-timeline-item.is-success::after { border-color: #047857; background: #ECFDF5; }
.app-timeline-item.is-warning::after { border-color: #B54D00; background: #FFFBEB; }
.app-timeline-item.is-danger::after { border-color: #D1242F; background: #FFF1F2; }
.app-timeline-item.is-info::after { border-color: #0C66E4; background: #EFF6FF; }
.app-timeline-item.is-brand::after { border-color: #9E4323; background: #FDF6F3; }
.app-timeline-time { display: block; font-size: .6875rem; color: #94A3B8; font-variant-numeric: tabular-nums; }
.app-timeline-title { margin: .0625rem 0 0; font-size: .8125rem; font-weight: 600; color: #0F172A; }
.app-timeline-body { margin: .125rem 0 0; font-size: .75rem; color: #64748B; }
.app-timeline-amount { font-variant-numeric: tabular-nums; font-weight: 700; }
.app-timeline-amount.is-credit { color: #047857; }
.app-timeline-amount.is-debit { color: #BE123C; }


/* ============================================================================
   FORM — app-datepicker (DEC-045 / calendar date selection, 2026-10-05)
   The design system's own calendar: a field button showing the chosen date in
   full ("Wed, 15 Oct 2026") that opens a month grid. Logic: wwwroot/js/date-picker.js;
   markup: Pages/Shared/_DatePickerField.cshtml. Out-of-range days are shown but
   not pickable. On a phone the grid spans the field's width, up to the screen.
   <div class="app-datepicker" x-data="appDatePicker({ min: () => todayIso() })"
        x-modelable="value" x-model="form.date"> <partial name="_DatePickerField" model="@("id")" /> </div>
   ============================================================================ */
.app-datepicker { position: relative; display: block; min-width: 0; }
.app-datepicker-field {
  display: flex; align-items: center; gap: .5rem; width: 100%;
  text-align: left; cursor: pointer;
}
.app-datepicker-field.is-open { border-color: #9E4323; box-shadow: 0 0 0 2px rgba(158, 67, 35, .15); }
.app-datepicker-glyph { display: inline-flex; color: #9E4323; flex: none; }
.app-datepicker-glyph svg, .app-datepicker-caret svg { width: 1rem; height: 1rem; }
.app-datepicker-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: #0F172A; }
.app-datepicker-value.is-placeholder { font-weight: 400; color: #94A3B8; }
.app-datepicker-caret { display: inline-flex; color: #64748B; flex: none; }

.app-datepicker-pop {
  position: absolute; top: 100%; left: 0; z-index: 60; margin-top: .375rem;
  width: 18rem; max-width: calc(100vw - 2rem);
  padding: .625rem; background: #FFFFFF;
  border: 1px solid #DFE3E8; border-radius: .75rem;
  box-shadow: 0 10px 25px -5px rgba(16, 24, 40, .18), 0 8px 10px -6px rgba(16, 24, 40, .10);
}
.app-datepicker-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .375rem; }
.app-datepicker-month { font-size: .8125rem; font-weight: 700; color: #0F172A; }
.app-datepicker-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .125rem; }
.app-datepicker-dow {
  padding: .25rem 0; text-align: center;
  font-size: .625rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #64748B;
}
.app-datepicker-day {
  height: 2.125rem; border: 0; border-radius: .5rem; background: transparent;
  font-size: .75rem; font-weight: 600; color: #0F172A; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.app-datepicker-day:hover { background: #FDF6F3; color: #9E4323; }
.app-datepicker-day:focus-visible { outline: 2px solid #9E4323; outline-offset: 1px; }
.app-datepicker-day.is-outside { color: #94A3B8; font-weight: 500; }
.app-datepicker-day.is-today { box-shadow: inset 0 0 0 1px #F3D1C3; color: #9E4323; }
.app-datepicker-day.is-selected, .app-datepicker-day.is-selected:hover { background: #9E4323; color: #FFFFFF; box-shadow: none; }
.app-datepicker-day.is-disabled, .app-datepicker-day.is-disabled:hover {
  background: transparent; color: #CBD5E1; cursor: not-allowed; text-decoration: line-through;
}
.app-datepicker-foot { display: flex; justify-content: space-between; margin-top: .5rem; padding-top: .5rem; border-top: 1px solid #F1F5F9; }
.app-datepicker-link {
  border: 0; background: none; padding: .25rem .375rem; border-radius: .375rem;
  font-size: .75rem; font-weight: 700; color: #9E4323; cursor: pointer;
}
.app-datepicker-link:hover { background: #FDF6F3; }
.app-datepicker-link:disabled { color: #CBD5E1; cursor: not-allowed; background: none; }
@media (max-width: 480px) {
  .app-datepicker-pop { width: 100%; min-width: 16rem; }
  .app-datepicker-day { height: 2.5rem; font-size: .8125rem; }
}

/* Duration read-out beside a start/end time pair ("4 hours"). */
.app-duration-chip {
  display: inline-flex; align-items: center; gap: .25rem;
  padding: .125rem .5rem; border-radius: 9999px;
  background: #FDF6F3; color: #9E4323; font-size: .6875rem; font-weight: 700;
}
.app-duration-chip svg { width: .75rem; height: .75rem; }
