/*
 * services.css — the page that sells, plus the interior of the booking dialog.
 *
 * Load order: after site-system.css, before desktop-tokens.css. So every rule
 * here beats style.css, interactive.css and the page's own inline block without
 * !important, and desktop-shell.css still wins the selectors it writes — in
 * particular `.desktop-web .service-card-new .buy-button { border-radius: 8px }`,
 * which is the system's control radius and is designed with, not fought.
 *
 * This file owns two things and nothing else:
 *   1. The five service cards and the two bands they sit in.
 *   2. The interior of the booking dialog interactive.js renders from this
 *      page. Its shell (glass tier 3, the backdrop, .site-modal-close) is the
 *      system's and is untouched. The payment-methods dialog that used to
 *      share this section is gone: the page never linked to it from anywhere
 *      but its own now-removed trigger, and the copy it carried duplicated
 *      what checkout already tells you.
 *
 * Materials, as everywhere: the card is extruded out of the page, the fields
 * inside the dialog are pressed into it, and every button is flat.
 */

/* ===========================================================================
 * 1. PAGE FRAME
 * ======================================================================== */

/* The tap-highlight suppression, the shell height and the page entrance are the
   system's now (site-system.css §3). This page's own keyframe name and its own
   copy of the shell rules are gone. */

/*
 * style.css still centres .page-hero-inner, and desktop-shell.css only sets
 * text-align on .page-hero itself. An inherited value loses to a declared one,
 * so the hero stayed centred on every page that has one. Corrected here for
 * this page; the shared fix is in the report.
 */
.desktop-web .page-hero-inner { text-align: left; }
/* The hero sat 40px left of every section below it: .page-hero already carries
   the gutter as padding, and .page-hero-inner is then capped at the full
   container width, while .ds-container is capped at that width and adds the
   gutter inside itself. Subtracting the gutter twice puts the h1 on the same
   line as the h2s. */
.desktop-web .page-hero .page-hero-inner {
  max-width: calc(var(--ds-container) - var(--ds-gutter) * 2);
}
/* The hero is not a .ds-section, so its own bottom padding plus a full section
   rhythm stranded it about 120px above the first band. */
.desktop-web #app .page-hero { padding-bottom: 0; }
/* Adjacency, not :first-of-type: .page-hero is itself the first <section>
   inside #app, so :first-of-type never matched the band. */
.desktop-web .page-hero + .service-band { padding-top: var(--ds-7); }

/* ===========================================================================
 * 2. THE CARD
 *
 * The surface is the system's one card object (site-system.css). What is left
 * here is the layout inside it: a head that states what the thing is, what it
 * costs and how to take it, then the list as supporting detail.
 * ======================================================================== */
/*
 * The original card declaration, moved here verbatim from the <style id=
 * "page-style"> block in services.html so that page can be served style-src
 * 'self'. test/source.test.mjs pins it against this file now.
 *
 * It is kept at its original one-class specificity on purpose: the rule below
 * and site-system.css's card object both qualify with .desktop-web, so both
 * still win over it exactly as they did when it was inline, and the surface
 * the visitor sees is still the system's one card (16px, the --ds-e2
 * extrusion, no border).
 */
.service-card-new { box-sizing: border-box; background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 0; box-shadow: none; }

.desktop-web .service-card-new {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.desktop-web .service-card-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: var(--ds-5);
}

/* A flex column, so the action can be pushed to the bottom of the head with an
   auto margin. That is what lets a reserved head height align the Book Now
   buttons of a row rather than merely padding the box under them. */
.desktop-web .card-head {
  display: flex;
  flex-direction: column;
  gap: var(--ds-4);
  margin: 0 0 var(--ds-5);
  padding: 0 0 var(--ds-5);
  border-bottom: 1px solid var(--ds-hairline);
}
/* The auto margin the comment above describes, which was never written. Without
   it the reserved head height (`--overclock` below, and the two-line title row)
   only padded the box under the button; the buttons of a row still sat at
   whatever height their own text left them. The last element of the head is the
   action, so it goes on the head's bottom edge and the row lines up. */
.desktop-web .card-head > .buy-button { margin-top: auto; }

/* A reserved title row, so a one-line and a two-line service name still put
   the price of every card in a row on the same line. */
.desktop-web .service-card-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ds-3);
  min-height: 44px;
}
.desktop-web .service-card-new .card-title {
  margin: 0;
  font-size: var(--ds-text-h3);
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--text);
}
.desktop-web .value-badge { flex: none; letter-spacing: 0; }

/* The three overclock cards share a row, but only one of them carries the
   component picker. Reserving its height on all three is what keeps the three
   Book Now buttons on one line; without it the card with the select pushes its
   own button below its neighbours. */
.desktop-web .service-grid--overclock .card-head { min-height: 270px; }

/* --- Price --------------------------------------------------------------- */
.desktop-web .price-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-4);
  margin: 0;
}
.desktop-web .price-tag {
  display: flex;
  align-items: baseline;
  gap: 1px;
  margin: 0;
  font-size: clamp(28px, 2.6vw, 34px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* The currency mark, not another number. */
.desktop-web .price-tag > span:first-child {
  font-size: 0.56em;
  font-weight: 500;
  color: var(--text-muted);
}
/*
 * When a referral is active, interactive.js replaces the tag's children with
 * <s> old price, <strong> new price, <sup> badge. Both states are styled here,
 * so a discounted card is the same object rather than a differently shaped one.
 * The badge stays monochrome: a promotion is not the fifth thing the accent is
 * spent on.
 */
.desktop-web .price-tag s {
  font-size: 0.5em;
  font-weight: 500;
  color: var(--text-faint);
  text-decoration-thickness: 1px;
}
.desktop-web .price-tag strong { font-weight: 600; }
.desktop-web .price-tag sup {
  align-self: center;
  margin-left: var(--ds-2);
  padding: 0 8px;
  border: 1px solid var(--ds-hairline-strong);
  border-radius: var(--ds-r-xs);
  background: rgba(255, 255, 255, 0.035);
  color: var(--text-muted);
  font-size: var(--ds-text-micro);
  font-weight: 500;
  letter-spacing: 0.04em;
  line-height: 22px;
  vertical-align: baseline;
}
/* The static USD suffix is a unit, not a badge: no box. */
.desktop-web .price-tag .price-unit {
  align-self: baseline;
  margin-left: 6px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--text-faint);
  font-size: var(--ds-text-tag);
  font-weight: 500;
  letter-spacing: 0;
  line-height: inherit;
  vertical-align: baseline;
}

/* --- The component picker ------------------------------------------------ */
.desktop-web .oc-pick {
  display: grid;
  gap: var(--ds-2);
  margin: 0;
  text-align: left;
}
.desktop-web .oc-pick-label {
  color: var(--text-muted);
  font-size: var(--ds-text-small);
  font-weight: 500;
  letter-spacing: 0;
}
.desktop-web .oc-pick select { min-height: 44px; cursor: pointer; }

/* --- The action ---------------------------------------------------------- */
.desktop-web .service-card-new .buy-button {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  margin: auto 0 0;
}

/* --- The list ------------------------------------------------------------ */
.desktop-web .feature-list {
  display: grid;
  flex: 1;
  align-content: start;
  gap: var(--ds-3);
  margin: 0;
  padding: 0;
  list-style: none;
}
.desktop-web .service-feature {
  display: flex;
  align-items: flex-start;
  gap: var(--ds-2);
  margin: 0;
  color: var(--text-muted);
  font-size: var(--ds-text-small);
  line-height: 1.55;
}
/* The tick says "included" where a bullet would only separate. It is
   decoration: the sentence beside it carries the meaning, so it is hidden from
   assistive technology and stays monochrome, because the accent is spent
   elsewhere. */
.desktop-web .service-feature .ui-icon {
  flex: none;
  color: var(--text-faint);
  /*
   * The row is `align-items: flex-start`, so the tick's box height is what puts
   * it on the first line of the sentence. An <svg> has no line box of its own,
   * so one is stated: the box is exactly the row's `line-height: 1.55`, and the
   * 24x24 viewBox fits to the shorter side and centres itself in it, which
   * lands the ink on the first line's optical centre. Without it every row is
   * 2px shorter and the list creeps upward against the card above it.
   *
   * `1.55em` and no `font-size`, where this said `1.4em` at `--ds-text-body`:
   * the two numbers only agreed because 1.4 x 14px happened to come out near
   * 1.55 x 13px. An icon is 1em of the text beside it (DESIGN §13), so the
   * font-size is gone and the height now tracks the line-height it is named
   * after. Measured: +0.17px off the cap centre before, +0.38px after, and the
   * tick is the size of its own sentence rather than a step above it.
   */
  height: 1.55em;
  /* These ticks were font glyphs on a bare <i>, which the site-wide `.ui-icon`
     fade never reached. They carry that class now, so state the full strength
     here rather than letting twenty ticks per card quietly drop to 85%. */
  opacity: 1;
}

/* --- Featured ------------------------------------------------------------
 * The same card at the same elevation, ringed in the accent and tagged in it.
 * A different fill or a taller box would make it a second card object; this
 * marks one of five without inventing one.
 */
.desktop-web .service-card-new.is-featured {
  box-shadow: var(--ds-e2), inset 0 0 0 1px var(--ds-accent-line);
}

/* One primary per view (DESIGN §6).
 *
 * `.buy-button` is mapped to the primary face, and this page renders five of
 * them; with the header's own accent control that put six solid accent slabs
 * on one screen, which is the exact case §6 names: if everything is the
 * primary action, nothing is. The page already says which service it
 * recommends, with the featured card's accent ring and its "Most value" tag,
 * so that one keeps the primary face and the other four take the secondary
 * one. Nothing new is invented here: these are the same three tokens the
 * system's own secondary rule uses, restated at a specificity that can reach
 * past the primary list. The geometry, radius and focus behaviour are still
 * the system's.
 */
.desktop-web .service-card-new:not(.is-featured) .buy-button {
  border-color: var(--ds-hairline-strong);
  background: var(--ds-control-fill);
  color: var(--text);
  font-weight: 600;
}
.desktop-web .service-card-new:not(.is-featured) .buy-button:hover:not(:disabled) {
  border-color: var(--text-faint);
  background: var(--ds-control-fill-hover);
  color: var(--text);
}
.desktop-web .service-card-new:not(.is-featured) .buy-button:active:not(:disabled) {
  background-color: var(--ds-control-fill-hover);
}
/* The accent ring, not the white-on-accent one: there is no accent fill under
   it any more. */
.desktop-web .service-card-new:not(.is-featured) .buy-button:focus-visible {
  outline-color: var(--ds-focus);
}

/* ===========================================================================
 * 3. THE BOOKING DIALOG — INTERIOR ONLY
 *
 * interactive.js renders the markup and the system paints the shell. What is
 * corrected here is the interior, which still carried the pre-system treatment
 * from interactive.css: shouty uppercase micro-labels, bordered fields, and an
 * acknowledgement drawn as a solid amber outline.
 * ======================================================================== */
.desktop-web .site-booking-modal {
  /* Named, because the close button below has to sit on the same two edges and
     the dialog changes both of them at 600px. One value, read twice. */
  --booking-pad-y: var(--ds-6);
  --booking-pad-x: var(--ds-5);
  width: min(520px, 100%);
  padding: var(--booking-pad-y) var(--booking-pad-x) var(--ds-5);
}

/*
 * The close is part of the title's row, not a mark in the corner.
 *
 * It was inset 14px from the top and the right of the dialog, which put it
 * 6.3px above the title's optical centre and 10px outside the right edge every
 * field in the form lines up on -- the only element in the dialog standing on
 * neither. Now: the right edge is the dialog's own side padding, so it ends
 * where the inputs end; the top centres the 44px target on the title's line
 * box (`--ds-text-h3` at the 1.2 the h2 above sets), so the two read as one
 * row. Measured: -6.28px off the title's cap centre before, -0.08px after.
 */
.desktop-web .site-booking-modal .site-modal-close {
  top: calc(var(--booking-pad-y) + (var(--ds-text-h3) * 1.2 - 44px) / 2);
  right: var(--booking-pad-x);
}
.desktop-web .site-booking-modal form {
  display: grid;
  gap: var(--ds-4);
}

/* The dialog opens straight on the service name now that "New ticket" is
   gone; the eyebrow used to sit above it and a negative top margin pulled the
   title up to close the gap that left. With no eyebrow, the title is the
   form grid's first child and takes the grid's own gap like every field
   below it. */
.desktop-web .site-booking-modal h2 {
  margin: 0 56px 0 0;
  font-size: var(--ds-text-h3);
  font-weight: 600;
  letter-spacing: -0.024em;
  line-height: 1.2;
}

/* Empty until a submission fails; an empty grid item would otherwise open a
   16px hole between the title and the first field. */
.desktop-web .site-booking-modal [data-error]:empty { display: none; }
.desktop-web .site-booking-modal .site-error-notice {
  border-color: rgba(229, 104, 109, 0.42);
  border-radius: var(--ds-r-md);
}

/* Label above, field below. Sentence case at reading size: a form is read, and
   eight lines of tracked-out capitals is the thing that reads as generated. */
.desktop-web .site-booking-modal label {
  display: grid;
  gap: var(--ds-2);
  color: var(--text-muted);
  font-size: var(--ds-text-small);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}
.desktop-web .site-booking-modal label > span {
  display: flex;
  align-items: center;
  gap: var(--ds-2);
}
/* 1em of the label beside it (DESIGN §13). It was pinned a step up, which put
   a 14px glyph beside a 13px field label in the one dialog where five of them
   stack. */
.desktop-web .site-booking-modal label .ui-icon {
  flex: none;
  color: var(--text-faint);
}
.desktop-web .site-booking-modal :is(input, select) { min-height: 44px; }
.desktop-web .site-booking-modal select { cursor: pointer; }

/* The overclock acknowledgement is a notice you have to agree with, so it is
   drawn as the system's warn notice rather than as a boxed field. */
.desktop-web .site-booking-modal .site-ack {
  align-items: start;
  gap: var(--ds-3);
  padding: var(--ds-3) var(--ds-4);
  border: 1px solid rgba(221, 164, 79, 0.42);
  border-radius: var(--ds-r-md);
  background: var(--warn-soft);
  color: var(--warn);
  font-size: var(--ds-text-small);
  font-weight: 400;
  line-height: 1.55;
}
.desktop-web .site-booking-modal .site-ack input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 1px 0 0;
  accent-color: var(--ds-accent);
  cursor: pointer;
}
.desktop-web .site-booking-modal .site-ack span { cursor: pointer; }

.desktop-web .site-booking-modal [type="submit"] {
  width: 100%;
  min-height: 44px;
  margin-top: var(--ds-2);
}

/* The ticket-created confirmation replaces the form in the same shell. */
.desktop-web .site-booking-modal .site-success-mark {
  width: 44px;
  height: 44px;
  margin: 0 0 var(--ds-4);
  border-radius: 50%;
  font-size: var(--ds-text-h3);
}

/* ===========================================================================
 * 4. NARROW VIEWPORTS
 * ======================================================================== */
/* One column: nothing sits beside a card, so the reserved row would only be
   dead space. 591px is the last width at which .ds-grid--3 no longer fits two columns. */
@media (max-width: 591px) {
  .desktop-web .service-grid--overclock .card-head { min-height: 0; }
  /* Nothing sits beside a card here either, so the reserved title row is the
     same dead space. */
  .desktop-web .service-card-heading { min-height: 0; }
}

@media (max-width: 760px) {
  .desktop-web .service-card-body { padding: 22px; }
}

@media (max-width: 600px) {
  .desktop-web .site-booking-modal {
    --booking-pad-y: var(--ds-5);
    --booking-pad-x: var(--ds-4);
    padding: var(--booking-pad-y) var(--booking-pad-x) max(var(--ds-5), env(safe-area-inset-bottom));
  }
  /* 16px, or iOS zooms the page the moment a field takes focus. */
  .desktop-web .site-booking-modal :is(input, select) { font-size: 16px; }
}

@media (max-width: 420px) {
  .desktop-web .service-card-body { padding: 18px; }
}
