/* ==========================================================================
   site.css — hand-written styles for the public site.
   ==========================================================================

   No framework, no build step, no runtime compile. This file is served as-is
   from public/css/ and cached like any other asset.

   It sits next to public/css/utilities.css, which is the transitional layer
   compiled from tailwind.public.config.js for the templates that have not been
   migrated to these components yet. Load order is:

       utilities.css   (preflight + utility classes, for old templates)
       site.css        (this file — wins on equal specificity)

   Colours come from partials/theme_tokens.blade.php, which emits the design
   tokens as `--c-<name>: R G B` custom properties for both light and dark.
   Everything here reads those, so the theme toggle keeps working.

   CONTENTS
     1.  Base
     2.  Dark-mode compatibility (moved out of the layout's inline <style>)
     3.  Primitives
     4.  Reading progress
     5.  Article masthead
     6.  Hero figure
     7.  Article layout + table of contents
     8.  Article body typography
     9.  Article footer actions
     10. Post index (listing)
     11. Related articles
     12. News listing
     13. News article
     14. Tour promotion (callout band, in-text mention, tour rail)
     15. RTL
     16. Reduced motion

   Nothing here introduces a new colour: every value reads a token from
   partials/theme_tokens.blade.php, so the theme toggle keeps working and the
   brand identity is unchanged.
   ========================================================================== */

/* ------------------------------------------------------------------ 1. Base */

*,
*::before,
*::after {
    box-sizing: border-box;
}

:root {
    /* Semantic aliases so the rules below read as intent, not as tokens. */
    --ls-body: rgb(var(--c-on-surface));
    --ls-heading: rgb(var(--c-on-surface));
    --ls-muted: rgb(var(--c-on-surface-variant));
    --ls-accent: rgb(var(--c-primary));
    --ls-accent-container: rgb(var(--c-primary-container));
    --ls-on-accent: rgb(var(--c-on-primary));
    --ls-rule: rgb(var(--c-outline-variant));
    --ls-card: rgb(var(--c-surface-container-low));
    --ls-page: rgb(var(--c-surface));
    --ls-radius-card: 1.75rem;
    --ls-radius-media: 1.25rem;
    --ls-wrap: 1280px;
    --ls-measure: 44rem; /* the reading column: ~72 characters at 18px */
    --ls-font-display: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
    --ls-font-body: Inter, ui-sans-serif, system-ui, sans-serif;
}

:root.dark {
    /* Filled brand surfaces use the container shade in dark mode, matching the
       .dark .bg-primary override the layout has always applied. Text accents
       keep --c-primary, which is the light peach in this theme. */
    --ls-accent-container: rgb(var(--c-primary-container));
    --ls-on-accent: rgb(var(--c-on-primary-container));
}

/* Arabic needs a face that actually has the glyphs. Inter and Plus Jakarta Sans
   are Latin/Cyrillic only, so without this the browser falls back to whichever
   system Arabic font it happens to find — inconsistent between platforms, and
   the usual reason a translated page looks like an afterthought. Noto Sans
   Arabic is already loaded by the layout for the chrome. Declared after :root
   on purpose: same specificity, so this has to come second to win. */
:lang(ar) {
    --ls-font-display: "Noto Sans Arabic", "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
    --ls-font-body: "Noto Sans Arabic", Inter, ui-sans-serif, system-ui, sans-serif;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: var(--ls-font-body);
    color: var(--ls-body);
    background-color: var(--ls-page);
}

img,
picture,
svg,
video {
    max-width: 100%;
}

img {
    height: auto;
}

[hidden] {
    display: none !important;
}

/* A single visible focus treatment for every interactive element in this file.
   The old markup repeated a long focus-visible utility chain on each link, which
   is why the article page produced such a large class attribute. */
:where(a, button, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--ls-accent);
    outline-offset: 2px;
    border-radius: 0.25rem;
}

/* --------------------------- 2. Dark-mode compatibility overrides ---------- */

/* These used to live in an inline <style id="theme-tokens"> block in
   layouts/public.blade.php so they could re-map utility classes that hard-code
   white. They are static CSS, so they belong here: the layout no longer ships
   a second style block on every page. */

:root.dark .bg-white {
    background-color: rgb(var(--c-surface-container-lowest) / 1);
}

:root.dark .bg-white\/90,
:root.dark .bg-white\/92,
:root.dark .bg-white\/95 {
    background-color: rgb(var(--c-surface-container-lowest) / 0.92);
}

:root.dark .bg-white\/85,
:root.dark .bg-white\/88,
:root.dark .bg-white\/80 {
    background-color: rgb(var(--c-surface-container-lowest) / 0.85);
}

:root.dark .bg-white\/\[0\.92\] {
    background-color: rgb(var(--c-surface-container-lowest) / 0.92);
}

:root.dark .hover\:bg-white:hover {
    background-color: rgb(var(--c-surface-container-high) / 1);
}

:root.dark .border-outline-variant\/20,
:root.dark .border-outline-variant\/30 {
    border-color: rgb(var(--c-outline-variant) / 0.3);
}

:root.dark .bg-primary {
    background-color: rgb(var(--c-primary-container) / 1);
}

:root.dark .bg-primary .text-on-primary,
:root.dark .bg-primary.text-on-primary {
    color: rgb(var(--c-on-primary-container) / 1);
}

:root.dark .text-on-primary {
    color: rgb(var(--c-on-primary-container) / 1);
}

:root.dark .bg-primary .text-primary {
    color: rgb(var(--c-on-primary-container) / 1);
}

:root.dark .bg-primary-container {
    background-color: rgb(var(--c-primary-container) / 1);
}

/* ------------------------------------------------------------ 3. Primitives */

.ls-wrap {
    width: 100%;
    max-width: var(--ls-wrap);
    margin-inline: auto;
    padding-inline: 1rem;
}

@media (min-width: 768px) {
    .ls-wrap {
        padding-inline: 2.5rem;
    }
}

.ls-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;
}

/* ------------------------------------------------------ 4. Reading progress */

.ls-progress {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    height: 3px;
    z-index: 60;
    pointer-events: none;
}

.ls-progress__bar {
    display: block;
    width: 0;
    height: 100%;
    background: linear-gradient(90deg, var(--ls-accent-container), var(--ls-accent));
    transition: width 90ms linear;
}

/* Respect the user's motion preference globally rather than per-rule. */
@media (prefers-reduced-motion: reduce) {
    .ls-progress__bar {
        transition: none;
    }
}

/* ------------------------------------------------------ 5. Article masthead */

.ls-article {
    overflow-x: hidden;
    background-color: var(--ls-page);
}

/* The page wrapper for the article listing, which has no single article in it.
   Same job as .ls-article — keep a long unbroken string from widening the
   viewport — under a name that does not lie about the content. */
.ls-shell {
    overflow-x: hidden;
    background-color: var(--ls-page);
}

/* The masthead clears the fixed mobile header (64px) before it starts. The
   layout gives <main> no top offset — most pages open on a hero that carries
   its own — so a page that opens on a breadcrumb has to make room itself. */
.ls-article__head {
    max-width: var(--ls-wrap);
    margin-inline: auto;
    padding: 5rem 1rem 0;
}

@media (min-width: 768px) {
    .ls-article__head {
        padding: 3rem 2.5rem 0;
    }
}

.ls-crumbs {
    margin-bottom: 1.5rem;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--ls-muted);
}

.ls-crumbs ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ls-crumbs li {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
}

.ls-crumbs a {
    color: var(--ls-accent);
    text-decoration: none;
    border-radius: 0.25rem;
}

.ls-crumbs a:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* A chevron rather than a slash: it reads as a direction, so it survives being
   flipped for RTL without the glyph meaning something else. Scoped to the
   breadcrumb so it still wins over .ls-icon's own size. */
.ls-crumbs .ls-crumbs__sep {
    width: 0.875em;
    height: 0.875em;
    color: var(--ls-rule);
}

.ls-crumbs [aria-current="page"] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* On a phone the section is as far as the trail needs to go: the headline is
   already the H1 three lines below, and printing it twice pushes the story off
   the first screen. A listing keeps its last crumb — "News" is short and is the
   page's own name. */
@media (max-width: 639px) {
    /* Scoped to beat `.ls-crumbs li`, which sets display on every item. */
    .ls-crumbs .ls-crumbs__here {
        display: none;
    }

    .ls-crumbs--full .ls-crumbs__here {
        display: flex;
    }
}

.ls-kicker {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.625rem;
    margin: 0 0 1rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ls-kicker__cat {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.75rem;
    border-radius: 999px;
    background-color: var(--ls-accent-container);
    color: var(--ls-on-accent);
    text-decoration: none;
}

a.ls-kicker__cat:hover {
    filter: brightness(1.08);
}

.ls-kicker__meta {
    color: var(--ls-muted);
    font-weight: 500;
    letter-spacing: 0.02em;
    text-transform: none;
}

/* The headline owns the full column width on a desktop. It is the one element
   on the page that earns the whole measure: set in the display face at a tight
   leading, a wide headline reads as a masthead rather than as a paragraph, and
   constraining it to a reading measure only wraps it into three short lines. */
.ls-article__title {
    margin: 0;
    font-family: var(--ls-font-display);
    /* Fluid: ~30px on a 390px phone, 56px on a wide desktop. */
    font-size: clamp(1.875rem, 1.2rem + 3.2vw, 3.5rem);
    font-weight: 800;
    line-height: 1.08;
    letter-spacing: -0.022em;
    color: var(--ls-heading);
    overflow-wrap: break-word;
    text-wrap: balance;
}

.ls-article__standfirst {
    max-width: var(--ls-measure);
    margin: 1.25rem 0 0;
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--ls-muted);
}

@media (min-width: 768px) {
    .ls-article__standfirst {
        font-size: 1.1875rem;
    }
}

/* Byline. Shared by the blog article and the news story, which do not put the
   same things in it: a blog post has a named author, a news story has an outlet
   and a timestamp. The base row is the plain one the blog uses — a line of
   separators — and .ls-byline--story is the news layout, where the source gets
   a mark of its own and the dates sit opposite it as metadata rather than as a
   sentence. Splitting them rather than restyling the base keeps the blog page
   from having its three items flung to the edges of the column. */
.ls-byline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--ls-rule);
    font-size: 0.875rem;
    color: var(--ls-muted);
}

.ls-byline__author {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
    color: var(--ls-body);
}

.ls-byline__avatar,
.ls-byline__badge {
    display: grid;
    place-items: center;
    flex: none;
    border-radius: 999px;
    background-color: var(--ls-accent-container);
    color: var(--ls-on-accent);
    font-family: var(--ls-font-display);
    font-size: 0.8125rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.ls-byline__avatar {
    width: 2rem;
    height: 2rem;
}

.ls-byline__sep {
    color: var(--ls-rule);
}

/* The news story's version of the same strip. */
.ls-byline--story {
    gap: 0.75rem 1.5rem;
    margin-top: 1.75rem;
}

@media (min-width: 768px) {
    .ls-byline--story {
        justify-content: space-between;
    }
}

.ls-byline__source {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0;
    min-width: 0;
}

.ls-byline__badge {
    width: 2.25rem;
    height: 2.25rem;
}

.ls-byline__badge .ls-icon {
    width: 1.125rem;
    height: 1.125rem;
}

.ls-byline__source-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.ls-byline__label {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ls-muted);
}

.ls-byline__name {
    font-family: var(--ls-font-display);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.25;
    color: var(--ls-body);
}

.ls-byline__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1.25rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ls-byline__item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--ls-muted);
}

.ls-byline__item .ls-icon {
    width: 1rem;
    height: 1rem;
    color: var(--ls-accent);
}

.ls-byline__item--updated {
    color: var(--ls-body);
}

.ls-byline__item--updated time {
    font-weight: 600;
}

/* The way out of the article, at the end of it. Full-width targets on a phone:
   this is the last thing a reader reaches with a thumb. */
.ls-article__end {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--ls-rule);
}

.ls-article__back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 48px;
    padding: 0 1.5rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    background-color: var(--ls-card);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--ls-body);
    text-decoration: none;
}

.ls-article__back:hover {
    border-color: var(--ls-accent);
    color: var(--ls-accent);
}

.ls-article__topic-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    min-height: 48px;
    padding: 0 0.25rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--ls-accent);
    text-decoration: none;
}

.ls-article__topic-link:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
}

@media (max-width: 639px) {
    .ls-article__end {
        flex-direction: column;
        align-items: stretch;
    }
}

/* ------------------------------------------------------------ 6. Hero figure */

.ls-hero {
    max-width: var(--ls-wrap);
    margin: 1.5rem auto 0;
    padding-inline: 1rem;
}

@media (min-width: 768px) {
    .ls-hero {
        margin-top: 2rem;
        padding-inline: 2.5rem;
    }
}

.ls-hero__frame {
    position: relative;
    overflow: hidden;
    border-radius: var(--ls-radius-card);
    border: 1px solid var(--ls-rule);
    background-color: var(--ls-card);
}

.ls-hero__img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

/* A picture smaller than the frame.
   The frame is 1200px wide on a desktop and a publisher's photograph is
   whatever size they published it, so a 640px JPEG stretched to fill the frame
   is soft and visibly so. site.js measures the picture once it loads and, when
   it cannot fill the frame without upscaling, marks the figure and hands it the
   picture's own width: the frame shrinks to that, the 16:9 crop is dropped so
   nothing is cut off, and the two sit centred in the column. The credit keeps
   the same width so it stays under the picture it belongs to. */
.ls-hero--intrinsic .ls-hero__frame,
.ls-hero--intrinsic .ls-hero__credit {
    max-width: var(--ls-hero-width, 100%);
    margin-inline: auto;
}

.ls-hero--intrinsic .ls-hero__img {
    aspect-ratio: auto;
    height: auto;
    object-fit: contain;
}

/* The licence credit under the lead picture. Small and muted: it has to be
   present for the picture to be honestly used, and it must not compete with
   the headline above it. */
.ls-hero__credit {
    margin: 0.5rem 0 0;
    font-size: 0.75rem;
    line-height: 1.4;
    color: var(--ls-muted);
    text-align: end;
}


/* ------------------------------- 7. Article layout + table of contents ----- */

.ls-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
    max-width: var(--ls-wrap);
    margin-inline: auto;
    padding: 1.75rem 1rem 1rem;
}

@media (min-width: 768px) {
    .ls-layout {
        gap: 2.5rem;
        padding: 2.5rem 2.5rem 1rem;
    }
}

@media (min-width: 1080px) {
    .ls-layout {
        grid-template-columns: 17rem minmax(0, 1fr);
        gap: 4rem;
        align-items: start;
    }

    /* Collapse the empty column when an article has no headings to list. */
    .ls-layout--no-toc {
        grid-template-columns: minmax(0, 1fr);
    }
}

.ls-toc {
    border: 1px solid var(--ls-rule);
    border-radius: 1.5rem;
    background-color: var(--ls-card);
}

@media (min-width: 1080px) {
    .ls-toc {
        position: sticky;
        inset-block-start: 6rem;
    }
}

.ls-toc__summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 1rem 1.25rem;
    cursor: pointer;
    font-family: var(--ls-font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--ls-heading);
    list-style: none;
}

.ls-toc__summary::-webkit-details-marker {
    display: none;
}

.ls-toc__chevron {
    transition: transform 200ms ease;
}

.ls-toc[open] .ls-toc__chevron {
    transform: rotate(90deg);
}

.ls-toc__list {
    margin: 0;
    padding: 0 1.25rem 1.25rem;
    list-style: none;
    counter-reset: ls-toc;
}

.ls-toc__list li {
    counter-increment: ls-toc;
}

.ls-toc__link {
    display: flex;
    gap: 0.625rem;
    padding: 0.5rem 0.5rem 0.5rem 0;
    border-inline-start: 2px solid transparent;
    padding-inline-start: 0.75rem;
    font-size: 0.875rem;
    line-height: 1.45;
    color: var(--ls-muted);
    text-decoration: none;
}

.ls-toc__link::before {
    content: counter(ls-toc, decimal-leading-zero);
    flex: none;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--ls-accent);
    padding-top: 0.15em;
}

.ls-toc__link:hover {
    color: var(--ls-heading);
    border-inline-start-color: var(--ls-rule);
}

/* Set by public/js/site.js as the reader scrolls. Falls back to the hover
   treatment when JS is unavailable, which is why it is additive only. */
.ls-toc__link[aria-current="true"] {
    color: var(--ls-heading);
    font-weight: 600;
    border-inline-start-color: var(--ls-accent);
}

/* ---------------------------------------- 8. Article body typography ------- */

.ls-prose {
    max-width: var(--ls-measure);
    font-size: 1.125rem;
    line-height: 1.75;
    color: var(--ls-body);
    overflow-wrap: break-word;
    counter-reset: ls-section;
}

.ls-prose > *:first-child {
    margin-top: 0;
}

.ls-prose p {
    margin: 0 0 1.4em;
}

.ls-prose strong,
.ls-prose b {
    font-weight: 700;
    color: var(--ls-heading);
}

.ls-prose em,
.ls-prose i {
    font-style: italic;
}

/* The opening paragraph of most articles is a single <strong> sentence. The
   publish-time pass tags it .ls-takeaway; without the tag it stays ordinary
   body copy, so this is safe for any article shape. */
.ls-prose .ls-takeaway {
    padding: 1.25rem 1.5rem;
    margin-bottom: 2rem;
    border-inline-start: 4px solid var(--ls-accent);
    border-radius: 0 1rem 1rem 0;
    background-color: var(--ls-card);
    font-size: 1.0625rem;
    line-height: 1.65;
}

:root[dir="rtl"] .ls-prose .ls-takeaway,
[dir="rtl"] .ls-prose .ls-takeaway {
    border-radius: 1rem 0 0 1rem;
}

.ls-prose .ls-takeaway strong,
.ls-prose .ls-takeaway b {
    font-weight: 600;
    color: var(--ls-heading);
}

/* The callout's label ("Quick answer", "Réponse rapide", ...). The publish-time
   pass writes it into data-label already translated, so nothing here has to
   know the language. */
.ls-prose .ls-takeaway[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 0.6rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ls-accent);
}

/* Headings ---------------------------------------------------------------- */

.ls-prose h2 {
    position: relative;
    margin: 3.25rem 0 1.1rem;
    padding-inline-start: 1.125rem;
    border-inline-start: 5px solid var(--ls-accent);
    font-family: var(--ls-font-display);
    font-size: clamp(1.5rem, 1.25rem + 0.8vw, 1.875rem);
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: -0.015em;
    color: var(--ls-heading);
    scroll-margin-top: 6rem;
    text-wrap: balance;
}

/* The section number, so a long guide reads as numbered steps the reader can
   keep their place in. Counted in CSS, so the stored HTML stays untouched. */
.ls-prose h2::before {
    content: counter(ls-section, decimal-leading-zero);
    display: block;
    margin-bottom: 0.35rem;
    font-family: var(--ls-font-body);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    color: var(--ls-accent);
}

.ls-prose h2 {
    counter-increment: ls-section;
}

.ls-prose h3 {
    position: relative;
    margin: 2.25rem 0 0.7rem;
    padding-inline-start: 1.375rem;
    font-family: var(--ls-font-display);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--ls-heading);
    scroll-margin-top: 6rem;
}

.ls-prose h3::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0.5em;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 999px;
    background-color: var(--ls-accent);
}

.ls-prose h4 {
    margin: 1.75rem 0 0.5rem;
    font-family: var(--ls-font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--ls-heading);
}

/* The FAQ block ----------------------------------------------------------- */

/* The publish-time pass tags the "frequently asked questions" heading and the
   question/answer pairs that follow it. Answers stay visible: Google needs the
   text in the rendered page for FAQPage markup to be eligible, and the AI
   answer engines the content plan targets read the same text. */

.ls-prose h2.ls-faq-heading {
    border-inline-start-color: rgb(var(--c-secondary));
}

.ls-prose h2.ls-faq-heading::before {
    color: rgb(var(--c-secondary));
}

.ls-prose .ls-faq-item {
    padding: 1.125rem 1.25rem;
    margin-bottom: 0.875rem;
    border: 1px solid var(--ls-rule);
    border-radius: 1rem;
    background-color: var(--ls-page);
}

.ls-prose .ls-faq-item h3 {
    margin: 0 0 0.5rem;
}

.ls-prose .ls-faq-item p {
    margin-bottom: 0;
    font-size: 1rem;
    line-height: 1.7;
    color: var(--ls-muted);
}

/* Lists ------------------------------------------------------------------- */

.ls-prose ul,
.ls-prose ol {
    margin: 0 0 1.5rem;
    padding-inline-start: 1.375rem;
}

.ls-prose ul {
    list-style: none;
}

.ls-prose ol {
    list-style: decimal;
}

.ls-prose li {
    margin-bottom: 0.6em;
    padding-inline-start: 0.125rem;
}

.ls-prose ul > li::marker {
    color: transparent;
}

.ls-prose ol > li::marker {
    color: var(--ls-accent);
    font-weight: 700;
    font-size: 0.9375em;
}

/* Custom bullet: a small brand tick instead of a plain disc. */
.ls-prose ul > li {
    position: relative;
}

.ls-prose ul > li::before {
    content: "";
    position: absolute;
    inset-inline-start: -1.125rem;
    inset-block-start: 0.62em;
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 2px;
    background-color: var(--ls-accent);
    opacity: 0.85;
}

.ls-prose li > ul,
.ls-prose li > ol {
    margin-top: 0.6em;
}

/* Quotes, rules and media ------------------------------------------------ */

.ls-prose blockquote {
    margin: 2rem 0;
    padding: 0.25rem 0 0.25rem 1.5rem;
    border-inline-start: 4px solid var(--ls-accent);
    font-size: 1.125rem;
    font-style: italic;
    color: var(--ls-muted);
}

.ls-prose blockquote p:last-child {
    margin-bottom: 0;
}

.ls-prose hr {
    height: 1px;
    margin: 2.75rem 0;
    border: 0;
    background: linear-gradient(90deg, var(--ls-rule), transparent);
}

.ls-prose img {
    display: block;
    width: 100%;
    margin: 2rem 0;
    border-radius: var(--ls-radius-media);
}

.ls-prose a {
    color: var(--ls-accent);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}

.ls-prose a:hover {
    text-decoration-thickness: 2px;
}

/* ------------------------------------------------- 9. Article footer ------- */

.ls-article__foot {
    max-width: var(--ls-wrap);
    margin-inline: auto;
    padding: 0 1rem 3.5rem;
}

@media (min-width: 768px) {
    .ls-article__foot {
        padding-inline: 2.5rem;
    }
}

.ls-article__foot-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}

/* Same grid as .ls-layout, with the contents column left empty, so the tags
   and the share row start exactly under the body copy on a wide screen. */
@media (min-width: 1080px) {
    .ls-article__foot-inner {
        grid-template-columns: 17rem minmax(0, 1fr);
        gap: 4rem;
    }

    .ls-article__foot-inner > * {
        grid-column: 2;
    }
}

.ls-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--ls-rule);
}

/* The topic and keyword terms under a story. Named apart from .ls-tag, which is
   the filled section pill the cards use: a keyword is a label, not a control,
   and two rules for one class name meant whichever came last in this file won —
   so the article's keywords were being painted as if they were topic buttons. */
.ls-keyword {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
    padding: 0 0.875rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--ls-muted);
    text-decoration: none;
    background-color: var(--ls-card);
}

a.ls-keyword:hover {
    color: var(--ls-accent);
    border-color: var(--ls-accent);
}

/* Inline icons. Small, currentColor-only SVGs rather than the Material Symbols
   icon font: the article page then needs no icon-font request at all, and the
   glyph is painted with the first frame instead of after a font swap. */
.ls-icon {
    flex: none;
    width: 1.125em;
    height: 1.125em;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.ls-share {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1.5rem;
}

.ls-share__label {
    margin-inline-end: 0.25rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ls-muted);
}

.ls-share__btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 40px;
    padding: 0 0.875rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    background-color: var(--ls-page);
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ls-body);
    text-decoration: none;
    cursor: pointer;
}

.ls-share__btn:hover {
    border-color: var(--ls-accent);
    color: var(--ls-accent);
}

/* On a phone the share controls become a two-column block of full-width
   targets rather than a row that wraps into a ragged second line — the last
   thing on the page should be easy to hit with a thumb, not a puzzle. */
@media (max-width: 639px) {
    .ls-share {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        margin-top: 1.25rem;
    }

    .ls-share__label {
        grid-column: 1 / -1;
        margin-inline-end: 0;
    }

    .ls-share__btn {
        justify-content: center;
        min-height: 48px;
    }
}

/* Swapped in by site.js once the clipboard call resolves, then restored — the
   button is a plain link-like control when JS is unavailable. */
.ls-share__btn[data-copied="true"] {
    border-color: var(--ls-accent);
    color: var(--ls-accent);
}

/* The language-fallback notice sits above the body, inside the reading column,
   so it needs no offset of its own. */
.ls-article__note {
    max-width: var(--ls-measure);
    margin: 0 0 2.5rem;
    padding: 1rem 1.25rem;
    border: 1px solid var(--ls-rule);
    border-radius: 1rem;
    background-color: var(--ls-card);
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--ls-muted);
}

/* The reading column of the layout grid. min-width:0 keeps a long unbroken
   string from forcing the grid wider than the viewport. */
.ls-article__main {
    min-width: 0;
}


.ls-to-top {
    position: fixed;
    inset-block-end: 5.5rem;
    inset-inline-end: 1rem;
    z-index: 40;
    display: none;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    background-color: var(--ls-card);
    color: var(--ls-body);
    cursor: pointer;
    box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
}

.ls-to-top[data-visible="true"] {
    display: grid;
}

@media (min-width: 768px) {
    .ls-to-top {
        inset-block-end: 2rem;
        inset-inline-end: 2rem;
    }
}

/* --------------------------------------------------- 10. Post index -------- */

/* A listing's masthead. Opens on a breadcrumb like the article masthead, so it
   clears the fixed mobile header the same way. */
.ls-index__head {
    max-width: var(--ls-wrap);
    margin-inline: auto;
    padding: 5rem 1rem 0;
}

@media (min-width: 768px) {
    .ls-index__head {
        padding: 3rem 2.5rem 0;
    }
}

.ls-index__title {
    margin: 0;
    font-family: var(--ls-font-display);
    font-size: clamp(2rem, 1.35rem + 2.9vw, 3rem);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--ls-heading);
}

.ls-index__lede {
    max-width: var(--ls-measure);
    margin: 0.75rem 0 0;
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--ls-muted);
}

.ls-chips {
    display: flex;
    gap: 0.5rem;
    margin: 1.75rem 0 0;
    padding: 0 0 0.5rem;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}

.ls-chips::-webkit-scrollbar {
    display: none;
}

.ls-chip {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 1rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    font-size: 0.875rem;
    font-weight: 600;
    white-space: nowrap;
    color: var(--ls-body);
    background-color: var(--ls-page);
    text-decoration: none;
}

.ls-chip:hover {
    border-color: var(--ls-accent);
    color: var(--ls-accent);
}

.ls-chip[aria-current="page"] {
    border-color: var(--ls-accent-container);
    background-color: var(--ls-accent-container);
    color: var(--ls-on-accent);
}

.ls-index__body {
    max-width: var(--ls-wrap);
    margin-inline: auto;
    padding: 2rem 1rem 4rem;
}

@media (min-width: 768px) {
    .ls-index__body {
        padding-inline: 2.5rem;
    }
}

.ls-feature {
    position: relative;
    display: block;
    overflow: hidden;
    min-height: 280px;
    margin-bottom: 2rem;
    border: 1px solid var(--ls-rule);
    border-radius: var(--ls-radius-card);
    background-color: var(--ls-card);
    text-decoration: none;
    color: #fff;
}

@media (min-width: 768px) {
    .ls-feature {
        min-height: 400px;
    }
}

.ls-feature__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 500ms ease;
}

.ls-feature:hover .ls-feature__img {
    transform: scale(1.04);
}

.ls-feature__scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgb(0 0 0 / 0.82), rgb(0 0 0 / 0.35) 45%, transparent);
}

.ls-feature__text {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    padding: 1.5rem;
}

@media (min-width: 768px) {
    .ls-feature__text {
        padding: 2.5rem;
    }
}

.ls-feature__title {
    display: block;
    max-width: 46rem;
    margin: 0.875rem 0 0;
    font-family: var(--ls-font-display);
    font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.5rem);
    font-weight: 800;
    line-height: 1.12;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

.ls-feature__excerpt {
    display: block;
    max-width: 40rem;
    margin: 0.875rem 0 0;
    font-size: 1rem;
    line-height: 1.6;
    color: rgb(255 255 255 / 0.86);
    /* Three-line clamp: the lead card has a fixed height, so a long excerpt
       would otherwise push the title out of the frame. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ls-grid {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) {
    .ls-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 1024px) {
    .ls-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.ls-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--ls-rule);
    border-radius: var(--ls-radius-card);
    background-color: var(--ls-card);
    transition: box-shadow 200ms ease, transform 200ms ease;
}

.ls-card:hover,
.ls-card:focus-within {
    box-shadow: 0 12px 32px rgb(0 0 0 / 0.1);
    transform: translateY(-2px);
}

.ls-card__link {
    display: flex;
    flex: 1;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
}

.ls-card__media {
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background-color: rgb(var(--c-surface-container));
}

/* A picture slot may hold a <picture> when there is a WebP set to offer (the
   news cards and lead, and the article hero). The wrapper is the one element
   here with no job of its own, so it is taken out of the layout entirely and
   the <img> inside behaves exactly as it did when it was the only child. */
.ls-card__media picture,
.ls-lead__media picture,
.ls-hero__frame picture {
    display: contents;
}

.ls-card__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 500ms ease;
}

.ls-card:hover .ls-card__img {
    transform: scale(1.05);
}

.ls-card__body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1.5rem;
}

.ls-card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--ls-muted);
}

.ls-card__cat {
    padding: 0.15rem 0.625rem;
    border-radius: 999px;
    background-color: rgb(var(--c-primary-container));
    color: rgb(var(--c-on-primary-container));
    font-weight: 600;
}

/* A story that has not been translated into this page's language still appears
   in the listing, in English. The tag names that language so a reader sees a
   choice, not a break: the section is multi-language, this one card is not yet.
   Muted and unfilled so it reads as a caveat, not as a call to action. */
.ls-card__lang {
    padding: 0.1rem 0.5rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--ls-muted);
}

.ls-card__title {
    margin: 0;
    font-family: var(--ls-font-display);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--ls-heading);
    /* Two-line clamp without the line-clamp plugin. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ls-card__excerpt {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--ls-muted);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ls-card__more {
    margin-top: auto;
    padding-top: 0.5rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--ls-accent);
}

.ls-empty {
    margin: 0;
    padding: 2.5rem;
    border: 1px solid var(--ls-rule);
    border-radius: var(--ls-radius-card);
    background-color: var(--ls-card);
    text-align: center;
    color: var(--ls-muted);
}

/* The listing pager — see partials/pager.blade.php for why it is hand-written
   instead of Laravel's own paginator view.

   One markup, two shapes:

     phone    ‹ Previous   Next ›
                  Page 3 of 12

     desktop   ‹ Previous   1 … 3 4 5 … 12   Next ›

   The phone stacks rather than fitting one row because the three things it has
   to say do not share a 360px line in every language — "Страница 6 из 12"
   between two labelled pills overflows, and the overflow used to push the Next
   button past the edge of the page. Two half-width pills on one row and the
   position under them fits in any language at any width.

   From 768px the position line is not needed: the highlighted number says the
   same thing, and the numbers take the middle column. */
.ls-pager {
    margin-top: 3rem;
}

.ls-pager__bar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0.5rem 0.75rem;
}

/* --- the two steps --- */

.ls-pager__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-height: 44px;
    padding-inline: 0.9rem;
    border: 1px solid var(--ls-rule);
    border-radius: 999px;
    background-color: var(--ls-page);
    color: var(--ls-body);
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

/* Placed explicitly: the numbered list is display:none on a phone, so with auto
   placement the Next button would land in the row the position line needs. */
.ls-pager__step:first-child {
    grid-column: 1;
    grid-row: 1;
}

.ls-pager__step:last-child {
    grid-column: 2;
    grid-row: 1;
}

a.ls-pager__step:hover {
    border-color: var(--ls-accent);
    color: var(--ls-accent);
}

/* The first and last page have nowhere to go. It stays in the layout as a
   <span> so the middle item does not shift when the reader reaches an end. */
.ls-pager__step[aria-disabled="true"] {
    opacity: 0.4;
}

/* Chevrons are drawn for a left-to-right reader. The rest of the component is
   logical properties and needs no telling; this is the only thing that does. */
.ls-pager__chevron--next {
    transform: scaleX(-1);
}

[dir="rtl"] .ls-pager__chevron--next {
    transform: none;
}

[dir="rtl"] .ls-pager__chevron:not(.ls-pager__chevron--next) {
    transform: scaleX(-1);
}

/* --- the position line (phone only) --- */

.ls-pager__status {
    grid-column: 1 / -1;
    grid-row: 2;
    margin: 0.25rem 0 0;
    font-size: 0.875rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ls-muted);
    text-align: center;
    white-space: nowrap;
}

/* --- the numbered run (768px and up) --- */

.ls-pager__pages {
    display: none;
    align-items: center;
    gap: 0.25rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ls-pager__page {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    height: 44px;
    padding-inline: 0.5rem;
    border: 1px solid transparent;
    border-radius: 999px;
    color: var(--ls-body);
    font-size: 0.9375rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-decoration: none;
}

a.ls-pager__page:hover {
    border-color: var(--ls-rule);
    background-color: var(--ls-card);
}

.ls-pager__page[aria-current="page"] {
    border-color: var(--ls-accent-container);
    background-color: var(--ls-accent-container);
    color: var(--ls-on-accent);
}

/* A skipped run. Read by sight as "…" and hidden from a screen reader, which
   gets the position from the links on either side of it instead. */
.ls-pager__gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 44px;
    color: var(--ls-muted);
}

@media (min-width: 768px) {
    .ls-pager__bar {
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
        align-items: center;
        gap: 0.75rem;
    }

    .ls-pager__step:first-child {
        justify-self: start;
    }

    .ls-pager__step:last-child {
        grid-column: 3;
        justify-self: end;
    }

    .ls-pager__pages {
        display: flex;
        grid-column: 2;
        grid-row: 1;
    }

    .ls-pager__status {
        display: none;
    }
}

/* ------------------------------------------------- 11. Related articles ---- */

.ls-related {
    padding: 4rem 0;
    border-top: 1px solid var(--ls-rule);
    background-color: var(--ls-card);
}

.ls-related__title {
    margin: 0 0 2rem;
    font-family: var(--ls-font-display);
    font-size: clamp(1.5rem, 1.25rem + 0.8vw, 2rem);
    font-weight: 800;
    letter-spacing: -0.015em;
    color: var(--ls-heading);
}

/* -------------------------------------------------------- 12. News list ---- */

/* The lead story, laid out beside its image rather than under it. The news
   cards below reuse .ls-card; only this one differs, because a single story
   should be visibly the one to read first. */
.ls-lead {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    overflow: hidden;
    margin-bottom: 2rem;
    border: 1px solid var(--ls-rule);
    border-radius: var(--ls-radius-card);
    background-color: var(--ls-card);
    color: inherit;
    text-decoration: none;
    transition: box-shadow 200ms ease, transform 200ms ease;
}

@media (min-width: 768px) {
    .ls-lead {
        grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    }
}

.ls-lead:hover,
.ls-lead:focus-within {
    box-shadow: 0 12px 32px rgb(0 0 0 / 0.1);
    transform: translateY(-2px);
}

.ls-lead__media {
    position: relative;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    background-color: rgb(var(--c-surface-container));
}

@media (min-width: 768px) {
    /* Stretch to the text column's height instead of forcing a ratio. */
    .ls-lead__media {
        aspect-ratio: auto;
        height: 100%;
        min-height: 22rem;
    }
}

/* Out of flow on purpose. An in-flow <img> at width/height 100% still measures
   as its own aspect ratio while the grid row is being sized, so a portrait
   photograph — publishers publish them, and one in this feed is 1200×1800 —
   decided how tall the lead story was: the picture won, the row grew to the
   picture's full height, and the copy sat at the top of a column that was two
   screens tall. Taken out of flow the frame is the only thing that can size the
   row, and every story crops to the same shape. */
.ls-lead__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 500ms ease;
}

.ls-lead:hover .ls-lead__img {
    transform: scale(1.03);
}

.ls-lead__body {
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
    padding: 1.5rem;
}

/* The body is a column, so everything in it stretches to the column's width:
   right for the headline and the standfirst, wrong for the topic pill, which is
   a chip and was being drawn as a full-width bar above the headline. Only the
   lead needs saying: a card's tags sit in a row, and in a row the same pill is
   already only as wide as its word. Kept off .ls-tag itself so the cards keep
   the centring they get from .ls-card__meta. */
.ls-lead__body > .ls-tag {
    align-self: flex-start;
}

@media (min-width: 768px) {
    .ls-lead__body {
        justify-content: center;
        padding: 2.5rem;
    }
}

.ls-lead__title {
    margin: 0;
    font-family: var(--ls-font-display);
    font-size: clamp(1.375rem, 1.1rem + 1.3vw, 2rem);
    font-weight: 800;
    line-height: 1.18;
    letter-spacing: -0.018em;
    color: var(--ls-heading);
    text-wrap: balance;
}

.ls-lead__excerpt {
    margin: 0;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--ls-muted);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ls-lead__foot {
    margin-top: auto;
    padding-top: 0.5rem;
}

/* Section pill. Coloured per topic, using the same three accent tokens the
   rest of the site already reads, so the palette is unchanged. */
.ls-tag {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.2rem 0.7rem;
    border-radius: 999px;
    background-color: rgb(var(--c-primary-container));
    color: rgb(var(--c-on-primary-container));
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    text-decoration: none;
}

.ls-tag--immigration {
    background-color: rgb(var(--c-secondary-container));
    color: rgb(var(--c-on-secondary-container));
}

.ls-tag--policy {
    background-color: rgb(var(--c-tertiary-container));
    color: rgb(var(--c-on-tertiary-container));
}

/* The card's footer line: who reported it. Kept apart from .ls-card__meta
   because it is attribution, and a reader scanning the grid should find it in
   the same place on every card. */
.ls-card__source {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: auto;
    padding-top: 0.75rem;
    border-top: 1px solid var(--ls-rule);
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--ls-muted);
}

/* ------------------------------------------------------ 13. News article --- */

.ls-story__body {
    min-width: 0;
    counter-reset: ls-story-section;
}

/* One of the five sections of a news page. The left rule and the number are
   painted in CSS so the markup stays plain headings and paragraphs. */
.ls-story__section {
    counter-increment: ls-story-section;
    padding-block: 1.75rem;
    border-top: 1px solid var(--ls-rule);
    scroll-margin-top: 6rem;
}

@media (min-width: 768px) {
    .ls-story__section {
        padding-block: 2.25rem;
    }
}

.ls-story__section:first-child {
    padding-top: 0;
    border-top: 0;
}

.ls-story__heading {
    position: relative;
    margin: 0 0 1.5rem;
    padding-inline-start: 1.125rem;
    border-inline-start: 5px solid var(--ls-accent);
    font-family: var(--ls-font-display);
    font-size: clamp(1.375rem, 1.2rem + 0.7vw, 1.75rem);
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: -0.015em;
    color: var(--ls-heading);
    text-wrap: balance;
}

.ls-story__heading::before {
    content: counter(ls-story-section, decimal-leading-zero);
    display: block;
    margin-bottom: 0.35rem;
    font-family: var(--ls-font-body);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    color: var(--ls-accent);
}

/* At a glance ------------------------------------------------------------- */

/* The three facts a reader needs before deciding whether to read on. Rendered
   as a definition list so the label/value pairing survives with no styles. */
.ls-glance {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1px;
    margin: 0;
    overflow: hidden;
    border: 1px solid var(--ls-rule);
    border-radius: 1.25rem;
    background-color: var(--ls-rule);
}

@media (min-width: 640px) {
    .ls-glance {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.ls-glance__item {
    padding: 1.25rem;
    background-color: var(--ls-card);
}

.ls-glance__label {
    margin: 0 0 0.5rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ls-accent);
}

.ls-glance__value {
    margin: 0;
    font-family: var(--ls-font-display);
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.45;
    color: var(--ls-heading);
}

/* The reference block in section 2 --------------------------------------- */

.ls-facts {
    margin: 0 0 2rem;
    padding: 0;
    border: 1px solid var(--ls-rule);
    border-radius: 1.25rem;
    background-color: var(--ls-card);
}

.ls-facts__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.25rem;
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--ls-rule);
}

.ls-facts__row:first-child {
    border-top: 0;
}

@media (min-width: 640px) {
    .ls-facts__row {
        grid-template-columns: 11rem minmax(0, 1fr);
        gap: 1rem;
    }
}

.ls-facts__term {
    margin: 0;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ls-muted);
}

.ls-facts__desc {
    margin: 0;
    font-size: 1rem;
    line-height: 1.55;
    color: var(--ls-body);
}

/* Detail prose ----------------------------------------------------------- */

.ls-story__prose {
    max-width: var(--ls-measure);
    font-size: 1.0625rem;
    line-height: 1.7;
    color: var(--ls-body);
}

.ls-story__prose p {
    margin: 0 0 1rem;
}

.ls-story__prose h3 {
    margin: 2rem 0 0.65rem;
    font-family: var(--ls-font-display);
    font-size: 1.1875rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--ls-heading);
    scroll-margin-top: 6rem;
}

.ls-story__prose ul {
    margin: 0 0 1.25rem;
    padding-inline-start: 1.25rem;
}

.ls-story__prose li {
    margin-bottom: 0.4rem;
}

.ls-story__prose li::marker {
    color: var(--ls-accent);
}

/* Traveller impact ------------------------------------------------------- */

.ls-impact {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
}

@media (min-width: 768px) {
    .ls-impact {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.ls-impact__item {
    padding: 1.25rem;
    border: 1px solid var(--ls-rule);
    border-radius: 1.25rem;
    background-color: var(--ls-card);
}

.ls-impact__title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 0.875rem;
    font-family: var(--ls-font-display);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--ls-heading);
}

.ls-impact__title .ls-icon {
    color: var(--ls-accent);
}

.ls-impact__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.ls-impact__list li {
    position: relative;
    margin-bottom: 0.65rem;
    padding-inline-start: 1.1rem;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--ls-muted);
}

.ls-impact__list li::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0.62em;
    width: 0.3125rem;
    height: 0.3125rem;
    border-radius: 999px;
    background-color: var(--ls-accent);
}

/* Affected groups -------------------------------------------------------- */

.ls-affected {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.875rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 768px) {
    .ls-affected {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.ls-affected__item {
    padding: 1.25rem;
    border: 1px solid var(--ls-rule);
    border-radius: 1.25rem;
    background-color: var(--ls-card);
}

.ls-affected__group {
    margin: 0 0 0.5rem;
    font-family: var(--ls-font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--ls-heading);
}

.ls-affected__why {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--ls-muted);
}

.ls-affected__action {
    margin: 0.75rem 0 0;
    padding-top: 0.75rem;
    border-top: 1px solid var(--ls-rule);
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--ls-body);
}

/* FAQ -------------------------------------------------------------------- */

/* Native <details>, so the answers are in the HTML for search engines and for
   a reader with no JavaScript, and a tap opens them with no script at all. */
.ls-story__faq {
    margin: 0;
    padding: 0;
}

.ls-story__faq-item {
    border: 1px solid var(--ls-rule);
    border-radius: 1rem;
    background-color: var(--ls-card);
}

.ls-story__faq-item + .ls-story__faq-item {
    margin-top: 0.75rem;
}

.ls-story__faq-q {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.125rem 1.25rem;
    min-height: 48px;
    cursor: pointer;
    font-family: var(--ls-font-display);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.4;
    color: var(--ls-heading);
    list-style: none;
}

.ls-story__faq-q::-webkit-details-marker {
    display: none;
}

.ls-story__faq-q .ls-icon {
    flex: none;
    margin-block-start: 0.2em;
    color: var(--ls-accent);
    transition: transform 200ms ease;
}

.ls-story__faq-item[open] .ls-story__faq-q .ls-icon {
    transform: rotate(180deg);
}

.ls-story__faq-a {
    margin: 0;
    padding: 0 1.25rem 1.25rem;
    font-size: 1rem;
    line-height: 1.65;
    color: var(--ls-muted);
}

/* Source -------------------------------------------------------------- */

/* The credit that makes the page accountable: the outlet, the date, a link out.
   Every claim above it is a rewrite of this one document. */
.ls-source {
    margin: 2.5rem 0 0;
    padding: 1.25rem;
    border: 1px solid var(--ls-rule);
    border-radius: 1.25rem;
    background-color: var(--ls-card);
}

.ls-source__label {
    margin: 0 0 0.5rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ls-muted);
}

.ls-source__link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 44px;
    font-size: 1rem;
    font-weight: 600;
    color: var(--ls-accent);
    text-decoration: none;
}

.ls-source__link:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.ls-source__meta {
    margin: 0.25rem 0 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--ls-muted);
}

/* Desktop only: the share row and back-to-top sit at the end of the reading
   column, so they must not be hidden behind the mobile bottom bar. */
.ls-story__foot {
    margin-top: 2rem;
}

/* ------------------------------------------------ 14. Tour promotion ------- */

/* Three placements, one idea: a reader who has just read a story about a place
   is the likeliest buyer of a trip to it. They are the same three the article
   page renders — a word linked inside the story, a box of two tours at the
   foot of "the details", and the rail at the end — and none of them is a boxed
   display ad, because a news page that starts shouting stops reading as news.

   Everything is inline-axis aware: margins, padding and the accent rule use
   logical properties, so the layout mirrors on its own in Arabic and only the
   directional glyphs need turning over (see §15). */

/* The word in the story. A dotted underline reads as a link inside prose
   without the sentence looking like it was written by the marketing team, and
   the small compass says where it goes before the reader gets there. */
.ls-tourlink {
    color: var(--ls-accent);
    font-weight: 600;
    text-decoration: underline;
    text-decoration-style: dotted;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
    /* The word and its glyph are one link, so they wrap as a unit: a compass
       left alone at the start of the next line reads as a stray bullet. */
    white-space: nowrap;
}

.ls-tourlink:hover,
.ls-tourlink:focus-visible {
    text-decoration-style: solid;
    text-decoration-thickness: 2px;
}

.ls-tourlink__icon {
    /* The icon sits in the middle of a sentence, and the reset that ships with
       the utility stylesheet makes every svg a block: without this the glyph
       drops onto a line of its own below the word it belongs to. */
    display: inline-block;
    width: 0.95em;
    height: 0.95em;
    margin-inline-start: 0.16em;
    vertical-align: -0.12em;
    stroke-width: 1.8;
}

/* The box at the foot of "the details". Two tours, as text, inside the reading
   column and no wider than the prose it follows, so it reads as a paragraph of
   the story rather than as inventory bolted onto it.

   What is deliberately absent is the furniture that makes a unit read as an
   ad: no image, no button, no display face, no price in the accent colour. The
   surface is the same card and hairline the page's own fact blocks use, which
   is what keeps it looking like something the page already says. */
.ls-tourbox {
    max-width: var(--ls-measure);
    margin: 0 0 1.75rem;
    padding: 1.125rem 1.25rem;
    border: 1px solid var(--ls-rule);
    border-radius: var(--ls-radius-media);
    background-color: var(--ls-card);
}

@media (min-width: 768px) {
    .ls-tourbox {
        padding: 1.25rem 1.5rem;
    }
}

/* The label, in the same small letterspaced caps the page labels its facts
   with, so the box announces itself the way every other block on the page
   does. */
.ls-tourbox__label {
    margin: 0 0 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ls-muted);
}

.ls-tourbox__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Title and price on one line, price at the far end; on a narrow screen a long
   title wraps and the price goes with it rather than being squeezed into a
   column. Baseline alignment keeps the price on the title's first line when
   the title runs to two. */
.ls-tourbox__item {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.15rem 0.75rem;
    padding-block: 0.55rem;
    border-top: 1px solid var(--ls-rule);
    font-size: 1rem;
    line-height: 1.5;
}

.ls-tourbox__item:first-child {
    padding-block-start: 0;
    border-top: 0;
}

/* The same link the rest of the article's prose uses: accent colour, a hairline
   underline. Nothing about it says "buy". */
.ls-tourbox__link {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--ls-accent);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}

.ls-tourbox__link:hover,
.ls-tourbox__link:focus-visible {
    text-decoration-thickness: 2px;
}

.ls-tourbox__price {
    margin-inline-start: auto;
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--ls-muted);
}

/* The way to the rest of them, as a footnote rather than a call to action: it
   is the count and an arrow. Muted until hovered, so it does not compete with
   the two titles above it. */
.ls-tourbox__more {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-block-start: 0.7rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--ls-muted);
    text-decoration: none;
}

.ls-tourbox__more:hover,
.ls-tourbox__more:focus-visible {
    color: var(--ls-accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.ls-tourbox__more .ls-icon {
    width: 0.9rem;
    height: 0.9rem;
}

/* The rail at the end of the story. Sits on the page colour rather than on the
   card colour so it does not merge into the related-news strip below it, which
   is carded. */
.ls-tours {
    padding: 4rem 0;
    border-top: 1px solid var(--ls-rule);
    background-color: var(--ls-page);
}

.ls-tours__head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 2rem;
    margin-bottom: 2rem;
}

.ls-tours__title {
    margin: 0;
    font-family: var(--ls-font-display);
    font-size: clamp(1.5rem, 1.25rem + 0.8vw, 2rem);
    font-weight: 800;
    letter-spacing: -0.015em;
    color: var(--ls-heading);
}

.ls-tours__note {
    max-width: 52ch;
    margin: 0.4rem 0 0;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--ls-muted);
}

/* The separator between the destination and the word "tours". Drawn rather
   than typed: a middot depends on the display font having one, and the fonts
   that serve five scripts do not all agree on what it looks like. */
.ls-tours__sep {
    display: inline-block;
    width: 0.24em;
    height: 0.24em;
    margin-inline: 0.5rem;
    border-radius: 999px;
    /* Current colour at low opacity rather than the hairline token: the rule
       colour all but disappears at this size, and this one follows the theme. */
    background-color: currentColor;
    opacity: 0.45;
    vertical-align: 0.2em;
}

.ls-tours__all {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-family: var(--ls-font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--ls-accent);
    text-decoration: none;
}

.ls-tours__all:hover,
.ls-tours__all:focus-visible {
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.ls-tours__all .ls-icon {
    width: 1rem;
    height: 1rem;
}

/* Below 768px the row scrolls sideways, with the next card showing at the edge
   so the row reads as scrollable without a scrollbar or a hint. The negative
   margin cancels .ls-wrap's gutter at that width, so the first card lines up
   with the heading and the last can be scrolled clear of the edge — then it is
   handed back at 768px, where the wrap's own 2.5rem padding takes over. */
.ls-tours__rail {
    display: grid;
    grid-auto-flow: column;
    /* A length, not a percentage: a scrolling grid has no free space to give
       its tracks, so a percentage track would sit at its minimum instead of
       the width intended. 82vw leaves the next card peeking at the edge. */
    grid-auto-columns: min(20rem, 82vw);
    gap: 1.25rem;
    margin: 0 -1rem;
    padding: 0 1rem 0.5rem;
    list-style: none;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    /* Snap positions come from the scrollport, not the padding, so without
       this the rail loads scrolled 16px in and the first card sits against the
       edge of the screen instead of on the page's margin. */
    scroll-padding-inline: 1rem;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
}

.ls-tourcard {
    display: flex;
    scroll-snap-align: start;
    border: 1px solid var(--ls-rule);
    border-radius: var(--ls-radius-media);
    background-color: var(--ls-card);
    transition: box-shadow 200ms ease, transform 200ms ease;
}

.ls-tourcard:hover,
.ls-tourcard:focus-within {
    box-shadow: 0 12px 32px rgb(0 0 0 / 0.1);
    transform: translateY(-2px);
}

.ls-tourcard__link {
    display: flex;
    flex: 1;
    flex-direction: column;
    overflow: hidden;
    border-radius: inherit;
    color: inherit;
    text-decoration: none;
}

.ls-tourcard__media {
    display: block;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background-color: rgb(var(--c-surface-container));
}

.ls-tourcard__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 500ms ease;
}

.ls-tourcard:hover .ls-tourcard__img {
    transform: scale(1.04);
}

.ls-tourcard__body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1rem 1.125rem 1.25rem;
}

.ls-tourcard__title {
    font-family: var(--ls-font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--ls-heading);
    /* Two lines, so three cards in a row are the same height whatever the
       operator called the tour. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ls-tourcard__meta {
    font-size: 0.8125rem;
    color: var(--ls-muted);
}

/* Pushed to the bottom, so the price sits on the same line across a row of
   cards whose titles wrap differently. */
.ls-tourcard__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: auto;
    padding-top: 0.5rem;
}

.ls-tourcard__rating {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ls-heading);
}

/* The star is drawn as an outline everywhere else on the site; here it is the
   filled one that reads at 16px. */
.ls-tourcard__rating .ls-icon {
    width: 1rem;
    height: 1rem;
    fill: currentColor;
    stroke: none;
    color: var(--ls-accent);
}

.ls-tourcard__reviews {
    font-weight: 400;
    color: var(--ls-muted);
}

.ls-tourcard__price {
    font-family: var(--ls-font-display);
    font-size: 1.0625rem;
    font-weight: 800;
    color: var(--ls-accent);
    white-space: nowrap;
}

@media (min-width: 640px) {
    .ls-tours__rail {
        grid-auto-columns: min(22rem, 48vw);
    }
}

@media (min-width: 768px) {
    .ls-tours__rail {
        grid-auto-flow: row;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        margin-inline: 0;
        padding-inline: 0;
        padding-bottom: 0;
        overflow-x: visible;
        scroll-snap-type: none;
    }
}

@media (min-width: 1024px) {
    .ls-tours__rail {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* -------------------------------------------------------------- 15. RTL ---- */

[dir="rtl"] .ls-prose h2,
[dir="rtl"] .ls-prose h3,
[dir="rtl"] .ls-prose blockquote,
[dir="rtl"] .ls-prose .ls-takeaway {
    border-inline-start-width: 5px;
}

[dir="rtl"] .ls-toc__chevron {
    transform: rotate(180deg);
}

/* Directional glyphs: a crumb chevron, the back arrow and the section arrow all
   point the way the script reads, so they turn over in RTL. */
[dir="rtl"] .ls-crumbs .ls-crumbs__sep,
[dir="rtl"] .ls-article__back .ls-icon,
[dir="rtl"] .ls-article__topic-link .ls-icon,
[dir="rtl"] .ls-tourbox__more .ls-icon,
[dir="rtl"] .ls-tours__all .ls-icon {
    transform: scaleX(-1);
}

[dir="rtl"] .ls-toc[open] .ls-toc__chevron {
    transform: rotate(90deg);
}

/* A tour title carries dir="auto" so an untranslated row keeps its own line
   direction, and text-align: start then follows that direction rather than the
   page's. Alignment belongs to the card, not to the name: on an RTL page a
   Latin title pinned to the opposite edge is the one thing on the card that
   looks unfinished. */
[dir="rtl"] .ls-tourcard__title,
[dir="rtl"] .ls-tourbox__link {
    text-align: right;
}

/* The news section rules are drawn on the inline-start edge, which flips with
   the document direction on its own; only the glyphs need turning over. */
[dir="rtl"] .ls-story__faq-item[open] .ls-story__faq-q .ls-icon {
    transform: rotate(180deg);
}

[dir="rtl"] .ls-source__link .ls-icon {
    transform: scaleX(-1);
}

/* ------------------------------------------------- 16. Reduced motion ------ */

@media (prefers-reduced-motion: reduce) {
    .ls-feature__img,
    .ls-card__img,
    .ls-tourcard__img,
    .ls-card,
    .ls-tourcard,
    .ls-lead,
    .ls-lead__img,
    .ls-toc__chevron,
    .ls-story__faq-q .ls-icon {
        transition: none;
    }

    .ls-card:hover,
    .ls-card:focus-within,
    .ls-tourcard:hover,
    .ls-tourcard:focus-within,
    .ls-feature:hover .ls-feature__img,
    .ls-card:hover .ls-card__img,
    .ls-tourcard:hover .ls-tourcard__img,
    .ls-lead:hover,
    .ls-lead:focus-within,
    .ls-lead:hover .ls-lead__img {
        transform: none;
    }
}