/* App-only rules. The design tokens and component CSS are copied unchanged from the kit. */

/* A view is a data boundary, not a box. display:contents keeps it out of flex and grid.
   The child combinator still sees xo-view, so the kit's `.carousel__track > *` snap
   never reaches the card. The card snaps itself. */
xo-view { display: contents; }
.page-sections { display: contents; }
.carousel__track .card { scroll-snap-align: start; }

/* Field errors come from the form engine as <small class="xo-error"> after the control. */
.xo-error {
  display: block;
  margin-top: var(--s-1);
  font-size: var(--fs-xs);
  color: var(--c-error);
  font-weight: var(--fw-semibold);
}
.field:has([aria-invalid="true"]) .field__control,
.field.is-invalid .field__control {
  border-color: var(--c-error);
  background: var(--c-error-soft);
}

/* The engine sets aria-busy on the form for the duration of the request. */
form[aria-busy="true"] [type="submit"] { font-size: 0; pointer-events: none; }
form[aria-busy="true"] [type="submit"]::after {
  content: "Đang gửi…";
  font-size: var(--fs-sm);
}

/* The kit draws .menu-toggle and .nav.is-open. This file does not restyle them. */

/* The lightbox is the dialog itself. Keep scroll chaining inside it. */
dialog:modal,
dialog::backdrop { overscroll-behavior: contain; }

/* Content photos use <xo-image>. The ratios are the kit's tokens, so the box
   is reserved before the element upgrades. A bound icon is an <xo-image> too,
   because a plain <img src="{...}"> does not bind, and it carries the kit's
   width and height (24). Those attributes do not size a custom element. In a
   flex column the host stretches, the control writes aspect-ratio inline, and
   a fill of 100% paints the SVG across the card. Only photo frames fill.
   24px is the fallback where typed attr() is unavailable (stable Safari). */
xo-image { display: block; position: relative; overflow: hidden; max-width: 100%; background: var(--c-surface-soft); }
xo-image > img { display: block; object-fit: var(--xo-image-fit, cover); object-position: var(--xo-image-position, center); transition: opacity var(--d-fast) var(--ease-out); }
/* Fill the frame so object-fit crops from the position, not from the top of an
   overflowing image. Package covers and article covers use the kit default (center). */
xo-image.card__media > img,
xo-image.article__cover > img,
xo-image.profile__photo > img,
.banner xo-image > img,
.lightbox xo-image > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
xo-image.article__cover,
.package-grid--pair xo-image.card__media { --xo-image-position: center center; }
xo-image[width][height]:not(.card__media):not(.article__cover):not(.profile__photo) {
  width: 24px;
  width: attr(width px);
  height: 24px;
  height: attr(height px);
  flex: none;
  align-self: flex-start;
  max-width: none;
  background: none;
  overflow: visible;
}
xo-image[width][height]:not(.card__media):not(.article__cover):not(.profile__photo) > img {
  width: 24px;
  width: attr(width px);
  height: 24px;
  height: attr(height px);
  max-width: none;
  object-fit: contain;
}
/* The kit sizes .btn__icon at 1rem. Ancestor picture rules (.map img, .confirm img)
   are for that block's own image and also match a glyph nested in the block. */
.btn > .btn__icon { width: var(--s-4); height: var(--s-4); max-width: none; flex: none; }
html:not(.no-js) xo-image[data-state="loading"] > img { opacity: 0; }
@media (prefers-reduced-motion: reduce) { xo-image > img { transition: none; } }
xo-image[data-state="empty"] > img,
xo-image[data-state="error"] > img { display: none; }
xo-image .xo-image-note { position: absolute; inset: 0; display: grid; place-items: center; padding: var(--s-3); text-align: center; font-size: var(--fs-sm); color: var(--c-muted); }
.card__media { aspect-ratio: var(--media-ratio); --xo-image-fit: cover; }
.card__media--portrait { aspect-ratio: var(--portrait-ratio); --xo-image-position: center top; }
.media--doctor { --xo-image-position: center top; }
.card__media--contain { --xo-image-fit: contain; box-sizing: border-box; }
@media (min-width: 64rem) {
  .package-grid--pair xo-image.card__media { block-size: 100%; aspect-ratio: auto; }
}
.article__cover { aspect-ratio: var(--cover-ratio); --xo-image-fit: cover; }
.banner xo-image { width: 100%; aspect-ratio: 1206 / 452; border-radius: var(--r-md); --xo-image-fit: contain; }
.lightbox xo-image { width: 100%; aspect-ratio: 1206 / 452; --xo-image-fit: contain; }

.article-block { display: contents; }
xo-image.article__cover, .banner xo-image, .lightbox xo-image { background: none; }

/* Progress bar shown from the moment an internal link is clicked until the next page replaces this one. */
.nav-progress { position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 9999; pointer-events: none; opacity: 0; }
.nav-progress::before { content: ""; position: absolute; inset: 0; background: var(--c-primary); transform-origin: left; transform: scaleX(0); }
html.is-navigating, html.is-navigating a { cursor: progress; }
html.is-navigating .nav-progress { opacity: 1; }
html.is-navigating .nav-progress::before { animation: nav-progress 8s cubic-bezier(0.1, 0.7, 0.2, 1) forwards; }
@keyframes nav-progress { from { transform: scaleX(0.05); } to { transform: scaleX(0.92); } }
@media (prefers-reduced-motion: reduce) {
  html.is-navigating .nav-progress::before { animation: none; transform: scaleX(0.6); }
}

/* Contact map: the kit box is a centred placeholder. The iframe fills that
   4/3 frame so the section does not jump when the map arrives. */
.map:has(.map__frame) {
  position: relative;
  display: block;
  padding: 0;
  overflow: hidden;
}
.map__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.map__open {
  position: absolute;
  z-index: 1;
  left: var(--s-4);
  bottom: var(--s-4);
  background: var(--c-surface);
}
.map__note {
  margin: var(--s-3) 0 0;
  font-size: var(--fs-sm);
  color: var(--c-muted);
}
figcaption:empty { display: none; }
