/* The server-rendered surface, wearing the app's design system.
 *
 * Every token below is a transcription of a value that already exists in Dart,
 * and the comment beside it names the source. That is the whole point of the
 * file: the blog, the store, the certificate check and the home page are the
 * same product as the Flutter app, and a reader who lands on an article from a
 * search result and then opens the app should not feel handed to a different
 * company. Keeping the values in one place with their provenance written down
 * is what makes the next palette change a two-file job instead of a hunt.
 *
 *   colors      varztan_shared/lib/core/constants/colors.dart  (AppColors)
 *   type scale  varztan_shared/lib/core/constants/styles.dart  (AppStyles)
 *   radii etc.  varztan_shared/lib/core/constants/theme.dart   (_appDimensions)
 *
 * Two deliberate departures from the Dart, both marked again where they are
 * used further down: long-form prose is not set at AppStyles.bodyMedium's
 * 14px/700, and the print stylesheet at the end has no counterpart in the app.
 */

/* ---------------------------------------------------------------------------
 * Dana — the same four faces the apps bundle.
 *
 * One @font-face per weight rather than a variable font, because these are the
 * files that exist; a browser fetches only the weights the page actually uses,
 * so listing all four costs nothing on a page that only needs two. swap, so a
 * Persian reader gets text immediately in Tahoma rather than a blank page.
 * ------------------------------------------------------------------------ */
@font-face {
  font-family: Dana;
  src: url("../fonts/Dana-Regular.b71257bb0802.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: Dana;
  src: url("../fonts/Dana-Medium.edeeac1d963c.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: Dana;
  src: url("../fonts/Dana-Bold.6cf2fd647a75.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: Dana;
  src: url("../fonts/Dana-Black.7b994969718c.ttf") format("truetype");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------------------
 * Tokens
 * ------------------------------------------------------------------------ */
:root {
  /* AppColors — brand palette */
  --primary: #555f33;          /* AppColors.primary        Brand Olive */
  --secondary: #6ca84c;        /* AppColors.secondary      Olive Light */
  --tertiary: #c4a464;         /* AppColors.tertiary       Brand Gold */

  /* AppColors — surfaces */
  --background: #f4f6f3;       /* AppColors.background */
  --surface: #ffffff;          /* AppColors.surface */
  --surface-variant: #f7f3eb;  /* AppColors.surfaceVariant Spa Beige */
  --border: #eadfcc;           /* AppColors.border */

  /* AppColors — text */
  --text-primary: #1e2a22;     /* AppColors.textPrimary */
  --text-secondary: #57665c;   /* AppColors.textSecondary */
  --text-tertiary: #9ba9a0;    /* AppColors.textTertiary */
  --text-disabled: #c7cdc8;    /* AppColors.textDisabled */
  --on-primary: #ffffff;       /* CoreColors.onPrimary in _lightColors */

  /* AppColors — status */
  --success: #488234;
  --warning: #e5a022;
  --error: #cc5252;
  --info: #45818e;

  /* The washed-out variants, precomputed rather than mixed at use site. The
     obvious way to write these is a color-mix() of the token above, and that
     needs Chrome 111 / Safari 16.2 — 2023 — on a public page in a market with a
     long tail of older Android browsers. There is no fallback behavior worth
     having: an unsupported color-mix makes the whole declaration invalid, so a
     tile loses its border outright and a focus ring never draws at all.
     Declaring them once per theme keeps them following the palette, which a
     single static rgba() further down would not. */
  --primary-wash: rgba(85, 95, 51, 0.12);      /* primary at 12% */
  --primary-ring: rgba(85, 95, 51, 0.22);      /* primary at 22% */
  --border-soft: rgba(234, 223, 204, 0.5);     /* border at 50% */
  --success-wash: rgba(72, 130, 52, 0.15);
  --error-wash: rgba(204, 82, 82, 0.15);

  /* The footer's ground does not follow the theme, in the app or here: a
     deep navy under both, the one blue in an olive design by choice. */
  --footer-bg: #071c35;                      /* footer */
  --developer-mark: #ff6b00;                 /* developerMark */
  --footer-text: rgba(255, 255, 255, 0.7);   /* Colors.white70 */
  --footer-strong: #ffffff;
  --footer-faint: rgba(255, 255, 255, 0.54); /* Colors.white54 */
  --footer-rule: rgba(255, 255, 255, 0.24);  /* Colors.white24 */

  /* _appDimensions */
  --radius-button: 8px;   /* buttonRadius */
  --radius-input: 8px;    /* inputRadius */
  --radius-l: 16px;       /* radiusL */
  --radius-modal: 20px;   /* modalRadius / radiusXL */
  --radius-card: 24px;    /* cardRadius */
  --radius-xxl: 32px;     /* radiusXXL */
  --radius-pill: 999px;
  --button-height: 54px;  /* buttonHeight */
  --page-padding: 24px;   /* pagePadding */

  /* AppStyles, in the same order it declares them. Flutter's logical pixels
     and CSS px are the same unit at the default zoom, so these transcribe
     directly. */
  --fs-display-large: 60px;   --fw-display-large: 300;   --ls-display-large: 0.5px;
  --fs-display-medium: 60px;  --fw-display-medium: 300;  --ls-display-medium: 0.5px;
  --fs-display-small: 34px;   --fw-display-small: 400;   --ls-display-small: 0;
  --fs-headline-medium: 28px; --fw-headline-medium: 400; --ls-headline-medium: 0.25px;
  --fs-headline-small: 22px;  --fw-headline-small: 400;  --ls-headline-small: 0;
  --fs-title-large: 20px;     --fw-title-large: 500;     --ls-title-large: 0.15px;
  --fs-title-medium: 16px;    --fw-title-medium: 400;    --ls-title-medium: 0.15px;
  --fs-title-small: 14px;     --fw-title-small: 300;     --ls-title-small: 0.5px;
  --fs-body-large: 16px;      --fw-body-large: 700;
  --fs-body-medium: 14px;     --fw-body-medium: 700;     --ls-body-medium: 0.5px;
  --fs-body-small: 12px;      --fw-body-small: 500;      --ls-body-small: 0.4px;
  --fs-label-large: 18px;     --fw-label-large: 500;     --ls-label-large: 0.5px;
  --fs-label-small: 10px;     --fw-label-small: 500;     --ls-label-small: 0.5px;
  --fs-header: 22px;          --fw-header: 900;          --ls-header: 0.5px;

  /* Long-form prose is the one place this page has no app equivalent to copy.
     The app's ContentViewer does set paragraphs at AppStyles.bodyMedium — 14px
     at weight 700 — but it renders short blocks of site copy, not a 2,000-word
     article. Holding an entire blog post at that size and weight would make the
     surface the blog exists for harder to read than the one it competes with,
     so prose gets a reading size and a medium weight. Everything else on the
     page — chrome, cards, labels, headings — is the app's scale verbatim. */
  --fs-prose: 16px;
  --fw-prose: 500;
  --lh-prose: 2;

  --font-fa: Dana, Vazirmatn, Tahoma, system-ui, sans-serif;

  /* Elevation. Transcribed from the BoxShadows in the home widgets: the action
     tiles use black at 2% / blur 8 / y+4, the post cards black at 3% /
     blur 10 / y+4. */
  --shadow-tile: 0 4px 8px rgba(0, 0, 0, 0.02);
  --shadow-card: 0 4px 10px rgba(0, 0, 0, 0.03);

  --content-width: 1200px;   /* HomeScreenDesktop's largeDesktop width */
  --reading-width: 760px;    /* an article is not read at 1200px */
}

/* The dark palette, reached two ways.
 *
 * A reader who picked Night gets it outright; a reader who picked nothing — or
 * picked "match my device" — gets it when their device says so, which is the
 * behaviour this file had before there was a switch at all. Picking Day is the
 * only thing that overrides the device, and it has to, or the switch would be
 * a switch with one position.
 *
 * The two blocks are identical on purpose and must stay that way.
 * ``tests/test_design_tokens.py`` compares them declaration by declaration, so
 * a value changed in one and not the other fails the suite rather than leaving
 * half the readers on a stale colour. Neither CSS variables nor a media query
 * can express "these two selectors, one of them conditional" in a single rule,
 * and nesting is newer than the browsers this page still has to serve. */
:root[data-theme="dark"] {
  --primary: #90a980;          /* AppColors.primaryDark  Sage Green */
  --tertiary: #c4a464;         /* AppColors.tertiaryDark */
  --background: #121814;       /* AppColors.backgroundDark */
  --surface: #242c27;          /* AppColors.surfaceDark */
  --surface-variant: #2d3630;  /* AppColors.surfaceVariantDark */
  --border: #323b35;           /* AppColors.borderDark */
  --text-primary: #e2e8e4;     /* AppColors.textPrimaryDark */
  --text-secondary: #9ba9a0;   /* AppColors.textSecondaryDark */
  --text-tertiary: #9ba9a0;
  --text-disabled: #6e7772;    /* AppColors.textDisabledDark */
  --on-primary: #000000;       /* CoreColors.onPrimary in _darkColors */

  --primary-wash: rgba(144, 169, 128, 0.16);
  --primary-ring: rgba(144, 169, 128, 0.28);
  --border-soft: rgba(50, 59, 53, 0.6);

  --shadow-tile: 0 4px 8px rgba(0, 0, 0, 0.35);
  --shadow-card: 0 4px 10px rgba(0, 0, 0, 0.4);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    --primary: #90a980;          /* AppColors.primaryDark  Sage Green */
    --tertiary: #c4a464;         /* AppColors.tertiaryDark */
    --background: #121814;       /* AppColors.backgroundDark */
    --surface: #242c27;          /* AppColors.surfaceDark */
    --surface-variant: #2d3630;  /* AppColors.surfaceVariantDark */
    --border: #323b35;           /* AppColors.borderDark */
    --text-primary: #e2e8e4;     /* AppColors.textPrimaryDark */
    --text-secondary: #9ba9a0;   /* AppColors.textSecondaryDark */
    --text-tertiary: #9ba9a0;
    --text-disabled: #6e7772;    /* AppColors.textDisabledDark */
    --on-primary: #000000;       /* CoreColors.onPrimary in _darkColors */

    --primary-wash: rgba(144, 169, 128, 0.16);
    --primary-ring: rgba(144, 169, 128, 0.28);
    --border-soft: rgba(50, 59, 53, 0.6);

    --shadow-tile: 0 4px 8px rgba(0, 0, 0, 0.35);
    --shadow-card: 0 4px 10px rgba(0, 0, 0, 0.4);
  }
}

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

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

body {
  margin: 0;
  background: var(--background);
  color: var(--text-primary);
  font-family: var(--font-fa);
  font-size: var(--fs-body-medium);
  font-weight: var(--fw-body-medium);
  letter-spacing: var(--ls-body-medium);
  line-height: 1.8;
  /* Persian numerals in a Persian page, Latin in the other two: the app renders
     whatever the locale gives it and so should this. */
  font-variant-numeric: proportional-nums;
}

a {
  color: var(--primary);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

a:hover {
  color: var(--secondary);
}

img,
video {
  max-width: 100%;
  height: auto;
}

/* An icon takes the color of the text around it. That is what the sprite in
   `partials/icons.html` is drawn for — its symbols carry no fill of their own,
   so this reaches them through `<use>` and an icon follows the theme the way an
   `Icon()` follows `Theme.of(context)`.

   Without it every icon on the site rendered in SVG's default black: nearly
   invisible on the dark theme's surfaces, and wrong in the light one too, where
   the home page's tiles set `color: var(--primary)` around an icon that stayed
   black regardless.

   On the element and never on its descendants. `partials/theme_toggle.html`
   draws a sun as strokes over `fill="none"`, and a rule reaching inside would
   fill the rays in — a child's own attribute beats what it inherits, but it
   does not beat a rule that selects the child. */
svg {
  fill: currentColor;
}

hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 32px 0;
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--radius-button);
}

h1,
h2,
h3,
h4 {
  color: var(--text-primary);
  line-height: 1.4;
}

h1 {
  font-size: var(--fs-headline-medium);
  font-weight: 700;
  letter-spacing: var(--ls-headline-medium);
  margin: 0.2em 0 0.4em;
}

h2 {
  font-size: var(--fs-headline-small);
  font-weight: 700;
  margin: 1.8em 0 0.5em;
}

h3 {
  font-size: var(--fs-title-large);
  font-weight: var(--fw-title-large);
  letter-spacing: var(--ls-title-large);
  margin: 1.6em 0 0.4em;
}

/* The one type ramp that grows with the viewport. The app gets a fixed
   headline because a phone is a phone; a page that may be opened at 1600px
   should not hold its title at 28px. */
@media (min-width: 900px) {
  h1 {
    font-size: var(--fs-display-small);
    letter-spacing: var(--ls-display-small);
  }
}

/* ---------------------------------------------------------------------------
 * Layout
 * ------------------------------------------------------------------------ */
.wrap {
  width: 100%;
  max-width: var(--reading-width);
  margin-inline: auto;
  padding-inline: var(--page-padding);
}

/* HomeScreenDesktop lays its sections out at largeDesktop: 1200. */
.wrap--wide {
  max-width: var(--content-width);
}

main.wrap {
  padding-bottom: 80px;
}

.stack > * + * {
  margin-block-start: 24px;
}

/* ---------------------------------------------------------------------------
 * Masthead — core/widgets/web/header.dart
 *
 * The app's HeaderWidget is 72px tall, constrained to 1400, with the wordmark
 * at the start, pill-shaped nav buttons in the middle and a bordered account
 * button at the end. The account button is the one thing that cannot cross
 * over: these pages have no session, so its place is taken by the language
 * switcher, which the app renders inside its settings sheet instead.
 * ------------------------------------------------------------------------ */
.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--background);
  border-bottom: 1px solid var(--border);
}

.masthead__inner {
  min-height: 72px;
  max-width: 1400px;
  margin-inline: auto;
  padding: 10px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.masthead__brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--text-primary);
  font-size: var(--fs-header);
  font-weight: var(--fw-header);
  letter-spacing: var(--ls-header);
}

/* 48px, as the app's top bar draws it (hoverable_logo.dart). */
.masthead__brand img {
  height: 48px;
  width: 48px;
}

.masthead__nav {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}

.masthead__nav a {
  padding: 8px 16px;
  border-radius: var(--radius-button);
  text-decoration: none;
  color: var(--text-secondary);
  font-size: var(--fs-title-small);
  font-weight: 400;
}

.masthead__nav a:hover {
  background: var(--surface-variant);
  color: var(--text-primary);
}

/* backgroundColor: primary.withAlpha(30) — 30/255 ≈ 12%. */
.masthead__nav a[aria-current="page"] {
  color: var(--primary);
  background: var(--primary-wash);
  font-weight: 700;
}

/* ---------------------------------------------------------------------------
 * Language switcher
 *
 * A language with no translation behind it is still offered — a reader may ask
 * for it and get the original with a note — but it is dimmed, because the one
 * thing this control must not do is promise a translation that is not there.
 * ------------------------------------------------------------------------ */
.langs {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  letter-spacing: var(--ls-body-small);
}

.langs a,
.langs span {
  text-decoration: none;
  color: var(--text-secondary);
}

.langs a:hover {
  color: var(--primary);
}

.langs .current {
  color: var(--text-primary);
  font-weight: 700;
}

.langs .untranslated {
  opacity: 0.55;
}

.account-link {
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  letter-spacing: var(--ls-body-small);
}

.account-link a {
  text-decoration: none;
  color: var(--text-secondary);
}

.account-link a:hover {
  color: var(--primary);
}

/* ---------------------------------------------------------------------------
 * The appearance switch
 *
 * Three states, not a two-way flip: day, night, and "match my device", which is
 * the default and is the absence of an override rather than a third palette.
 * It sits beside the language switcher because it is the same kind of control —
 * how to read the page, not where to go.
 *
 * A segmented group of submit buttons, because it is a form: the server stamps
 * the answer onto <html> and there is no script to race the first paint. The
 * pressed state is a background and a weight, never colour alone.
 * ------------------------------------------------------------------------ */
.theme-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
}

/* The group has an accessible name from this; sighted readers get it from the
   shapes, which is why it is hidden rather than removed. */
.theme-toggle__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.theme-toggle__group {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 2px;
  background: var(--surface);
}

.theme-toggle__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 32px;
  min-height: 32px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-body-small);
  cursor: pointer;
}

.theme-toggle__option:hover {
  color: var(--primary);
}

.theme-toggle__option.is-current {
  background: var(--primary-wash);
  color: var(--primary);
  font-weight: 700;
}

.theme-toggle__option .icon {
  width: 18px;
  height: 18px;
  flex: none;
}

/* In the masthead the shapes carry it; the words stay for a screen reader. */
.theme-toggle__text {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* On the account page there is room to say what each one is. */
.theme-toggle--panel {
  display: block;
}

.theme-toggle--panel .theme-toggle__group {
  width: 100%;
}

.theme-toggle--panel .theme-toggle__option {
  flex: 1;
  min-height: 40px;
}

.theme-toggle--panel .theme-toggle__text {
  position: static;
  width: auto;
  height: auto;
  clip-path: none;
}

/* ---------------------------------------------------------------------------
 * Signing in
 *
 * One narrow column. There is nothing to read on these pages and nothing to
 * scan — the whole job is one field and one button — so the reading width the
 * rest of the site uses is too wide to aim at.
 * ------------------------------------------------------------------------ */
.wrap--narrow {
  max-width: 420px;
}

.auth h1 {
  margin-top: 0;
}

.auth .lead {
  color: var(--text-secondary);
}

.auth__note {
  margin-top: 20px;
  font-size: var(--fs-body-small);
  color: var(--text-secondary);
}

.field {
  margin-bottom: 16px;
}

.field label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--fs-body-small);
  font-weight: 700;
  color: var(--text-secondary);
}

.field input {
  width: 100%;
  min-height: var(--button-height);
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  background: var(--surface);
  color: var(--text-primary);
  font: inherit;
  font-size: var(--fs-title-medium);
}

.field input:focus-visible {
  outline: 2px solid var(--primary-ring);
  outline-offset: 1px;
  border-color: var(--primary);
}

/* An error is a colour *and* a border *and* words. Colour alone fails the
   reader this most affects. */
.field-error,
.form-error {
  margin: 6px 0 0;
  color: var(--error);
  font-size: var(--fs-body-small);
}

.form-error {
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--error);
  border-radius: var(--radius-input);
  background: var(--error-wash);
}

.form-error p {
  margin: 0;
}

.btn--block {
  width: 100%;
}

/* Sized against the label rather than fixed, so the mark keeps its weight
   beside Dana as it does beside a Latin fallback. Its color comes from the
   base rule, which is to say from the button. */
.btn svg {
  width: 1.15em;
  height: 1.15em;
  flex: none;
}

/* The divider between the two ways in, the way the app draws it: a rule across
   the column with the word sitting in the middle of it. Built from a flex row
   rather than a border and a negative margin, so it is correct in RTL without
   a second rule. */
.auth__or {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  color: var(--text-secondary);
  font-size: var(--fs-body-small);
}

.auth__or::before,
.auth__or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.btn--quiet {
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border);
  min-height: 40px;
  font-size: var(--fs-body-small);
}

.btn--quiet:hover {
  background: var(--surface-variant);
  color: var(--text-primary);
}

/* ---------------------------------------------------------------------------
 * Buttons — CoreThemeFactory's buttonHeight 54 / buttonRadius 8
 * ------------------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--button-height);
  padding: 0 24px;
  border: 0;
  border-radius: var(--radius-button);
  background: var(--primary);
  color: var(--on-primary);
  font: inherit;
  font-size: var(--fs-title-medium);
  font-weight: 700;
  letter-spacing: var(--ls-title-medium);
  text-decoration: none;
  cursor: pointer;
}

.btn:hover {
  background: var(--secondary);
  color: var(--on-primary);
}

.btn--ghost {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border);
}

.btn--ghost:hover {
  background: var(--surface-variant);
  color: var(--text-primary);
}

.btn--small {
  min-height: 36px;
  padding: 0 18px;
  font-size: var(--fs-title-small);
}

/* ---------------------------------------------------------------------------
 * Chips — the pill row the app draws for categories and tags
 * ------------------------------------------------------------------------ */
.tags,
.chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin: 24px 0;
  padding: 0;
  list-style: none;
}

.tags a,
.chips a {
  display: inline-block;
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  letter-spacing: var(--ls-body-small);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 5px 14px;
  text-decoration: none;
  color: var(--text-secondary);
  background: var(--surface);
}

.tags a:hover,
.chips a:hover {
  border-color: var(--primary);
  color: var(--primary);
}

/* ---------------------------------------------------------------------------
 * Cards
 *
 * HomePostItem: cardColor ground, 20px corners, the cover filling the top with
 * matching corners, then 12px of padding around a bold title and a two-line
 * excerpt in the hint color.
 * ------------------------------------------------------------------------ */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-modal);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.card__media {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--surface-variant);
}

.card__body {
  padding: 14px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
}

.card__body > h2,
.card__body > h3 {
  margin: 0;
  font-size: var(--fs-title-small);
  font-weight: 700;
  letter-spacing: var(--ls-title-small);
  line-height: 1.6;
}

.card__body > h2 a,
.card__body > h3 a {
  color: var(--text-primary);
  text-decoration: none;
}

.card__body > h2 a:hover,
.card__body > h3 a:hover {
  color: var(--primary);
}

.card__excerpt {
  margin: 0;
  color: var(--text-tertiary);
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  letter-spacing: var(--ls-body-small);
  line-height: 1.7;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The blog and store index pages listed items as hairline-separated rows before
   the app's card had anywhere to land. This keeps that list shape available. */
.card--row {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
  padding: 22px 0;
  overflow: visible;
}

.card--row h2 {
  margin: 0 0 6px;
  font-size: var(--fs-title-large);
  font-weight: 700;
}

.card--row h2 a {
  text-decoration: none;
  color: var(--text-primary);
}

.card--row h2 a:hover {
  color: var(--primary);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
  margin: 24px 0;
}

/* ---------------------------------------------------------------------------
 * Breadcrumbs, meta lines, pagers, notices
 * ------------------------------------------------------------------------ */
.crumbs {
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  color: var(--text-tertiary);
  margin: 24px 0 8px;
}

.crumbs a {
  color: var(--text-tertiary);
}

.crumbs a:hover {
  color: var(--primary);
}

.meta {
  color: var(--text-tertiary);
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  letter-spacing: var(--ls-body-small);
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: center;
}

article > .meta {
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
}

.pager {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: center;
  margin-top: 40px;
  font-size: var(--fs-title-small);
}

.fallback {
  border: 1px solid var(--border);
  background: var(--surface-variant);
  border-radius: var(--radius-l);
  padding: 12px 16px;
  color: var(--text-secondary);
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
  margin: 20px 0;
}

/* What the last view had to say, carried across the redirect it ended with.
 *
 * The colored edge is `border-inline-start`, so it sits on the right in
 * Persian and Arabic and on the left in English without a second rule. A
 * `border-left` here would put the mark on the wrong side of three quarters of
 * this site's pages. */
.notices {
  display: grid;
  gap: 10px;
  margin: 0 0 24px;
}

.notice {
  margin: 0;
  padding: 12px 16px;
  border: 1px solid var(--border);
  border-inline-start: 4px solid var(--text-tertiary);
  border-radius: var(--radius-l);
  background: var(--surface-variant);
  color: var(--text-primary);
}

.notice--success {
  border-inline-start-color: var(--success);
  background: var(--success-wash);
}

.notice--error {
  border-inline-start-color: var(--error);
  background: var(--error-wash);
}

.notice--warning {
  border-inline-start-color: var(--warning);
}

.notice--info,
.notice--debug {
  border-inline-start-color: var(--info);
}

.muted {
  color: var(--text-tertiary);
}

/* ---------------------------------------------------------------------------
 * Long-form prose — see the --fs-prose note in the tokens block
 * ------------------------------------------------------------------------ */
.prose {
  font-size: var(--fs-prose);
  font-weight: var(--fw-prose);
  line-height: var(--lh-prose);
  letter-spacing: 0;
}

.prose > * + * {
  margin-block-start: 1.1em;
}

.prose img,
.prose figure img,
.prose video {
  border-radius: var(--radius-l);
}

.prose blockquote {
  margin-inline: 0;
  padding-inline-start: 18px;
  border-inline-start: 3px solid var(--tertiary);
  color: var(--text-secondary);
}

.prose code {
  background: var(--surface-variant);
  border-radius: 6px;
  padding: 1px 6px;
  font-size: 0.9em;
}

.prose pre {
  background: var(--surface-variant);
  border: 1px solid var(--border);
  border-radius: var(--radius-l);
  padding: 14px 16px;
  overflow-x: auto;
}

.cover {
  width: 100%;
  height: auto;
  border-radius: var(--radius-modal);
  margin: 24px 0;
}

/* ---------------------------------------------------------------------------
 * FAQ — features/site/presentation/widgets/faq.dart, as <details>
 *
 * A native disclosure rather than scripted panels: the answers have to be in
 * the markup for the FAQPage JSON-LD to be honest, and a crawler that finds
 * text hidden behind JavaScript it did not run treats it as absent.
 * ------------------------------------------------------------------------ */
.faq {
  margin: 24px 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.faq details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-l);
  padding: 4px 18px;
}

.faq details[open] {
  border-color: var(--primary);
}

.faq summary {
  cursor: pointer;
  list-style: none;
  padding: 14px 0;
  font-size: var(--fs-title-medium);
  font-weight: 700;
  letter-spacing: var(--ls-title-medium);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "+";
  color: var(--primary);
  font-size: var(--fs-title-large);
  font-weight: 700;
  line-height: 1;
}

.faq details[open] summary::after {
  content: "−";
}

.faq details > :not(summary) {
  margin: 0 0 16px;
  color: var(--text-secondary);
  font-size: var(--fs-prose);
  font-weight: var(--fw-prose);
  line-height: var(--lh-prose);
}

.related {
  margin-top: 48px;
  border-top: 2px solid var(--primary);
  padding-top: 20px;
}

/* ---------------------------------------------------------------------------
 * Store — what a price, a stock state and a comment thread need
 * ------------------------------------------------------------------------ */
.price {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin: 18px 0;
}

.price .now {
  font-size: var(--fs-title-large);
  font-weight: 700;
  color: var(--text-primary);
}

.price .was {
  color: var(--text-tertiary);
  text-decoration: line-through;
  font-size: var(--fs-body-medium);
}

/* Discounts are entered in Toman and the percentage is computed for display,
   so this badge always carries a derived number. */
.price .off {
  background: var(--tertiary);
  color: #ffffff;
  border-radius: var(--radius-pill);
  padding: 2px 10px;
  font-size: var(--fs-body-small);
  font-weight: 700;
}

.stock {
  font-size: var(--fs-body-small);
  font-weight: 700;
}

.stock.in {
  color: var(--success);
}

.stock.out {
  color: var(--error);
}

.stars {
  letter-spacing: 2px;
  color: var(--tertiary);
}

.gallery {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin: 20px 0;
}

.gallery img {
  width: 120px;
  height: 120px;
  object-fit: cover;
  border-radius: var(--radius-l);
  border: 1px solid var(--border);
}

.features {
  padding-inline-start: 1.2em;
  color: var(--text-secondary);
}

.comment {
  border-bottom: 1px solid var(--border);
  padding: 16px 0;
}

.comment .who {
  font-weight: 700;
}

.comment .badge {
  font-size: var(--fs-body-small);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 2px 8px;
  color: var(--text-tertiary);
  margin-inline-start: 8px;
}

.comment .reply {
  margin-inline-start: 24px;
  border-inline-start: 2px solid var(--border);
  padding-inline-start: 14px;
}

/* ---------------------------------------------------------------------------
 * Panels, badges and forms — the certificate check
 *
 * A panel is a card with padding and no media, which is what the app's own
 * cards are away from the home feed: cardRadius 24 on the surface color with a
 * hairline. It is a separate class from .card because .card clips its children
 * to hold a cover image flush against its corners.
 * ------------------------------------------------------------------------ */
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 24px;
}

.badge {
  display: inline-block;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  font-weight: 700;
  font-size: var(--fs-title-small);
  margin-bottom: 16px;
}

.badge.ok {
  background: var(--success-wash);
  color: var(--success);
}

.badge.bad {
  background: var(--error-wash);
  color: var(--error);
}

.facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px 18px;
  margin: 0;
}

.facts dt {
  color: var(--text-tertiary);
  font-size: var(--fs-body-small);
  font-weight: var(--fw-body-small);
}

.facts dd {
  margin: 0;
  font-weight: 700;
}

.panel__actions {
  margin-top: 22px;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

/* inputRadius 8 and buttonHeight 54, the same as the app's fields. */
.form-row {
  display: flex;
  gap: 10px;
  margin-top: 18px;
  flex-wrap: wrap;
}

.field {
  flex: 1 1 220px;
  min-height: var(--button-height);
  padding: 0 14px;
  border-radius: var(--radius-input);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-primary);
  font: inherit;
  font-size: var(--fs-title-medium);
}

.field:focus {
  border-color: var(--primary);
  outline: none;
  box-shadow: 0 0 0 3px var(--primary-ring);
}

/* A verification code is read off paper and typed, so it is spaced out and
   case-folded on the way in. */
.field--code {
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------------------
 * Home — features/home/presentation/pages/home_screen_desktop.dart
 * ------------------------------------------------------------------------ */

/* HeroWithSearchSection: a cover-fit photograph with the branding sitting near
   the bottom in white, over a shadow rather than a scrim. The scrim here is a
   gradient instead, because a text-shadow that survives one photograph does not
   survive the next one somebody uploads. */
.hero {
  position: relative;
  min-height: 340px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: var(--primary);
  overflow: hidden;
}

.hero__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.55) 0%,
    rgba(0, 0, 0, 0.15) 45%,
    rgba(0, 0, 0, 0.05) 100%
  );
}

.hero__content {
  position: relative;
  z-index: 1;
  text-align: center;
  color: #ffffff;
  padding: 0 24px 40px;
  max-width: 760px;
}

.hero__title {
  margin: 0;
  color: #ffffff;
  font-size: var(--fs-headline-medium);
  font-weight: 700;
  letter-spacing: var(--ls-headline-medium);
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
}

.hero__subtitle {
  margin: 12px 0 0;
  color: rgba(255, 255, 255, 0.9);
  font-size: var(--fs-title-medium);
  font-weight: var(--fw-title-medium);
  letter-spacing: var(--ls-title-medium);
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
}

/* The taglines the mobile HomeHeader fades in under the wordmark. They are the
   brand's own words, so they belong on the page a search result lands on. */
.hero__taglines {
  margin: 18px 0 0;
  color: #ffffff;
  font-size: var(--fs-body-small);
  font-weight: 700;
  letter-spacing: var(--ls-body-small);
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
}

@media (min-width: 700px) {
  .hero {
    min-height: 420px;
  }
  .hero__content {
    padding-bottom: 60px;
  }
}

@media (min-width: 1100px) {
  .hero {
    min-height: 520px;
  }
  .hero__content {
    padding-bottom: 80px;
  }
  .hero__title {
    font-size: var(--fs-display-small);
  }
}

/* HomeActionGrid: four tiles, 12px gutters, a surface square with a 16px
   radius and a hairline holding the icon, and the label centered underneath.
   Four across on a phone in the app; here it wraps rather than squeezing,
   because a desktop viewport has room and a 320px one does not. */
.actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin: 40px 0;
  padding: 0;
  list-style: none;
}

.action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
  text-decoration: none;
  color: var(--text-primary);
}

.action__icon {
  /* ``align-self`` rather than ``width: 100%``: the tile is a column flex item
     under ``align-items: center``, and "fill the cross axis" is what is
     actually meant. A percentage width has to be resolved against a container
     whose width is not definite at that point, which is the sort of thing
     engines disagree about — this says it directly instead. */
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px 12px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-tile);
  color: var(--primary);
}

.action__icon svg {
  width: 28px;
  height: 28px;
  display: block;
}

.action:hover .action__icon {
  border-color: var(--primary);
}

.action__label {
  font-size: var(--fs-body-small);
  font-weight: 600;
  letter-spacing: var(--ls-body-small);
  line-height: 1.5;
}

/* HomeSectionHeader: the title at titleMedium/bold with a "view all" link
   pushed to the far end. */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin: 48px 0 12px;
}

.section-head h2 {
  margin: 0;
  font-size: var(--fs-title-large);
  font-weight: 700;
  letter-spacing: var(--ls-title-large);
}

.section-head a {
  font-size: var(--fs-body-small);
  font-weight: 700;
  color: var(--primary);
  text-decoration: none;
  white-space: nowrap;
}

.section-head a:hover {
  text-decoration: underline;
}

/* BannersSection: two across on desktop, one below it, at a 4:1 aspect with
   12px gutters and 12px corners. */
.banners {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin: 24px 0;
}

@media (min-width: 900px) {
  .banners {
    grid-template-columns: 1fr 1fr;
  }
}

.banner {
  display: block;
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface-variant);
}

.banner img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 1;
  object-fit: cover;
}

/* The category strips. The app scrolls these horizontally on a phone and grids
   them on a desktop; one grid that collapses to a scroller does both. */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(260px, 1fr);
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: 8px;
  /* The scrollbar is the only affordance saying there is more to the side. */
  scrollbar-color: var(--border) transparent;
}

.rail > * {
  scroll-snap-align: start;
}

@media (min-width: 900px) {
  .rail {
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    overflow-x: visible;
  }
}

/* The FAQ and its illustration, 3:1 the way the desktop home lays them out. */
.faq-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  align-items: center;
}

@media (min-width: 1100px) {
  .faq-layout {
    grid-template-columns: 3fr 1fr;
  }
}

.faq-layout__art {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--primary);
  opacity: 0.55;
}

.faq-layout__art svg {
  width: 100%;
  max-width: 200px;
  height: auto;
}

/* The educational blurb the mobile home closes on, set as a justified block in
   the hint color the way _buildFooterSection does. */
.blurb {
  margin: 48px 0 0;
  color: var(--text-secondary);
  font-size: var(--fs-prose);
  font-weight: var(--fw-prose);
  line-height: var(--lh-prose);
  text-align: justify;
}

/* ---------------------------------------------------------------------------
 * Footer — core/widgets/footer.dart
 *
 * Four columns above 760px and stacked below it, which is the same breakpoint
 * the Dart LayoutBuilder uses.
 * ------------------------------------------------------------------------ */
.site-footer {
  background: var(--footer-bg);
  color: var(--footer-text);
  margin-top: 80px;
  padding: 40px 24px;
  font-size: var(--fs-title-small);
  font-weight: 400;
  letter-spacing: var(--ls-title-small);
}

.site-footer__inner {
  max-width: var(--content-width);
  margin-inline: auto;
}

.site-footer__columns {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

@media (min-width: 760px) {
  .site-footer__columns {
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
  }
}

.site-footer h2 {
  margin: 0 0 10px;
  color: var(--footer-strong);
  font-size: var(--fs-title-small);
  font-weight: 700;
}

.site-footer .brand {
  color: var(--footer-strong);
  font-size: var(--fs-header);
  font-weight: 700;
  letter-spacing: var(--ls-header);
  margin: 0 0 12px;
}

.site-footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-footer li {
  padding: 4px 0;
}

.site-footer a {
  color: var(--footer-text);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--footer-strong);
  text-decoration: underline;
}

.site-footer .contact {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  padding: 4px 0;
}

.site-footer .contact svg {
  width: 18px;
  height: 18px;
  flex: none;
  margin-top: 5px;
}

.site-footer .socials {
  display: flex;
  gap: 20px;
  margin-top: 16px;
}

.site-footer .socials a {
  display: inline-flex;
}

.site-footer .socials svg {
  width: 20px;
  height: 20px;
}

.site-footer__seal {
  display: flex;
  justify-content: center;
  margin: 48px 0 32px;
}

.site-footer__seal img {
  background: #ffffff;
  border-radius: var(--radius-l);
  padding: 6px;
}

.site-footer__base {
  border-top: 1px solid var(--footer-rule);
  padding-top: 24px;
  text-align: center;
}

/* The developer credit is set the way ipdalin.ir sets its own name: the first
   word in the footer's ink, the second in the studio's orange, no underline. */
.site-footer__base a,
.site-footer__base a:hover {
  color: var(--footer-strong);
  font-weight: 700;
  text-decoration: none;
}

.site-footer__developer-mark {
  color: var(--developer-mark);
}

.site-footer__copyright {
  margin: 16px 0 0;
  color: var(--footer-faint);
  font-size: var(--fs-body-small);
}

/* ---------------------------------------------------------------------------
 * Skip link — the masthead nav is long enough to be worth stepping over, and a
 * sticky masthead makes keyboard navigation worse without one.
 * ------------------------------------------------------------------------ */
.skip-link {
  position: absolute;
  inset-inline-start: -9999px;
  top: 0;
  z-index: 50;
  background: var(--primary);
  color: var(--on-primary);
  padding: 10px 18px;
  border-radius: 0 0 var(--radius-button) var(--radius-button);
}

.skip-link:focus {
  inset-inline-start: 0;
  color: var(--on-primary);
}

/* A label that only assistive technology reads. The social icons carry no text
   of their own, and a title attribute is not reliably announced. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
 * Catalog pages — academy, workshops, bookings
 *
 * The four sections that became crawlable after the blog and the store reuse
 * .card, .grid, .panel, .facts, .price and .badge unchanged; what is here is
 * the handful of shapes those did not already cover. A syllabus, a session
 * timetable and a roster of people are lists with a title on one side and a
 * time or a role on the other, so they are one pattern written once rather
 * than three that drift.
 * ------------------------------------------------------------------------ */

/* The sentence under an h1 that the app sets in AppStyles.titleMedium: bigger
   than body copy, lighter than a heading, and never the start of the prose. */
.lead {
  font-size: var(--fs-title-large);
  font-weight: 400;
  color: var(--text-secondary);
  margin: 0 0 24px;
  max-width: var(--reading-width);
}

.lessons,
.schedule {
  list-style: none;
  padding: 0;
  margin: 0 0 32px;
  border: 1px solid var(--border);
  border-radius: var(--radius-l);
  background: var(--surface);
  overflow: hidden;
}

.lessons > li,
.schedule > li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border-soft);
}

.lessons > li:last-child,
.schedule > li:last-child {
  border-bottom: 0;
}

.lessons__title,
.schedule__title {
  font-weight: 700;
  flex: 1 1 auto;
}

/* A running time and a clock time are both read left to right in Persian and
   Arabic, and both are tabular — the column only lines up if the glyphs do. */
.lessons__time,
.schedule__time {
  color: var(--text-tertiary);
  font-size: var(--fs-body-small);
  font-variant-numeric: tabular-nums;
}

/* .badge carries a 16px bottom margin for the standalone use on the
   certificate page; inside a row it has to sit on the same baseline. */
.lessons .badge,
.schedule .badge {
  margin-bottom: 0;
  font-size: var(--fs-label-small);
  padding: 3px 10px;
}

/* Instructors and therapists: a face, a name, and what they are qualified in.
   The app draws these as a horizontal rail; on a page that has to reflow to a
   phone they are a grid that collapses to one column on its own. */
.people {
  list-style: none;
  padding: 0;
  margin: 0 0 32px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 20px;
}

.people > li {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}

.people img {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-pill);
  object-fit: cover;
  flex: none;
}

.people h3 {
  margin: 0 0 4px;
  font-size: var(--fs-title-medium);
}

/* ---------------------------------------------------------------------------
 * The "open in the app" offer
 *
 * Slim, in the flow of the page, and above the fold only in the sense that the
 * masthead is. It is deliberately not fixed, not an overlay and not full-width
 * dark: an interstitial covering content on mobile is penalized by Google, and
 * these pages exist to rank. See templates/partials/app_offer.html.
 * ------------------------------------------------------------------------ */
.app-offer {
  display: flex;
  align-items: center;
  /* Wraps rather than crushes: on the narrowest phones the button drops to a
     second line, which is still two lines rather than five. */
  flex-wrap: wrap;
  gap: 12px 12px;
  max-width: var(--content-width);
  margin-inline: auto;
  margin-block: 12px 0;
  padding: 10px var(--page-padding);
  background: var(--surface-variant);
  border: 1px solid var(--border);
  border-radius: var(--radius-l);
  font-size: var(--fs-body-small);
}

.app-offer[hidden] {
  display: none;
}

.app-offer__text {
  margin: 0;
  /* ``min-width: 0`` because a flex item's default minimum is its content
     width, and without it a long Persian phrase squeezes itself into a narrow
     column rather than wrapping — which is what a 360px phone gives this bar. */
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text-secondary);
}

.app-offer__open {
  flex: none;
  padding: 6px 16px;
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--on-primary);
  font-weight: 700;
  text-decoration: none;
}

.app-offer__open:hover {
  background: var(--secondary);
  color: var(--on-primary);
}

.app-offer__close {
  flex: none;
  border: 0;
  background: none;
  color: var(--text-tertiary);
  font-size: 20px;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
  font-family: inherit;
}

.app-offer__close:hover {
  color: var(--text-primary);
}

/* ---------------------------------------------------------------------------
 * Print
 *
 * No app counterpart: an article printed or saved to PDF from a browser should
 * not carry a sticky masthead, a four-column footer or a dark ground.
 * ------------------------------------------------------------------------ */
@media print {
  .masthead,
  .site-footer,
  .skip-link,
  .pager,
  .app-offer,
  .langs {
    display: none !important;
  }

  body {
    background: #ffffff;
    color: #000000;
  }

  .wrap {
    max-width: none;
    padding: 0;
  }

  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
    color: #555555;
  }
}

/* ---------------------------------------------------------------------------
 * Motion
 * ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
