/* ==========================================================================
   BASE — reset, document defaults, layout rails, shared primitives.
   WP Phase 2: enqueue immediately after design-tokens.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. RESET
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* The masthead is fixed, so an anchor jump would park the target section
   underneath it and hide its own title. Every section reserves that height. */
main > section,
[id] { scroll-margin-block-start: calc(var(--header-h) + var(--sp-4)); }

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ol, ul {
  margin: 0;
  padding: 0;
}

ul[class], ol[class] { list-style: none; }

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

a { color: inherit; text-decoration: none; }

::selection {
  background: var(--c-selection-bg);
  color: var(--c-selection-fg);
}

/* --------------------------------------------------------------------------
   2. DOCUMENT
   -------------------------------------------------------------------------- */

body {
  background: var(--c-bg);
  color: var(--c-ink);
  font-family: var(--ff-body);
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--tr-normal);
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

:focus-visible {
  outline: var(--bw-rule) solid var(--c-accent);
  outline-offset: 3px;
}

.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.u-skip-link {
  position: absolute;
  top: var(--sp-3);
  left: var(--sp-3);
  z-index: 999;
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-ink);
  color: var(--c-bg);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-sm);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  transform: translateY(-200%);
}
.u-skip-link:focus { transform: translateY(0); }

/* --------------------------------------------------------------------------
   3. LAYOUT RAIL — .l-shell
   A 12-column editorial grid with named bleed lines. Children opt in by
   naming grid lines; nothing is centred by default.

   IMPORTANT: the rail opens with a margin track, so RAW NUMERIC line indices
   are offset by one. Always address content columns through the `col` name:

     grid-column: content-start / content-end;  -> the full 12-column well
     grid-column: content-start / span 7;       -> columns 1 through 7
     grid-column: col 4 / full-end;             -> column 4, bleeding off-screen
     grid-column: col 9 / content-end;          -> columns 9 through 12
   -------------------------------------------------------------------------- */

.l-shell {
  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--margin), 1fr)
    [content-start] repeat(var(--grid-columns), [col] minmax(0, calc(var(--content-max) / 12)))
    [content-end] minmax(var(--margin), 1fr)
    [full-end];
  column-gap: var(--gutter);
}

/* Default: unclassed direct children sit in the content well. */
.l-shell > * { grid-column: content-start / content-end; }

.l-bleed  { grid-column: full-start / full-end; }
.l-bleed-right { grid-column: content-start / full-end; }
.l-bleed-left  { grid-column: full-start / content-end; }

/* --------------------------------------------------------------------------
   4. TYPE PRIMITIVES
   -------------------------------------------------------------------------- */

.t-display {
  font-family: var(--ff-display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-weight: var(--fw-light);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
  text-wrap: balance;
}

.t-serif {
  font-family: var(--ff-display);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-tight);
}

.t-mono {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-sm);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  line-height: 1;
}

.t-mono--wide { letter-spacing: var(--tr-mono-wide); }
.t-mono--xs   { font-size: var(--fs-mono-xs); }

.t-lede {
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  color: var(--c-ink-soft);
  text-wrap: pretty;
}

.t-accent { color: var(--c-accent-text); }

/* Editorial italic inside display headings — the one flourish we allow. */
.t-display em {
  font-style: italic;
  font-variation-settings: "SOFT" 40, "WONK" 1;
  letter-spacing: -0.045em;
}

/* --------------------------------------------------------------------------
   5. RULES — hairline dividers used as structural punctuation
   -------------------------------------------------------------------------- */

.c-rule {
  border: 0;
  border-top: var(--bw-hair) solid var(--c-line);
  block-size: 0;
  inline-size: 100%;
}

.c-rule--strong { border-top-color: var(--c-line-strong); }


/* --------------------------------------------------------------------------
   6. FULL-BLEED MEDIA BEDS
   Any section can sit on photography or video. The bed is always three
   layers: media, grade, scrim. Content sits above all three.
   -------------------------------------------------------------------------- */

.c-bed {
  position: relative;
  isolation: isolate;
  overflow: clip;
}

.c-bed__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  filter: var(--grade-media);
}

/* Slow drift keeps a still photograph from reading as a dead backdrop. */
.c-bed--drift .c-bed__media {
  animation: bed-drift 34s var(--ease-inout) infinite alternate;
  transform-origin: center;
}

@keyframes bed-drift {
  from { transform: scale(1.04) translate3d(0, 0, 0); }
  to   { transform: scale(1.12) translate3d(-1.4%, -1.2%, 0); }
}

/*
  THE PLATE.
  Every bed rests on a designed surface, never on nothing. It is pure CSS —
  limestone catching light in the top right, deep water falling away to the
  bottom left — so a section is a finished composition before any film has
  loaded, and stays one if the visitor blocks third-party media entirely.

  This exists because the channel's thumbnails carry baked-in title graphics.
  They are correct on a video card and unusable as a background, so beds are
  fed by live video frames or by this plate. Never by a thumbnail.
*/
.c-bed__plate {
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    radial-gradient(130% 95% at 80% 8%,
      color-mix(in oklab, var(--slate-700) 62%, var(--stone-300)) 0%,
      transparent 56%),
    linear-gradient(168deg,
      var(--slate-800) 0%,
      var(--slate-900) 42%,
      var(--slate-950) 100%);
}

.c-bed__stage {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.2s var(--ease-out);
}

.c-bed[data-bed-ready] .c-bed__stage { opacity: 1; }

/*
  The frame is sized and offset by placeFrame() in site-ui.js, where the box
  dimensions are known. This rule only applies what it is given.

  --bed-x slides the player sideways far enough that its centre — and the
  round button drawn there — falls outside the visible box. That is done only
  where it costs nothing, which is on tall narrow boxes; on a wide one it
  would double the frame and halve the picture. See the note in site-ui.js.

  There is no zoom here any more. The frame is the smallest 16:9 rectangle
  that covers the box, which is the least-cropped framing available. The
  player's title bar and its "more videos" strip only appear in states the
  reel never shows, so there is nothing left to crop them out of view for.

  The caption track is switched off at the embed and again through the API:
  cc_load_policy is documented as "based on user preference", not "off".
*/
.c-bed__stage iframe {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  transform: translate(
    calc(-50% + var(--bed-x, 0px)),
    calc(-50% + var(--bed-y, 0px))
  );
  transform-origin: center;
  border: 0;
  filter: var(--grade-media);
}

/* Bed stacking order, fixed in one place:
     0  plate   — the designed surface
     1  stage   — live film
     2  scrim   — legibility layer, ABOVE the media
     3  content — never dimmed by its own scrim
*/
.c-bed__scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

/* Weighted to the bottom-left, where editorial type always lands, with a
   shallow band along the top so the masthead stays legible against a bright
   sky. Three stops, not a flat wash — the footage still reads as footage. */
.c-bed__scrim--corner {
  background:
    linear-gradient(to bottom, var(--scrim-flood) 0%, transparent 20%),
    linear-gradient(to top right, var(--scrim-deep) 0%, var(--scrim-mid) 40%, transparent 76%),
    linear-gradient(to top, var(--scrim-flood) 0%, transparent 46%);
}

.c-bed__scrim--flood {
  background: linear-gradient(to right, var(--scrim-deep) 0%, var(--scrim-mid) 52%, var(--scrim-veil) 100%);
}

.c-bed__scrim--even { background: var(--scrim-flood); }

/*
  THE WASH.
  A still from the channel, blurred far past the point where its baked-in
  title graphics can be read, then dimmed. What survives is the colour and
  the light of a real Maltese afternoon — texture, not a photograph. This is
  the only way the channel's stills are allowed near a background.
*/
.c-bed__wash {
  position: absolute;
  inset: -8%;
  z-index: 0;
  background-image: var(--wash);
  background-size: cover;
  background-position: center;
  filter: blur(64px) saturate(0.75) brightness(0.5);
  opacity: 0.42;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .c-bed__wash { animation: bed-drift 46s var(--ease-inout) infinite alternate; }
}

/* Panels put copy on one edge and a ledger on the other, so both edges need
   cover and the middle is where the film is allowed to show through. */
.c-bed__scrim--panel {
  background:
    linear-gradient(to bottom, var(--scrim-flood) 0%, transparent 16%),
    linear-gradient(100deg,
      var(--scrim-deep) 0%,
      var(--scrim-mid) 46%,
      var(--scrim-flood) 100%);
}

.c-bed > .l-shell,
.c-bed > .c-bed__content { position: relative; z-index: 3; }

/* --------------------------------------------------------------------------
   7. SCROLL REVEAL

   The hidden state is a class the SCRIPT ADDS and then REMOVES, rather than a
   default that an override has to beat. That ordering matters: an earlier
   version hid by default and revealed with a more specific selector, and a
   section could be left permanently invisible if the reveal landed while the
   subtree was not being rendered. Arming can only happen if the script is
   running, and un-arming is a class removal, so there is no state to get
   stuck in and no specificity race to lose.

   site-ui.js also un-arms everything unconditionally after a few seconds, so
   even a broken observer cannot hide content.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .is-armed {
    opacity: 0;
    transform: translateY(1.25rem);
  }

  [data-reveal] {
    transition:
      opacity var(--dur-slow) var(--ease-out),
      transform var(--dur-slow) var(--ease-out);
    transition-delay: calc(var(--reveal-delay, 0) * 90ms);
  }
}

/* --------------------------------------------------------------------------
   8. SECTION HEAD
   A centred stack: the small label sits ABOVE the heading, both centred on
   the rail. The old version put the label in column 1 and the heading in
   column 2, which read as a caption hanging off the side of a title rather
   than as one masthead.
   -------------------------------------------------------------------------- */

.c-head {
  row-gap: var(--sp-4);
  padding-block-end: var(--section-gap);
  justify-items: center;
  text-align: center;
}

.c-head > * { grid-column: content-start / content-end; }

.c-head__index {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono-wide);
  text-transform: uppercase;
  color: var(--c-accent-text);
}

.c-head__title {
  font-family: var(--ff-display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-weight: var(--fw-light);
  font-size: var(--fs-3xl);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
  text-wrap: balance;
}

.c-head__title em {
  font-style: italic;
  font-variation-settings: "SOFT" 60, "WONK" 1;
  color: var(--c-accent-text);
}

.c-head__standfirst {
  max-inline-size: 70ch;
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--c-ink-muted);
}

/* --------------------------------------------------------------------------
   9. ACTIONS — link-first. No oversized pill buttons anywhere on this site.
   -------------------------------------------------------------------------- */

.c-action {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding-block-end: var(--sp-2);
  border-block-end: var(--bw-rule) solid var(--c-accent);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-sm);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink);
  transition: color var(--dur-fast) var(--ease-out);
}

.c-action svg { inline-size: 1.5rem; block-size: auto; transition: transform var(--dur-base) var(--ease-out); }
.c-action:hover { color: var(--c-accent-text); }
.c-action:hover svg { transform: translateX(0.4rem); }

.c-action--solid {
  padding: var(--sp-4) var(--sp-6);
  border: 0;
  background: var(--c-accent);
  color: var(--c-accent-on);
  transition: background-color var(--dur-fast) var(--ease-out);
}
.c-action--solid:hover { background: var(--c-accent-hover); color: var(--c-accent-on); }

.c-action--ghost {
  padding: var(--sp-4) var(--sp-6);
  border: var(--bw-hair) solid var(--c-line-strong);
  color: var(--c-ink);
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.c-action--ghost:hover { border-color: var(--c-ink); background: color-mix(in oklab, var(--c-ink) 6%, transparent); }



/* Headings never break unevenly. */
h1, h2, h3, .c-head__title, .c-about__title, .c-panel__title,
.c-shop__title, .c-booking__title, .c-entry__title {
  text-wrap: balance;
}


/* ==========================================================================
   THE WRAP LAW
   The single source of truth for how text is allowed to break. Three tiers,
   and everything on the site belongs to exactly one of them.

   TIER 1 — NEVER WRAPS.
   Labels, chips, buttons, stamps, badges, eyebrows, datestamps, metadata,
   navigation. These are short by construction. If one of them is long enough
   to wrap, THE COPY IS WRONG and must be shortened — the layout is not at
   fault and must not be widened to accommodate it.

   TIER 2 — WRAPS EVENLY, NEVER RAGGEDLY.
   Headings and short card copy. These have to break on narrow screens, but
   they break into balanced lines with no word stranded alone on the last one.

   TIER 3 — PROSE.
   Body paragraphs. A paragraph must wrap; that is what a paragraph is. It is
   held to a sane measure and prevented from leaving an orphan.
   ========================================================================== */

/* --- TIER 1 : never wraps ------------------------------------------------- */

.t-mono,
.c-action,
.c-site-header__link,
.c-site-header__wordmark,
.c-site-header__badge,
.c-site-header__cta,
.c-hero__control,
.c-hero__eyebrow,
.c-hero__coords,
.c-hero__now-tag,
.c-hero__now-cue,
.c-hero__figure dt,
.c-head__index,
.c-archive__chip,
.c-archive__readout span,
.c-channel__cue,
.c-entry__stamp,
.c-entry__topic,
.c-entry__duration,
.c-entry__play,
.c-entry__foot,
.c-about__eyebrow,
.c-about__caption,
.c-about__figure dt,
.c-socials__text small,
.c-socials__text b,
.c-events__badge,
.c-events__list span,
.c-panel__eyebrow,
.c-panel__figure dt,
.c-shop__eyebrow,
.c-shop__price small,
.c-shop__rating,
.c-shop__contents li,
.c-cover__mark,
.c-services__tag,
.c-services__row-name,
.c-consult__meta div,
.c-mailcard__text small,
.c-mailcard__text b,
.c-mailcard__cue,
.c-tours__stops li,
.c-field label,
.c-site-footer__legal > span,
.c-site-footer__by span,
.c-site-footer__channel small {
  white-space: nowrap;
}

/* --- TIER 2 : wraps evenly ------------------------------------------------ */

h1, h2, h3, h4,
.c-head__title,
.c-hero__title,
.c-about__title,
.c-panel__title,
.c-shop__title,
.c-consult__title,
.c-contact__title,
.c-events__title,
.c-entry__title,
.c-tours__name,
.c-head__standfirst,
.c-tours__body p,
.c-entry__dek,
.c-services__panel h3,
.c-channel__text b {
  text-wrap: balance;
}

/* --- TIER 3 : prose ------------------------------------------------------- */

p,
li,
.c-hero__lede,
.c-about__copy,
.c-shop__copy,
.c-consult__copy,
.c-contact__copy,
.c-events__copy,
.c-services__panel p,
.c-post__body p {
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   NO-WRAP, tier 1 — text we do not write.
   Video titles and deks arrive from YouTube at arbitrary length, so they are
   clamped rather than edited: one line, ellipsis, never a second line at any
   viewport. Everything we author is kept short enough not to need this.
   -------------------------------------------------------------------------- */

.c-hero__now .c-hero__now-title,
.c-entry__title,
.c-entry__title span,
.c-entry__dek {
  display: block;
  inline-size: 100%;
  max-inline-size: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-wrap: nowrap;
}


/* --------------------------------------------------------------------------
   TOUCH: tap targets

   A text link with an arrow is 25px tall, which is fine for a cursor and not
   for a thumb. On a touch screen every action gets a 44px target — the
   padding grows around the text rather than the text growing, so nothing
   about the typography changes.
   -------------------------------------------------------------------------- */

@media (hover: none) {
  .c-action {
    min-block-size: 2.75rem;
    display: inline-flex;
    align-items: center;
  }

  .c-action--solid { padding-block: var(--sp-4); }
  .c-site-footer__by { min-block-size: 2.75rem; align-items: center; }
}

/* --------------------------------------------------------------------------
   PHONE: third-party titles wrap rather than truncate

   The override for this does NOT live here. timeline.css and hero.css each
   set their own `white-space: nowrap` on these elements and load after this
   file, so anything written here loses the cascade — which is exactly what
   happened on the first attempt: the line-clamp applied and the white-space
   did not, leaving a one-line ellipsis with a two-line clamp on it.

   See the PHONE blocks at the foot of timeline.css and hero.css.
   -------------------------------------------------------------------------- */
