/* Campaigns: the promotion page, its card, and the card the homepage shows once.

   Page-scoped. It ships on the homepage, on the blog and on a campaign's own
   page, and nowhere else - nothing on the booking journey has a campaign on it.

   NOTHING NEW IS INVENTED HERE. The card is the ArticleCard's shape because it
   sits in the same column under the same heading; the facts block is the cream
   band the car page already uses for its rates; the modal is a white panel with
   the system's one shadow on it. The only figure in this file that is not a
   token is the modal's 440px ceiling, and that is a measure, not a colour. */

/* === CampaignCard ===
   Square corners and a resting shadow, exactly as ArticleCard. Repeated rather
   than shared with a compound selector: the two are the same shape today and
   have no reason to move together tomorrow, and one of them is in a stylesheet
   the other's pages do not load. */

.kssk-campaign-card {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-none);
  background: var(--surface-page);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: transform var(--duration-base) var(--ease-out);
}

.kssk-campaign-card:hover { transform: var(--hover-lift); }

/* An ended campaign keeps its place in the list and loses its insistence. The
   picture is muted rather than removed: the page is still worth reading, it is
   just no longer an offer. */
.kssk-campaign-card.is-ended .kssk-campaign-card__image { filter: grayscale(1); opacity: 0.65; }

.kssk-campaign-card__media {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 16 / 9;
  background: var(--surface-cream);
  overflow: hidden;
}

.kssk-campaign-card__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The stand-in when there is no artwork yet, which is the normal state the
   evening before a launch. The offer itself, set large, rather than a stock
   photograph pretending to be the campaign. */
.kssk-campaign-card__plate {
  margin: 0;
  padding: var(--space-24);
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-3xl);
  line-height: var(--leading-33);
  color: var(--kssk-navy);
}

.kssk-campaign-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding: var(--space-21);
}

.kssk-campaign-card__offer {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-4) var(--space-12);
  border-radius: var(--radius-sm);
  background: var(--surface-cream);
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-note);
  line-height: var(--leading-18);
  color: var(--kssk-navy);
}

/* Ended borrows the placeholder badge's red, which is the system's one "this is
   not what you are looking for" colour. */
.kssk-campaign-card__badge {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-4) var(--space-12);
  border-radius: var(--radius-sm);
  background: var(--red-100);
  font-family: var(--font-body);
  font-size: var(--text-note);
  line-height: var(--leading-18);
  color: var(--red-700);
}

.kssk-campaign-card__title {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  line-height: var(--leading-26);
  color: var(--text-primary);
}

.kssk-campaign-card__title a { color: inherit; text-decoration: none; }

.kssk-campaign-card__title a:hover,
.kssk-campaign-card__title a:focus-visible {
  color: var(--kssk-orange);
  text-decoration: underline;
}

.kssk-campaign-card__text {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  color: var(--text-secondary);
}

.kssk-campaign-card__dates {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-note);
  line-height: var(--leading-18);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.kssk-campaign-card__more {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  text-transform: uppercase;
  color: var(--text-link);
  text-decoration: none;
}

.kssk-campaign-card:hover .kssk-campaign-card__more { text-decoration: underline; }

/* === CampaignFeature ===
   A campaign at full width: artwork one side, the offer the other. The hero of
   a campaign's own page AND the lead slot on the Promotions landing page, which
   is why it is one block and not two.

   CREAM, AND NOT TEXT ON A PHOTOGRAPH. The system has no scrim because nothing
   in it is ever set over photography, and a campaign image is whatever was
   uploaded - not a surface anything can be promised to read on. So the picture
   keeps its own half and the words sit on the brand's warm band beside it. With
   no picture yet the block is the offer on cream, which is a design rather than
   a hole. */

.kssk-campaign-feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
  border-radius: var(--radius-sm);
  background: var(--surface-cream);
  overflow: hidden;
}

/* One column, and the words get the room the picture was using. */
.kssk-campaign-feature--plain { grid-template-columns: minmax(0, 1fr); }

.kssk-campaign-feature__media {
  position: relative;
  min-height: 280px;
  background: var(--surface-cream-raw);
}

/* <picture> is inline by default, which breaks the height chain the image
   below depends on: an inline wrapper has no height of its own, so height:100%
   on the img resolves against nothing and the artwork collapses. Only present
   when a campaign has a portrait upload, so the fault would appear on one
   campaign and not the rest. */
.kssk-campaign-feature__media picture {
  display: block;
  width: 100%;
  height: 100%;
}

.kssk-campaign-feature__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* THE TALL HERO: THE WHOLE ARTWORK, FILLING THE CARD, INSIDE THE SCREEN.
   Square or portrait - whatever shape the second upload is, this adapts to it.
   Three requirements, and only one arrangement satisfies all three.

   It must fit on the screen: an upload left to its own devices comes out
   around 800px tall at half the content column and pushes the button below
   the fold. It must not be cropped: a promotional graphic carries its own
   type, so anything trimmed off is words. And it must fill its side of the
   card corner to corner, because artwork sitting short of the edges with
   bands of cream above and below reads as a mistake rather than a margin.

   Capping the box crops (object-fit:cover discards what no longer fits).
   Scaling the picture inside a box the words have made taller leaves exactly
   those bands. The way out is to let the ARTWORK decide both dimensions:

     column width  = the ceiling times the image's width-over-height, never
                     more than half the block
     media height  = that width back through the same ratio, via aspect-ratio

   The second line is what makes any shape work. Whichever of the two limits
   binds - the screen's height for something tall, the half-block for
   something square - the box that results still has the image's own
   proportions, and in a box of its own proportions cover and contain do the
   same thing: nothing to discard, nothing left over.

   A worked example, on a 1080px-high window. A 9:16 upload: the ceiling binds,
   the column is 484px and the media 860px, exactly the ceiling. A square: the
   half-block binds at 600px, and the media is 600px too, well inside the
   ceiling. Both fill their side of the card completely.

   --kssk-hero-ratio is written on by PHP, because only the server knows the
   proportions of a file the browser has not fetched yet. The 0.75 fallback is
   a sane portrait for the moment before it arrives. min-height:0 undoes the
   280px floor the media carries for the landscape case, which would otherwise
   overrule the aspect ratio on a short window and reintroduce a crop.

   Only above 1024px. Below that the two stack, the landscape upload is used
   at 16/9, and none of this applies. */
@media (min-width: 1024px) {
  .kssk-campaign-feature--portrait {
    --kssk-hero-height: calc(100vh - 220px);
    --kssk-hero-height: calc(100svh - 220px);

    grid-template-columns:
      min(50%, calc(var(--kssk-hero-height) * var(--kssk-hero-ratio, 0.75)))
      minmax(0, 1fr);
  }

  .kssk-campaign-feature--portrait .kssk-campaign-feature__media {
    aspect-ratio: var(--kssk-hero-ratio, 0.75);
    min-height: 0;
  }

  .kssk-campaign-feature--portrait .kssk-campaign-feature__media picture,
  .kssk-campaign-feature--portrait .kssk-campaign-feature__image {
    width: 100%;
    height: 100%;
    max-height: none;
    object-fit: cover;
  }
}

/* Ended keeps its place and loses its insistence, exactly as the card does. */
.kssk-campaign-feature.is-ended .kssk-campaign-feature__image { filter: grayscale(1); opacity: 0.65; }

.kssk-campaign-feature__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-16);
  padding: var(--space-40);
  min-width: 0;
}

/* The flag is one slot carrying one of three states - the offer, not started
   yet, finished - so they cannot appear together and contradict each other. */
.kssk-campaign-feature__flag {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-4) var(--space-12);
  border-radius: var(--radius-sm);
  background: var(--surface-page);
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  color: var(--kssk-navy);
}

.kssk-campaign-feature__flag--offer { background: var(--surface-brand); color: var(--text-inverse); }
.kssk-campaign-feature__flag--ended { background: var(--red-100); color: var(--red-700); }

.kssk-campaign-feature__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-8xl);
  line-height: var(--leading-54);
  color: var(--text-primary);
  text-wrap: balance;
}

.kssk-campaign-feature__title a { color: inherit; text-decoration: none; }

.kssk-campaign-feature__title a:hover,
.kssk-campaign-feature__title a:focus-visible {
  color: var(--kssk-orange);
  text-decoration: underline;
}

.kssk-campaign-feature__lead {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xl);
  line-height: var(--leading-30);
  color: var(--text-body);
  /* A measure, not the half-column it happens to sit in. */
  max-width: 46ch;
}

.kssk-campaign-feature__meta {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

.kssk-campaign-feature__cta { display: flex; margin-top: var(--space-4); }

/* === The Promotions landing page === */

.kssk-campaign-index__more {
  display: flex;
  flex-direction: column;
  gap: var(--space-24);
  margin-top: var(--space-40);
}

/* No campaign today is a real state, and a sentence about it beats a blank
   band. Centred and narrow: it is one thought and a way out of it. */
.kssk-campaign-index__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-24);
  padding: var(--space-40) var(--space-24);
  border-radius: var(--radius-sm);
  background: var(--surface-subtle);
  text-align: center;
}

.kssk-campaign-index__empty-text {
  margin: 0;
  max-width: 52ch;
  font-family: var(--font-body);
  font-size: var(--text-lg);
  line-height: var(--leading-30);
  color: var(--text-secondary);
}

/* The four accounts, under the sentence that points at them. Navy on the pale
   band rather than the footer's white on navy - same glyphs, read from the
   same record, but this surface is light. They inherit currentColor because
   the set is inlined SVG, so the hover is a colour change and not a second
   asset. */
.kssk-campaign-index__social {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-16);
}

.kssk-campaign-index__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  color: var(--kssk-navy);
  transition: color var(--duration-fast) var(--ease-standard),
              background-color var(--duration-fast) var(--ease-standard);
}

.kssk-campaign-index__social-link:hover,
.kssk-campaign-index__social-link:focus-visible {
  color: var(--kssk-orange);
  background: var(--surface-panel);
}

/* === The campaign page === */

/* Narrower than the 1200 column. What is in here is read top to bottom in
   sentences and lists, and a 1200px line of body copy is unreadable. The hero
   and the grid of other campaigns are both outside it, in their own bands at
   full width, because neither is reading. */
/* The page's own column, at the site's full width. The hero lives here and the
   reading measure below is nested inside it, because the hero is not reading:
   it is one heading, one sentence and a button beside a picture, and giving it
   a measure set for paragraphs halved it - 300px for the words on a 1440 or a
   1920 screen, which broke a 48px heading four ways and left the offer badge
   wider than the column it sits in. */
.kssk-campaign__stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-32);
}

.kssk-campaign__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-32);
  max-width: 760px;
}

/* The facts, as a definition list on the cream the car page uses for its rate
   band. Rows rather than columns: a label above its value survives a long Malay
   term wrapping, and two of these values are whole sentences. */
.kssk-campaign__facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-24);
  margin: 0;
  padding: var(--space-24);
  border-radius: var(--radius-sm);
  background: var(--surface-cream);
}

.kssk-campaign__fact { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

.kssk-campaign__fact-term {
  font-family: var(--font-body);
  font-size: var(--text-note);
  line-height: var(--leading-18);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
}

.kssk-campaign__fact-value {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-base);
  line-height: var(--leading-24);
  color: var(--text-primary);
}

.kssk-campaign__section { display: flex; flex-direction: column; gap: var(--space-16); }

.kssk-campaign__heading {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-5xl);
  line-height: var(--leading-48);
  color: var(--text-primary);
}

.kssk-campaign__steps,
.kssk-campaign__terms {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  margin: 0;
  padding-left: var(--space-24);
}

.kssk-campaign__step,
.kssk-campaign__term {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-24);
  color: var(--text-body);
}

/* The marker is the list's own, in the brand colour. The number on a step is
   information - it is the order you do them in - so it is not decoration and
   it is not hidden. */
.kssk-campaign__steps { list-style: decimal; }
.kssk-campaign__terms { list-style: disc; }
.kssk-campaign__step::marker { color: var(--kssk-orange); font-weight: var(--weight-bold); }
.kssk-campaign__term::marker { color: var(--kssk-orange); }

.kssk-campaign__standing {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  color: var(--text-secondary);
}

.kssk-campaign__standing a { color: var(--kssk-orange); }

.kssk-campaign__cta { display: flex; }

/* === The homepage card ===
   A native <dialog>. Everything below styles the box the browser already opens,
   closes and traps focus in. */

.kssk-campaign-modal {
  width: min(440px, calc(100vw - (2 * var(--space-24))));
  max-width: none;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--surface-page);
  box-shadow: var(--shadow-card);
  color: var(--text-primary);
}

/* Navy at 60%, not black: the backdrop is the one full-screen surface on the
   site and it belongs to the palette like everything else. */
.kssk-campaign-modal::backdrop { background: rgb(38 41 50 / 0.6); }

.kssk-campaign-modal__panel { position: relative; display: flex; flex-direction: column; }

/* 44px, the touch floor, and sitting on the artwork rather than beside it -
   there is no room for a control row above a picture that starts at the top of
   the card. White with a dark scrim behind it so it reads on any photograph. */
.kssk-campaign-modal__close {
  position: absolute;
  top: var(--space-8);
  right: var(--space-8);
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: rgb(38 41 50 / 0.55);
  color: var(--text-inverse);
  font-family: var(--font-body);
  font-size: var(--text-2xl);
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}

.kssk-campaign-modal__close:hover { background: rgb(38 41 50 / 0.8); }
.kssk-campaign-modal__close:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.kssk-campaign-modal__media {
  aspect-ratio: 16 / 9;
  background: var(--surface-cream);
  overflow: hidden;
}

.kssk-campaign-modal__image { display: block; width: 100%; height: 100%; object-fit: cover; }

.kssk-campaign-modal__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding: var(--space-24);
}

.kssk-campaign-modal__offer {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-4) var(--space-12);
  border-radius: var(--radius-sm);
  background: var(--surface-cream);
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-note);
  line-height: var(--leading-18);
  color: var(--kssk-navy);
}

.kssk-campaign-modal__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--text-5xl);
  line-height: var(--leading-48);
  color: var(--text-primary);
  text-wrap: balance;
}

.kssk-campaign-modal__text {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  color: var(--text-secondary);
}

.kssk-campaign-modal__meta {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-note);
  line-height: var(--leading-18);
  color: var(--text-muted);
}

.kssk-campaign-modal__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-12) var(--space-16);
  margin-top: var(--space-4);
}

/* A text button, not a second filled one. There is one thing to do on this card
   and it is the orange; declining is the quiet way out and should look like it. */
.kssk-campaign-modal__decline {
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--leading-22);
  color: var(--text-secondary);
  text-decoration: underline;
  cursor: pointer;
}

.kssk-campaign-modal__decline:hover { color: var(--text-primary); }
.kssk-campaign-modal__decline:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }

.kssk-campaign-modal__note {
  margin: 0;
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--text-note);
  line-height: var(--leading-18);
  color: var(--text-muted);
}

/* The split holds until the words run out of room. Below 1024 the body is
   under 300px wide inside the content column, which is four or five words a
   line for a display face at 48px - so the picture goes on top and the words
   get the full width instead. */
@media (max-width: 1023px) {
  .kssk-campaign-feature { grid-template-columns: minmax(0, 1fr); }
  .kssk-campaign-feature__media { min-height: 0; aspect-ratio: 16 / 9; }
  .kssk-campaign-feature__body { padding: var(--space-32); }
}

@media (max-width: 767px) {
  .kssk-campaign-feature__body { padding: var(--space-24); gap: var(--space-12); }
  .kssk-campaign-feature__cta { display: flex; }
  .kssk-campaign-feature__cta .kssk-button { width: 100%; justify-content: center; }
  .kssk-campaign-index__more { margin-top: var(--space-32); }
  .kssk-campaign-index__empty { padding: var(--space-32) var(--space-16); }

  /* One column of facts. Two 33%-wide values on a 390px screen are four words
     each and wrap to three lines. */
  .kssk-campaign__facts { grid-template-columns: 1fr; gap: var(--space-16); }

  .kssk-campaign__inner { gap: var(--space-24); }

  /* The card comes down from the middle of the screen to just under the top of
     it: at this width it is most of the viewport, and centring it leaves an
     uneven margin that reads as a mistake rather than as a frame. */
  .kssk-campaign-modal { margin-top: var(--space-24); }

  .kssk-campaign-modal__actions { flex-direction: column; align-items: stretch; }
  .kssk-campaign-modal__decline { text-align: center; }
}
