/**
 * Shell-iT — Proof Mode component library.
 * Every measurement here comes from the approved design system.
 */

/* ============================================================== BUTTONS */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-block-size: 3rem;              /* 48px regular */
  min-inline-size: 8.25rem;          /* 132px — never a fixed width, so Greek fits */
  max-inline-size: 100%;
  padding-inline: 1.25rem;           /* 20px */
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-text);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard),
              color var(--motion-fast) var(--ease-standard),
              transform var(--motion-fast) var(--ease-standard);
}

.button--small { min-block-size: 2.75rem; padding-inline: var(--space-2); font-size: 0.875rem; }
.button--large { min-block-size: 3.5rem; min-inline-size: 10rem; padding-inline: var(--space-3); }

.button--primary {
  background-color: var(--control-bg);
  border-color: var(--control-bg);
  color: var(--color-text-inverse);   /* 4.94:1 — AA */
}

.button--primary:hover {
  background-color: var(--control-bg-hover);
  border-color: var(--control-bg-hover);
  color: var(--color-text-inverse);
}

.button--primary:active { background-color: var(--control-bg-active); border-color: var(--control-bg-active); transform: translateY(1px); }

.button--secondary {
  background-color: transparent;
  border-color: var(--color-border-strong);
  color: var(--color-text-primary);
}

.button--secondary:hover { background-color: var(--color-surface-sunken); border-color: var(--color-brand-slate); color: var(--color-text-primary); }
.button--secondary:active { transform: translateY(1px); }

.button--ghost { background: none; border-color: transparent; color: var(--color-link); min-inline-size: 0; }
.button--ghost:hover { background-color: var(--color-surface-sunken); }

/* On inverse surfaces the secondary button needs its own borders. */
.surface-panel .button--secondary,
.surface-inverse .button--secondary {
  border-color: rgb(255 255 255 / 45%);
  color: var(--color-text-inverse);
}

.surface-panel .button--secondary:hover,
.surface-inverse .button--secondary:hover { background-color: rgb(255 255 255 / 10%); }

.button[aria-disabled="true"],
.button:disabled {
  background-color: var(--control-disabled-bg);
  border-color: var(--control-disabled-bg);
  color: var(--control-disabled-text);
  cursor: not-allowed;
  pointer-events: none;
}

/* Loading keeps the button's width so the layout never jumps. */
.button[aria-busy="true"] { position: relative; }
.button[aria-busy="true"]::after {
  content: "";
  inline-size: 1.125rem;
  block-size: 1.125rem;
  border: 2px solid currentcolor;
  border-block-start-color: transparent;
  border-radius: 50%;
  animation: shellit-spin 640ms linear infinite;
}

@keyframes shellit-spin { to { transform: rotate(360deg); } }

.button--icon {
  min-inline-size: 0;
  inline-size: 3rem;
  block-size: 3rem;
  padding: 0;
}

/* Stack paired CTAs rather than shrinking Greek type to keep them on one line. */
.button-group { display: flex; flex-wrap: wrap; gap: var(--space-1-5); }

@media (max-width: 440px) {
  .button-group { flex-direction: column; align-items: stretch; }
  .button-group .button { inline-size: 100%; }
}

/* ================================================================ LINKS */

/*
 * The arrow belongs to the last word, not to the right edge.
 *
 * This was `inline-flex`, which makes the text and the arrow two flex items in
 * a row. At 390px «Προτιμάτε να μιλήσουμε; Κλείστε ραντεβού» wraps to two
 * lines, the text item shrinks, and the arrow is left sitting alone against
 * the right edge of the container, vertically centred beside the block of
 * text — it reads as an unrelated control rather than as punctuation.
 *
 * `inline-block` puts the arrow back in the text flow, so it trails the final
 * word wherever that word ends, while still accepting the block padding that
 * keeps the link a 44px target.
 */
.link-standalone {
  display: inline-block;
  min-block-size: 2.75rem;           /* 44px target */
  padding-block: 0.6rem;
  font-weight: 600;
  text-decoration: none;
}

/*
 * The arrow is drawn, not marked up, so it cannot be orphaned.
 *
 * With the arrow as a real element there is a break opportunity in the
 * whitespace before it, and at 390px «Προτιμάτε να μιλήσουμε; Κλείστε
 * ραντεβού» filled the line exactly — leaving the arrow alone on a second
 * line. Moving it into `::after` behind a non-breaking space removes that
 * break opportunity entirely: the arrow is now part of the last word's run and
 * can only wrap with it.
 *
 * A non-breaking space is only enough if nothing breakable comes before it, so
 * the `<span>` and the whitespace around it were removed from the templates and
 * from the saved page content at the same time — the link text now ends
 * flush against `</a>`. The rule below stays as a guard: any arrow span that
 * survives somewhere is hidden rather than drawn twice.
 *
 * The hover nudge moves from `transform` to `margin`, because an inline box
 * cannot be transformed — and it has to stay inline, since an inline-block
 * would reintroduce exactly the break this removes.
 */
.link-standalone__arrow { display: none; }

.link-standalone::after,
.proof-panel__link::after {
  content: "\00a0→";
  transition: margin-inline-start var(--motion-fast) var(--ease-standard);
}

.link-standalone:hover::after,
.proof-panel__link:hover::after { margin-inline-start: 4px; }

@media (prefers-reduced-motion: reduce) {
  .link-standalone::after,
  .proof-panel__link::after { transition: none; }
}
.link-standalone:hover { text-decoration: underline; text-decoration-thickness: 2px; }

/* ======================================================= CUSTOM CURSOR */

/*
 * Not ours — a Fluent Snippet adds a 12px dot that follows the pointer and
 * swells to a 32px ring over anything interactive. The ring is drawn on top of
 * the element it is highlighting and carries two layers of glow, so on a filled
 * button it sat over the label and washed the text out. Malvina saw it in Opera,
 * which composites the shadows more heavily, but it is visible in Chrome too.
 *
 * The effect is kept; the glow is not. A ring can outline a control without
 * bleeding over the words inside it. Deleting the snippet removes this with it.
 */
.shellit-cursor,
.shellit-cursor.active,
.shellit-cursor.glow { box-shadow: none !important; }

/* Over a filled control the ring gets out of the way of the label entirely. */
.shellit-cursor.active { border-width: 2px !important; }

/* A pointer-follower is decoration. It has no business on a touch device, and
   it must not animate for a reader who has asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .shellit-cursor { display: none !important; }
}

/* =============================================================== HEADER */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  background-color: var(--color-page);
  /* The header never shrinks on scroll — that would move the layout. */
  border-block-end: 1px solid transparent;
  transition: border-color var(--motion-standard) var(--ease-standard);
}

.site-header.is-scrolled { border-block-end-color: var(--color-border-subtle); }

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: var(--header-height);
}

.site-header__brand { display: inline-flex; align-items: center; text-decoration: none; }

/*
 * Specificity note: the base layer sets `img[width][height] { height: auto }`
 * to protect intrinsic aspect ratio, and an attribute selector outranks a
 * single class. The logo therefore needs the extra descendant qualifier to
 * win, otherwise WordPress's custom-logo markup renders at full size.
 */
.site-header .site-logo,
.site-footer .site-logo { block-size: 2.5rem; inline-size: auto; max-inline-size: 100%; }

.site-nav { margin-inline-start: auto; }

.site-nav__list { display: flex; align-items: center; gap: 1.25rem; list-style: none; margin: 0; padding: 0; }

.site-nav__item { position: relative; display: flex; align-items: center; }

.site-nav__link {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  color: var(--color-text-primary);
  font-size: 0.9375rem;
  /* 600, not 500: the text face now ships 400 and 600 only, and 500 would
     resolve down to 400 — leaving the navigation the same weight as body copy. */
  font-weight: 600;
  text-decoration: none;
  /* Greek nav labels must never wrap into a second header row. */
  white-space: nowrap;
}

.site-nav__link:hover { color: var(--color-link); }

.site-nav__item.is-current > .site-nav__link {
  color: var(--color-brand-blue);
  font-weight: 700;
  /* State is not communicated by colour alone. */
  box-shadow: inset 0 -2px 0 0 var(--color-accent);
}

.site-nav__disclosure {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  color: var(--color-text-secondary);
  border-radius: var(--radius-xs);
}

.site-nav__disclosure svg { transition: transform var(--motion-standard) var(--ease-standard); }
.site-nav__disclosure[aria-expanded="true"] svg { transform: rotate(180deg); }

.site-nav__panel {
  position: absolute;
  inset-block-start: calc(100% + 0.5rem);
  inset-inline-start: 0;
  inline-size: min(48rem, calc(100vw - 6rem));
  padding: var(--space-3);
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}


.site-nav__sublist {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-nav__sublist a {
  display: block;
  min-block-size: 2.75rem;
  padding-block: var(--space-1);
  color: var(--color-text-primary);
  text-decoration: none;
}

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

.site-header__utilities { display: flex; align-items: center; gap: var(--space-1); }

/*
 * The menu button is the only navigation a phone has. It was a bare icon with
 * no border and no background — the same weight as a decorative glyph — so it
 * read as part of the logo lockup rather than as the control that opens the
 * site. It now carries a border and a surface, which is the least a primary
 * control can do, and it grows to the design's 44px minimum touch target with
 * room to spare.
 */
.site-header__menu-toggle {
  display: none;
  inline-size: 3rem;
  block-size: 3rem;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-raised);
  color: var(--color-text-primary);
  transition: background-color var(--motion-standard) var(--ease-standard),
              border-color var(--motion-standard) var(--ease-standard);
}

.site-header__menu-toggle:hover {
  border-color: var(--color-text-secondary);
  background-color: var(--color-surface-sunken);
}

.site-header__menu-toggle svg { inline-size: 1.5rem; block-size: 1.5rem; }

/*
 * The TranslatePress switcher arrives as an ordinary item in the WordPress
 * menu, so it is rendered by our own walker — but its markup is the plugin's:
 * a flag `img` followed by the language name. The base reset makes every image
 * a block, which stacked the flag above the label and left the item sitting a
 * few pixels below the rest of the navigation.
 */
.site-nav__link .trp-flag-image,
.site-drawer__list .trp-flag-image {
  display: inline-block;
  inline-size: 1.125rem;
  block-size: auto;
  margin-inline-end: 0.4em;
  vertical-align: -0.15em;
}

.site-nav__link [data-no-translation],
.site-drawer__list [data-no-translation] { display: inline; }

/*
 * The language dropdown is not a mega-menu.
 *
 * TranslatePress's switcher is a menu item WITH CHILDREN, so the walker gave it
 * the same panel the Services menu uses — `min(48rem, …)` wide. One language
 * link was sitting in a 768px sheet of empty white, anchored to the left edge of
 * a button that lives at the right edge of the header, so it also ran towards
 * the viewport edge.
 *
 * It gets a panel the size of its contents, aligned to its right edge so it
 * opens inwards and can never overflow the window.
 */
.site-nav__item:has(.trp-flag-image) > .site-nav__panel {
  inline-size: max-content;
  min-inline-size: 9rem;
  max-inline-size: min(16rem, calc(100vw - 2rem));
  padding: var(--space-1) var(--space-2);
  inset-inline-start: auto;
  inset-inline-end: 0;
}

.site-nav__item:has(.trp-flag-image) .site-nav__sublist {
  grid-template-columns: 1fr;
  gap: 0;
}

/* The flag inside the dropdown needs the same inline treatment as the trigger. */
.site-nav__sublist .trp-flag-image {
  display: inline-block;
  inline-size: 1.125rem;
  block-size: auto;
  margin-inline-end: 0.4em;
  vertical-align: -0.15em;
}

.site-nav__sublist [data-no-translation] { display: inline; }

/*
 * Collapse to the drawer at 1180px, not 1024px: the Greek labels are
 * materially longer than the English ones and crowd earlier.
 */
@media (max-width: 1180px) {
  .site-nav { display: none; }
  .site-header__menu-toggle { display: inline-flex; }
  .site-header__cta { display: none; }
  .site-header__inner { min-block-size: var(--header-height-mobile); }

  /*
   * `.site-nav` carried the `margin-inline-start: auto` that pushed everything
   * to the right, and it is display:none here — so the menu button collapsed
   * back against the logo and sat in the middle of the header. The utilities
   * group takes over the job once the navigation is gone.
   */
  .site-header__utilities { margin-inline-start: auto; }
}

/* =============================================================== DRAWER */

.site-drawer { position: fixed; inset: 0; z-index: var(--z-drawer); }

.site-drawer__overlay { position: absolute; inset: 0; background-color: rgb(0 4 8 / 56%); }

.site-drawer__panel {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: min(92vw, 26rem);
  padding: var(--space-3);
  background-color: var(--color-surface-raised);
  overflow-y: auto;
  animation: shellit-drawer-in var(--motion-slow) var(--ease-out);
}

@keyframes shellit-drawer-in { from { transform: translateX(100%); } to { transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .site-drawer__panel { animation: none; }
}

.site-drawer__close { inline-size: 3rem; block-size: 3rem; display: inline-flex; align-items: center; justify-content: center; margin-inline-start: auto; border-radius: var(--radius-sm); }

.site-drawer__list { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.site-drawer__list a { display: block; min-block-size: 3rem; padding-block: var(--space-1-5); color: var(--color-text-primary); font-size: 1.125rem; font-weight: 600; text-decoration: none; border-block-end: 1px solid var(--color-border-subtle); }
.site-drawer__footer { display: flex; flex-direction: column; gap: var(--space-2); margin-block-start: var(--space-4); }

/* ====================================================== LANGUAGE SWITCH */

.lang-switcher { display: inline-flex; align-items: center; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); overflow: hidden; }

.lang-switcher__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 2.75rem;
  min-block-size: 2.75rem;
  padding-inline: var(--space-1);
  color: var(--color-text-secondary);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-decoration: none;
}

.lang-switcher__item + .lang-switcher__item { border-inline-start: 1px solid var(--color-border-subtle); }
.lang-switcher__item:hover { background-color: var(--color-surface-sunken); color: var(--color-text-primary); }

.lang-switcher__item.is-current {
  color: var(--color-brand-navy);
  box-shadow: inset 0 -2px 0 0 var(--color-interactive);
}

/* A language with no translation stays visible so the bilingual structure is
   understandable, but is not a link and never 404s. Contrast stays readable. */
.lang-switcher__item.is-unavailable { color: var(--color-text-muted); cursor: default; }
.lang-switcher__item.is-unavailable:hover { background: none; color: var(--color-text-muted); }

/* =========================================================== BREADCRUMB */

/*
 * The gap under the trail was accidental, not designed: a hero grid is
 * `align-items: center`, so how far the H1 sat below the breadcrumb depended
 * on whether the column beside it happened to be taller. On a service page
 * that produced 40px; on /about-us/, where the copy is the tall column, it
 * produced none at all and the title sat directly on the trail. This gives
 * the breadcrumb its own space so the answer never depends on the neighbour.
 */
.breadcrumb { font-size: var(--type-body-sm); margin-block-end: var(--space-2); }
.breadcrumb ol { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); list-style: none; margin: 0; padding: 0; }
.breadcrumb li { display: inline-flex; align-items: center; gap: var(--space-1); min-block-size: 2.75rem; }
.breadcrumb [aria-current="page"] { color: var(--color-text-secondary); }
.breadcrumb__sep { color: var(--color-text-muted); }

/*
 * Breadcrumb NavXT emits plain list items with no separator markup of its
 * own, so its trail rendered as "Shell-iT Digital Agency Έργα" — two links
 * with only a space between them. Our own trails ship a real separator
 * element; this supplies one for NavXT's without touching the plugin.
 */
.breadcrumb li + li:not(.breadcrumb__sep)::before { content: "/"; margin-inline-end: var(--space-1); color: var(--color-text-muted); }
.breadcrumb li.breadcrumb__sep + li::before { content: none; }

/* A long project title must not turn the trail into three wrapped lines above
   the H1 — which repeats it in full immediately below. */
@media (max-width: 768px) {
  .breadcrumb__current { min-inline-size: 0; }
  .breadcrumb__current span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ================================================================ CARDS */

.card { display: flex; flex-direction: column; }

.card__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-xs);
  background-color: var(--color-surface-sunken);
}

.card__media img { inline-size: 100%; block-size: auto; transition: transform var(--motion-slow) var(--ease-standard); }
.card:hover .card__media img { transform: scale(1.015); }

/*
 * The thumbnail's own link. It fills the frame so the whole picture is the
 * target, and carries no visual treatment of its own — the card already shows
 * its hover state, and a second underline or colour change on the image would
 * announce a second, different destination when there is only one.
 */
.card__media-link { display: block; inline-size: 100%; block-size: 100%; }

/*
 * The card ratios are enforced in CSS as well as by the registered crops.
 *
 * `shellit-card-4x3` and `shellit-card-16x10` were added after the media
 * library was populated, so no thumbnail exists for older uploads and
 * WordPress silently serves the full-size file at its native ratio. The grid
 * then rendered with images of three different heights and the card titles
 * stopped lining up. Declaring the ratio here means the layout is correct
 * whether or not the crop was ever generated — regenerating thumbnails
 * becomes a bandwidth optimisation instead of a layout dependency.
 */
.card--project .card__media { aspect-ratio: 4 / 3; }
.card--post .card__media { aspect-ratio: 16 / 10; }

.card--project .card__media img,
.card--post .card__media img { block-size: 100%; object-fit: cover; }

/*
 * The lead project in the Selected Work row. Wider column, so a wider frame
 * and one step up in title size — the hierarchy is carried by size and area,
 * not by a badge or a coloured border.
 */
.card--feature .card__media { aspect-ratio: 16 / 9; }
.card--feature .card__title { font-size: var(--type-h3); line-height: 1.12; }
.card--feature .card__body { padding-block-start: var(--space-3); }

@media (max-width: 1199px) {
  .card--feature .card__media { aspect-ratio: 4 / 3; }
  .card--feature .card__title { font-size: var(--type-h4); }
}

/*
 * The lead article on the blog index: image and copy side by side, so the
 * reader has an obvious entry point instead of eight equal cards. Below the
 * two-column breakpoint it stacks and becomes an ordinary — if larger — card.
 */
.card--post-lead { display: grid; grid-template-columns: 7fr 5fr; gap: var(--space-4); align-items: center; }
.card--post-lead .card__media { aspect-ratio: 16 / 10; }
.card--post-lead .card__body { padding-block-start: 0; }
.card--post-lead .card__title { font-size: var(--type-h3); line-height: 1.12; }
.card--post-lead .card__excerpt { max-inline-size: var(--measure-lead); }

@media (max-width: 768px) {
  .card--post-lead { grid-template-columns: 1fr; gap: var(--space-3); }
  .card--post-lead .card__title { font-size: var(--type-h4); }
}

/* Factual scope stands in for a result that has not been measured. It is
   supporting information, so it must not compete with a real outcome. */
.card__scope { margin-block-start: var(--space-1-5); color: var(--color-text-secondary); font-size: var(--type-body-sm); }
.card__delivered { margin-block-start: var(--space-1); }

.card__body { padding-block-start: var(--space-3); }
.card__type { display: inline-block; margin-block-end: var(--space-1); }
.card__title { margin-block-end: var(--space-1); }
.card__title a { color: inherit; text-decoration: none; }
.card__title a:hover { text-decoration: underline; }
.card__meta { color: var(--color-text-secondary); font-size: var(--type-body-sm); }
.card__result { margin-block-start: var(--space-1-5); font-weight: 600; }

/* Project + post cards: border-first, never shadow-first. */
.card--bordered {
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  background-color: var(--color-surface-raised);
  transition: border-color var(--motion-standard) var(--ease-standard);
}

.card--bordered:hover { border-color: var(--color-interactive); }
.card:focus-within { outline: 3px solid var(--color-focus-ring); outline-offset: 3px; }

/* Service card */
/*
 * No min-block-size. `.grid-cards` is a grid and its items already stretch to
 * the tallest sibling in the row, so a 280px floor added nothing except a
 * large empty bottom on short cards — most visibly on the homepage values
 * row. Height is now content-driven; the row still equalises.
 */
.service-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-1-5);
  padding: var(--space-3);          /* 24px */
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-raised);
  transition: border-color var(--motion-standard) var(--ease-standard);
}

.service-card--linked:hover { border-color: var(--color-interactive); }

/*
 * A service with no detail page is a genuine non-interactive article. It gets
 * identical typography, padding and border so it reads as complete — but no
 * arrow, no hover transform, no pointer cursor and nothing focusable.
 */
.service-card--static { cursor: default; }
.service-card--static:hover { border-color: var(--color-border-subtle); }

.service-card__title { margin: 0; }
.service-card__title a { color: inherit; text-decoration: none; }
.service-card__desc { color: var(--color-text-secondary); }
.service-card__footer { margin-block-start: auto; padding-block-start: var(--space-2); }

/* ========================================================= PROOF PANEL */

/*
 * The image takes a column; the facts stack beside it.
 *
 * This was a 2 x 2 grid: picture, then three tiles each holding a label and two
 * or three words. Three of the four cells were therefore mostly empty navy, and
 * the panel read as a component waiting for content that was never coming — the
 * facts are short by nature, so no amount of writing would have filled them.
 *
 * One tall image beside a stacked list of facts uses the same area, shows the
 * work at nearly twice the size, and has no empty cells to explain.
 *
 * A fourth fact would be worth a cell only if it said something a label cannot:
 * a verified headline result. `_shellit_headline_result` exists for exactly
 * that and is empty on all 28 projects — see the open items.
 */
.proof-panel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  min-block-size: 27.5rem;          /* 440px */
  padding: 1px;
  background-color: var(--color-border-inverse);
  border-radius: var(--radius-md);
  overflow: hidden;
}

/*
 * The panel has exactly two children: the picture and the fact stack. Grid
 * items stretch to their row by default, so the picture is as tall as the
 * facts beside it without being told to span anything.
 */
.proof-panel__media { min-inline-size: 0; }
.proof-panel__media img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }

/*
 * The facts share the remaining height rather than each taking only what its
 * two words need, which is what left the old 2 x 2 grid with a band of dead
 * navy under the last tile. `1fr` on auto rows is a floor of `auto`, so a fact
 * that wraps to three lines still gets the room it needs.
 */
.proof-panel__stack {
  display: grid;
  grid-auto-rows: 1fr;
  gap: 1px;
  min-inline-size: 0;
}

/* With no cover to show, the facts take the full width instead of half of it. */
.proof-panel--no-media { grid-template-columns: 1fr; }

.proof-panel__quadrant {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-1);
  padding: var(--space-3);
  background-color: var(--color-panel-inverse);
  color: var(--color-text-inverse);
}

.proof-panel__label { color: var(--color-text-inverse-secondary); }
.proof-panel__value { font-family: var(--font-display); font-size: 2rem; font-weight: 700; line-height: 1; }

/*
 * A quadrant carrying a sentence rather than a number cannot use the 32px
 * display step — three services or a client name would overflow the tile. Same
 * family and weight, sentence-sized, and clamped so a long value truncates
 * instead of pushing the panel taller than the hero column beside it.
 */
.proof-panel__value--text {
  font-size: 1.0625rem;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

/*
 * `inline-block`, not `inline-flex`, for the same reason as `.link-standalone`
 * above — and this one had the fault twice over. As a flex container it made
 * the `::after` arrow a flex ITEM, so the `gap` was applied on top of the
 * arrow's own non-breaking space (two gaps where one was designed) and the
 * arrow could still be stranded away from the text when «Δείτε το case study»
 * wrapped inside a narrow proof-panel quadrant.
 */
.proof-panel__link {
  display: inline-block;
  min-block-size: 2.75rem;
  padding-block: 0.6rem;
  margin-block-start: var(--space-1);
  color: var(--color-text-inverse);
  font-size: var(--type-body-sm);
  font-weight: 650;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.proof-panel__link:hover { color: var(--color-accent); }

/* Below ~420px each quadrant would be under 150px of usable width, so stack. */
@media (max-width: 420px) {
  .proof-panel { grid-template-columns: 1fr; min-block-size: 0; }
  /* Stacked, the cover has no fact column to match, so it keeps its own shape
     instead of stretching to whatever the facts happen to need. */
  .proof-panel__media { aspect-ratio: 4 / 3; }
  .proof-panel__stack { grid-auto-rows: min-content; }
}

/* A stat whose value is a phrase, not a number — "εντός 1 εργάσιμης", say.
   The 32px display step is for figures; a sentence at that size wraps and
   stops reading as a single value. */
.stat__value--sentence { font-size: 1.5rem; line-height: 1.25; }

/* =================================================== BLOCK EDITOR BUTTONS */

/*
 * Core Button blocks, wearing the theme's button.
 *
 * The first converted page shipped its call to action as a core Button block
 * and it rendered as WordPress's default: transparent background, link-blue
 * text, a 9999px pill and weight 400, against the theme's solid blue, white,
 * 8px radius and weight 700. Nothing in the markup was wrong — the block
 * simply had no styles of its own, and counting headings and cards would never
 * have caught it. Measuring the computed background did.
 *
 * These are registered as BLOCK STYLES rather than being forced onto every
 * button, so they appear in the block's own style picker: someone adding a
 * button picks "Shell-iT primary" from the toolbar and gets the real thing.
 * The declarations mirror `.button` exactly rather than sharing a class,
 * because the class lives on the wrapper and the styling belongs on the link.
 */
.wp-block-button.is-style-shellit-primary .wp-block-button__link,
.wp-block-button.is-style-shellit-secondary .wp-block-button__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-block-size: 3rem;
  min-inline-size: 8.25rem;
  max-inline-size: 100%;
  padding: 0 1.25rem;
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-text);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  transition: background-color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard),
              color var(--motion-fast) var(--ease-standard),
              transform var(--motion-fast) var(--ease-standard);
}

.wp-block-button.is-style-shellit-primary .wp-block-button__link {
  background-color: var(--control-bg);
  border-color: var(--control-bg);
  color: var(--color-text-inverse);
}

.wp-block-button.is-style-shellit-primary .wp-block-button__link:hover {
  background-color: var(--control-bg-hover);
  border-color: var(--control-bg-hover);
}

.wp-block-button.is-style-shellit-secondary .wp-block-button__link {
  background-color: transparent;
  border-color: var(--color-border-strong);
  color: var(--color-text-primary);
}

.wp-block-button.is-style-shellit-secondary .wp-block-button__link:hover {
  background-color: var(--color-surface-sunken);
  border-color: var(--color-brand-slate);
  color: var(--color-text-primary);
}

.wp-block-button.is-style-shellit-primary .wp-block-button__link:active,
.wp-block-button.is-style-shellit-secondary .wp-block-button__link:active {
  transform: translateY(1px);
}

/* The buttons row keeps the component's spacing, not the block's default. */
.wp-block-buttons.button-group { gap: var(--space-2); }

/* ========================================================= SEARCH FORM */

/*
 * These rules used to be inline `style` attributes on the input and the row,
 * which is how the bug below survived: nothing in the cascade could correct
 * them and no stylesheet mentioned the component at all.
 *
 * A flex item defaults to `min-width: auto`, and a text input's min-content
 * width is its `size` attribute — about 20 characters. On a 390px screen that
 * floor plus the Greek submit label ("Αναζήτηση", 132px) exceeded the column
 * and pushed the button 22px past the viewport, giving the 404 and search
 * pages a horizontal scrollbar. `min-inline-size: 0` lets the field shrink to
 * the space that is actually there.
 */
.search-form__row {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
}

.search-form__field {
  flex: 1 1 12rem;
  min-inline-size: 0;                /* Override the flex-item min-content floor. */
  min-block-size: 3.25rem;
  padding-inline: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-raised);
  color: var(--color-text-primary);
  font: inherit;
}

/*
 * `flex-basis: 12rem` with wrap is the escape hatch: below roughly 260px of
 * available width the field can no longer hold a useful query, so the button
 * drops to its own line and both keep their full 44px+ target instead of the
 * button being squeezed to an unreadable sliver.
 */
.search-form__submit { flex: 0 0 auto; min-block-size: 3.25rem; }

/* ========================================================= SERVICE BRIEF */

/*
 * What this page contains, on the navy surface.
 *
 * An executive brief rather than a card: ordinals in the metadata register,
 * section titles as the only links, and one hairline between rows so it reads
 * as a contents list and not as a menu of buttons.
 */
.service-brief { padding: var(--space-4); border-radius: var(--radius-md); }

.service-brief__list {
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

.service-brief__list li {
  display: grid;
  grid-template-columns: 2.25rem 1fr;
  align-items: baseline;
  gap: var(--space-1);
  padding-block: var(--space-2);
  border-block-start: 1px solid var(--color-border-inverse);
}

.service-brief__list li:first-child { border-block-start: 0; padding-block-start: 0; }

.service-brief__ordinal {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  color: var(--color-accent-text);
}

.service-brief__list a {
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none;
}

.service-brief__list a:hover { text-decoration: underline; }

/* =========================================================== STAT / TILE */

.stat-row { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-0-5);
  min-block-size: 6.5rem;           /* 104px */
  min-inline-size: 9rem;            /* 144px */
  padding-inline-end: var(--space-3);
  border-inline-end: 1px solid var(--color-border-subtle);
}

.stat:last-child { border-inline-end: 0; padding-inline-end: 0; }

/*
 * Statistics as a supporting line rather than as a panel.
 *
 * The 104px minimum exists so a column of stats aligns with a neighbouring
 * block; inline under a lede it just adds air. The values also step down,
 * because here they support the sentence above them instead of competing
 * with the H1.
 */
.stat-row--inline { gap: var(--space-4); margin-block-start: var(--space-5); }
.stat-row--inline .stat { min-block-size: 0; min-inline-size: 0; }
.stat-row--inline .stat__value { font-size: 1.5rem; }
.stat__value { font-family: var(--font-display); font-size: 2rem; font-weight: 700; line-height: 1; letter-spacing: -0.02em; }
.stat__label { color: var(--color-text-secondary); font-size: var(--type-body-sm); }

.surface-panel .stat, .surface-inverse .stat { border-inline-end-color: var(--color-border-inverse); }

/*
 * AWARD — a credibility marker, not a statistic.
 *
 * The rail originally reused `.stat`, which made the year the largest thing
 * in the row: three identical "2024"s read as a dashboard rather than as
 * three distinct awards. The award name is the claim, so it is primary; the
 * place and year are supporting metadata.
 */
.award {
  display: flex;
  flex-direction: column;
  gap: var(--space-0-5);
  flex: 1 1 13rem;
  max-inline-size: 20rem;
  padding-inline-end: var(--space-3);
  border-inline-end: 1px solid var(--color-border-subtle);
}

.award:last-child { border-inline-end: 0; padding-inline-end: 0; }
.award__name { font-family: var(--font-display); font-size: 1.125rem; font-weight: 700; line-height: 1.25; letter-spacing: -0.005em; }
.award__meta { color: var(--color-text-secondary); font-size: var(--type-body-sm); font-variant-numeric: tabular-nums; }

@media (max-width: 768px) {
  .award { flex-basis: 100%; padding-inline-end: 0; padding-block-end: var(--space-2); border-inline-end: 0; border-block-end: 1px solid var(--color-border-subtle); }
  .award:last-child { padding-block-end: 0; border-block-end: 0; }
}

/* ============================================================== CHIPS */

/*
 * The filter bar carries two ranked dimensions: type as chips, service as a
 * select. They are separated by a rule rather than by whitespace so the
 * ranking is legible without the two rows merging into one chip soup.
 */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-block-end: var(--space-5);
  padding-block-end: var(--space-2);
  border-block-end: 1px solid var(--color-border-subtle);
}

.filter-bar > .filter-chips { flex: 1 1 auto; }

.filter-select { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
.filter-select__label { color: var(--color-text-secondary); font-size: var(--type-body-sm); font-weight: 650; }

.filter-select__control {
  min-block-size: 2.75rem;
  padding-inline: var(--space-1-5) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-raised);
  color: var(--color-text-primary);
  font-family: inherit;
  font-size: var(--type-body-sm);
}

.filter-select__control:focus-visible { outline: 3px solid var(--color-focus-ring); outline-offset: 2px; }

/* Count is supporting detail — never the reason the chip is readable. */
.chip__count { margin-inline-start: var(--space-0-5); opacity: 0.7; font-variant-numeric: tabular-nums; }

@media (max-width: 768px) {
  .filter-bar { flex-direction: column; align-items: stretch; }
  .filter-select__control { inline-size: 100%; }
}

.filter-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-block-size: 2.75rem;
  padding-inline: var(--space-2);
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-pill);
  color: var(--color-text-primary);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard);
}

.chip:hover { background-color: var(--color-surface-sunken); }

/* Selection is carried by aria-pressed, and shown with fill + a check icon —
   never by colour alone. */
.chip[aria-pressed="true"],
.chip.is-selected {
  background-color: var(--color-brand-navy);
  border-color: var(--color-brand-navy);
  color: var(--color-text-inverse);
}

.chip[aria-pressed="true"]:hover { background-color: var(--color-brand-navy); }

/* ========================================================= PAGINATION */

.pagination ul { display: flex; flex-wrap: wrap; gap: var(--space-1); list-style: none; margin: 0; padding: 0; }

.pagination a,
.pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 2.75rem;
  min-block-size: 2.75rem;
  padding-inline: var(--space-1);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-sm);
  text-decoration: none;
}

.pagination [aria-current="page"] { background-color: var(--color-brand-navy); border-color: var(--color-brand-navy); color: var(--color-text-inverse); }

/* ========================================================== ACCORDION */

.accordion__item { border-block-end: 1px solid var(--color-border-subtle); }

.accordion__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: 3.5rem;           /* 56px */
  padding-block: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--type-h5);
  font-weight: 650;
  text-align: start;
}

.accordion__trigger svg { flex: none; transition: transform var(--motion-slow) var(--ease-standard); }
.accordion__trigger[aria-expanded="true"] svg { transform: rotate(180deg); }
.accordion__panel { padding-block-end: var(--space-3); }

/* =============================================================== FORMS */

.field { display: flex; flex-direction: column; gap: var(--space-1); margin-block-end: var(--space-3); }
.field__label { font-weight: 600; }
.field__hint { color: var(--color-text-secondary); font-size: var(--type-body-sm); }

.field input[type="text"],
.field input[type="email"],
.field input[type="tel"],
.field input[type="search"],
.field input[type="url"],
.field select,
.field textarea {
  inline-size: 100%;
  min-block-size: 3rem;             /* 48px */
  padding: 0.75rem 0.9375rem;       /* 12 / 15 */
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  color: var(--color-text-primary);
}

.field textarea { min-block-size: 11rem; resize: vertical; }  /* 176px */

.field input:hover,
.field select:hover,
.field textarea:hover { border-color: var(--color-brand-slate); }

.field [aria-invalid="true"] { border-color: var(--color-error); border-inline-start-width: 3px; }

.field__error {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--color-error);
  font-size: var(--type-body-sm);
  font-weight: 600;
}

/* Checkbox and radio: the visual control is 20px but the whole label row is a
   44px target. */
.field--choice label { display: flex; align-items: center; gap: var(--space-1-5); min-block-size: 2.75rem; }
.field--choice input { inline-size: 1.25rem; block-size: 1.25rem; accent-color: var(--color-interactive); }

.form-summary {
  padding: var(--space-3);
  border-radius: var(--radius-md);
  margin-block-end: var(--space-4);
}

.form-summary--error { background-color: var(--color-error-bg); color: var(--color-error); }
.form-summary--success { background-color: var(--color-success-bg); color: var(--color-success); }
.form-summary:focus-visible { outline: 3px solid var(--color-focus-ring); outline-offset: 3px; }
.form-summary ol { margin: var(--space-1) 0 0; padding-inline-start: var(--space-3); }

/* ============================================================== NOTICE */

.notice { display: flex; gap: var(--space-1-5); padding: var(--space-2); border-radius: var(--radius-sm); }
.notice__icon { flex: none; }
.notice--info { background-color: var(--color-info-bg); color: var(--color-info); }
.notice--success { background-color: var(--color-success-bg); color: var(--color-success); }
.notice--warning { background-color: var(--color-warning-bg); color: var(--color-warning); }
.notice--error { background-color: var(--color-error-bg); color: var(--color-error); }

/* ========================================================== BLOCKQUOTE */

blockquote {
  max-inline-size: 42.5rem;         /* 680px */
  padding-inline-start: var(--space-3);
  border-inline-start: 4px solid var(--color-brand-blue);
  font-size: 1.375rem;
  line-height: 1.5;
}

blockquote cite { display: block; margin-block-start: var(--space-2); font-size: var(--type-body-sm); font-style: normal; color: var(--color-text-secondary); }

/* =============================================================== TABLE */

.table-scroll { overflow-x: auto; }

table { inline-size: 100%; font-size: var(--type-body-sm); }
th, td { min-block-size: 3.25rem; padding: 0.75rem 1rem; border: 1px solid var(--color-border-subtle); text-align: start; }
thead th { background-color: var(--color-surface-sunken); }
td[data-numeric], th[data-numeric] { text-align: end; font-variant-numeric: tabular-nums; }

/* ============================================================== FIGURE */

figure { margin: 0; }
figcaption { margin-block-start: var(--space-1); max-inline-size: var(--measure-caption); color: var(--color-text-secondary); font-size: var(--type-caption); }

/* ============================================================ CTA BAND */

/* Surface and text colours come from `.surface-panel` in the markup — see the
   note in parts/cta-band.php. This rule owns geometry only. */
.cta-band { padding-block: var(--space-10); }
.cta-band__inner { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: center; }
.cta-band__copy { grid-column: span 8; }
.cta-band__actions { grid-column: span 4; display: flex; flex-wrap: wrap; gap: var(--space-1-5); justify-content: flex-end; }

@media (max-width: 768px) {
  .cta-band { padding-block: var(--space-6); }
  .cta-band__inner { grid-template-columns: 1fr; gap: var(--space-3); }
  .cta-band__copy, .cta-band__actions { grid-column: 1 / -1; justify-content: flex-start; }
}

/* ========================================================= BACK TO TOP */

.back-to-top {
  position: fixed;
  inset-inline-end: var(--space-3);
  inset-block-end: 5.5rem;          /* clears the chat bubble by 16px */
  z-index: var(--z-sticky);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 3rem;
  block-size: 3rem;
  background-color: var(--color-brand-navy);
  color: var(--color-text-inverse);
  border-radius: var(--radius-pill);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--motion-standard) var(--ease-standard),
              transform var(--motion-standard) var(--ease-standard),
              visibility var(--motion-standard);
  transform: translateY(4px);
}

.back-to-top.is-visible { opacity: 1; visibility: visible; transform: none; }

@media (max-width: 768px) {
  .back-to-top { inset-inline-end: var(--space-2); inset-block-end: 5rem; }
}

/*
 * Not on a phone.
 *
 * At 390px there is no gutter for a persistent floating control: every
 * important thing on the page is full-bleed, so it necessarily sits on top of
 * something. Scanning the contact page at 200px steps it covered the tail of a
 * wrapped footer link; hiding it over the footer fixed that and it immediately
 * landed on «Αποστολή» instead, once the submit button went full width — which
 * is the single control the whole page exists to get pressed.
 *
 * It is convenience UI, not navigation: the footer carries the full menu, and
 * both mobile platforms have their own scroll-to-top gesture. It stays from
 * 601px up, where there is room for it to float over nothing.
 */
@media (max-width: 600px) {
  .back-to-top { display: none; }
}

/* ============================================================== FOOTER */

.site-footer { background-color: var(--color-panel-inverse); color: var(--color-text-inverse); padding-block: var(--space-10) var(--space-5); }
.site-footer a { color: var(--color-text-inverse); }
.site-footer a:hover { color: var(--color-accent); }
.site-footer__grid { display: grid; grid-template-columns: 4fr 3fr 2fr 3fr; gap: var(--space-4); }
.site-footer__heading { color: var(--color-text-inverse); font-size: var(--type-h6); margin-block-end: var(--space-2); }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li a { display: inline-flex; align-items: center; min-block-size: 2.75rem; text-decoration: none; }
.site-footer li a:hover { text-decoration: underline; }
/*
 * Social links are a row of icon targets, not a stacked menu. Without this the
 * list inherited the footer's block layout and the four icons ran down the
 * page, which is what produced most of the footer's excess height.
 */
.site-footer__social { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-block-start: var(--space-3); }

/* The legal links sit on the copyright row, so they read as a row. Left as a
   plain list they stacked underneath it. */
.site-footer__legal { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); }

/*
 * A label prefixing a phone number needs its own spacing rather than a trailing
 * space in the translated string — HTML collapses that space away, so the
 * footer read "Γραφείο:+30 210 440 7283".
 */
.contact-link__label { margin-inline-end: 0.35em; }

/*
 * Registered name, VAT and registry number. Set in the metadata register — it
 * is a statement of record, not a sentence, and reads as one.
 */
.site-footer__identity { flex-basis: 100%; order: 3; font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.02em; color: var(--color-text-inverse-secondary); }
.site-footer__social li a { justify-content: center; inline-size: 2.75rem; }

/* 40px above the rule, not 64: the columns already carry their own bottom
   space and the extra step left a visibly empty band. */
.site-footer__bottom { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; margin-block-start: var(--space-5); padding-block-start: var(--space-3); border-block-start: 1px solid var(--color-border-inverse); color: var(--color-text-inverse-secondary); font-size: var(--type-body-sm); }

@media (max-width: 1199px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 768px) { .site-footer { padding-block: 3.5rem var(--space-4); } .site-footer__grid { grid-template-columns: 1fr; gap: var(--space-5); } .site-footer__bottom { margin-block-start: var(--space-4); } }

/* ================================================== INTEGRATION WRAPPERS */

/*
 * FluentBooking: reserve height so the embed cannot cause layout shift, but
 * never clip it and never create a nested scroll region — we do not control
 * the plugin's internal height.
 */
.booking-wrapper {
  inline-size: 100%;
  max-inline-size: 60rem;           /* 960px */
  margin-inline: auto;
  /*
   * Height is reserved only while `aria-busy` is set — see `[aria-busy]`
   * below. Reserving it permanently left the shell taller than the embed
   * once it had rendered, which is where a third of the dead space under
   * the calendar came from.
   */
  padding: var(--space-3);
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
  overflow: visible;
}

.booking-wrapper[aria-busy="true"] { min-block-size: 42.5rem; } /* 680px desktop */

.booking-wrapper iframe,
.booking-wrapper > * { max-inline-size: 100%; box-sizing: border-box; }

/*
 * Stop the embed pushing the booking page sideways on a phone.
 *
 * FluentBooking renders each slot's location as a flex row whose text child
 * cannot shrink — a flex item's default `min-width: auto` floors it at its
 * content width. At 390px those rows measured 318px wide sitting at x=532,
 * giving the page 167px of horizontal scroll. Third-party markup, but it is
 * the booking page, and a visitor on a phone does not care whose CSS it was.
 *
 * This is the third instance of the same root cause in this codebase — the
 * search form and the contact layout were the others — which is why the rule
 * is written as a general "let flex children shrink" for the whole embed
 * rather than as a fix for `.slot_location` specifically. The next component
 * FluentBooking adds is covered without anyone noticing it needed to be.
 *
 * `overflow-wrap: anywhere` handles the remaining case the shrink cannot: an
 * unbroken string, such as a long meeting URL, wider than the column itself.
 */
.booking-wrapper :is([class*="fcal_"], [class*="fluent_booking"]) {
  min-inline-size: 0;
  max-inline-size: 100%;
}

.booking-wrapper :is([class*="fcal_"], [class*="fluent_booking"]) { overflow-wrap: anywhere; }

@media (max-width: 1199px) { .booking-wrapper[aria-busy="true"] { min-block-size: 45rem; } }   /* 720 */
@media (max-width: 768px)  { .booking-wrapper[aria-busy="true"] { min-block-size: 47.5rem; } } /* 760 */

/*
 * ------------------------------------------------ FluentBooking, at 600px
 *
 * The embed keeps a desktop two-column meeting card at every width: the
 * description in a flexible column, "Κάντε κράτηση τώρα" in a fixed 171px
 * one beside it. Measured at 390px that left the description 99px of
 * column — two or three words a line, four cards of it, and a page 4,966px
 * tall to compare four meeting types. The button is not the problem; the
 * parallel columns are.
 *
 * Collapsing the card to one column and taking one step out of each nested
 * padding gives the description ~275px instead of ~99px. The padding is
 * trimmed, not zeroed — the plugin's own card still needs to look like a
 * card, and blindly flattening every wrapper is what breaks on the next
 * plugin update.
 *
 * Selectors are the plugin's stable structural classes (`fcal_card`,
 * `book_now`), scoped to `.booking-wrapper` so nothing here can reach a
 * FluentBooking instance placed anywhere else.
 */
@media (max-width: 600px) {
  .booking-wrapper { padding: var(--space-1-5); }

  /*
   * The plugin's own outer wrapper adds 20px a side on top of everything
   * else. It is the last layer between the site gutter and the text, and at
   * 390px it is worth 40px of description width.
   */
  .booking-wrapper .fluent_booking_wrap { padding-inline: 0; }

  .booking-wrapper .fcal_slot { padding-inline: var(--space-2); }

  .booking-wrapper .fcal_card {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
  }

  .booking-wrapper .fcal_slot_content { inline-size: 100%; }

  /* Full width, and a real touch target — the plugin ships a 36px button. */
  .booking-wrapper .book_now {
    inline-size: 100%;
    min-block-size: 2.75rem;
    justify-content: center;
  }
}

/*
 * The embed prints the agency name as its own H1, so every booking page had
 * two visitor-facing H1s. The plugin injects this markup as a string rather
 * than mounting a component over it, so the tag is swapped for a paragraph
 * in `theme.js` — this rule is what keeps it looking the way it did.
 */
.booking-wrapper .fcal_author_header .author_info .booking-author-name {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: -0.025em;
  text-align: center;
  color: var(--color-text-primary);
}

/*
 * ------------------------------------------- Booking: the other way to ask
 *
 * A single line offering email instead of a call. It is the booking block's
 * closing element, so it takes the booking shell's width and surface rather
 * than opening a section of its own.
 */
.alt-contact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-4);
  inline-size: 100%;
  max-inline-size: 60rem;   /* 960px — the booking shell */
  margin-inline: auto;
  margin-block-start: var(--space-6);
  padding: var(--space-2) var(--space-4);
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
}

.alt-contact__title,
.alt-contact__action { margin: 0; }

@media (max-width: 600px) {
  .alt-contact {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-0-5);
    margin-block-start: var(--space-4);
    padding: var(--space-2) var(--space-3);
  }
}

.booking-placeholder { display: flex; flex-direction: column; gap: var(--space-2); align-items: center; justify-content: center; min-block-size: 24rem; color: var(--color-text-secondary); }

/*
 * `display: flex` outranks the browser's `[hidden] { display: none }`, so the
 * placeholder stayed on screen after the script had hidden it: "Φόρτωση
 * διαθέσιμων ραντεβού…" sat above a calendar that had finished loading.
 *
 * The theme already carries this guard for the nav panels, the drawer and the
 * accordions. This component was missed — which is the argument for the guard
 * being written next to every component that sets `display` and can be
 * hidden, rather than remembered.
 */
/* Now handled globally — see the `[hidden]` rule in 02-base.css. */

/* CookieYes: restyle only. Its roles, ARIA and consent logic are untouched. */
.cky-consent-container { max-inline-size: 26.25rem !important; }
.cky-consent-container .cky-consent-bar { border-radius: var(--radius-md) !important; padding: var(--space-3) !important; }
.cky-btn { min-block-size: 2.75rem !important; border-radius: var(--radius-sm) !important; font-family: var(--font-text) !important; font-weight: 700 !important; }
.cky-btn-accept { background-color: var(--control-bg) !important; border-color: var(--control-bg) !important; color: #fff !important; }
.cky-btn-reject, .cky-btn-customize { background-color: transparent !important; border-color: var(--color-border-strong) !important; color: var(--color-text-primary) !important; }

/* Legal/plugin tables must stay readable — never shrunk into 11px text. */
.cky-cookie-des-table, .cky-cookie-des-table td, .cky-cookie-des-table th { font-size: 1rem !important; }

/* ========================================================= WPFORMS */

/*
 * WPForms ships its own stylesheet. Rather than fight it selector for
 * selector, only the things that would visibly break the design system are
 * overridden: the control geometry, the focus ring and the button. Its
 * validation markup, ARIA and error handling are left completely alone.
 */
.contact-form .wpforms-container { margin: 0; }
.contact-form .wpforms-field { padding: 0 0 var(--space-3); }
.contact-form .wpforms-field-label { font-size: var(--type-body-sm); font-weight: 650; }
.contact-form .wpforms-field-sublabel,
.contact-form .wpforms-field-description { color: var(--color-text-secondary); font-size: var(--type-caption); }

.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form input[type="tel"],
.contact-form input[type="url"],
.contact-form textarea,
.contact-form select {
  inline-size: 100%;
  min-block-size: 3rem;
  padding: 0.75rem var(--space-1-5);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-raised);
  color: var(--color-text-primary);
  font-family: inherit;
  font-size: 1rem;
}

.contact-form textarea { min-block-size: 9rem; resize: vertical; }

/*
 * WPForms sizes its controls with its own -small/-medium/-large classes, which
 * cap a "medium" field at around 60% of the column. On a single-column form
 * that left the name and email inputs at half width while everything around
 * them was full-bleed — the one place the plugin was still visible through the
 * design. Sizing is the template's decision here.
 */
/*
 * `!important` is deliberate and is the narrow exception, not a habit.
 *
 * WPForms scopes its width defaults to the form's ID — `#wpforms-1348
 * .wpforms-field-medium { max-width: 60% }` — and an ID selector outranks any
 * class-only rule we can write. The alternatives are hard-coding that form ID
 * into the stylesheet, which breaks the moment the form is rebuilt, or
 * accepting half-width inputs in a full-width column. Field sizing on this
 * template is the theme's decision, so it is stated as one.
 */
.contact-form .wpforms-field-small,
.contact-form .wpforms-field-medium,
.contact-form .wpforms-field-large,
.contact-form .wpforms-field-row {
  max-inline-size: 100% !important;
  inline-size: 100% !important;
}

/* The dual-layer focus ring from the design system, not the browser default. */
.contact-form :is(input, textarea, select):focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-color: var(--color-interactive);
}

/* Checkbox targets stay at least 44px including their label. */
/*
 * Checkbox targets stay at least 44px including their label, and the control
 * itself is 24px square — WCAG 2.2 2.5.8 sets 24x24 as the floor for a target
 * that is not inline in a sentence, and an 18px box on the consent tickbox of
 * the only lead-capture form on the site was under it.
 *
 * Top alignment, not centre: the consent label wraps to two or three lines at
 * narrow widths, and centring the label block moved its first line below the
 * box it belongs to.
 */
.contact-form .wpforms-field-checkbox li { display: flex; gap: var(--space-1-5); align-items: flex-start; }
.contact-form .wpforms-field-checkbox label { min-block-size: 2.75rem; display: flex; align-items: flex-start; padding-block: 0.6rem; font-size: var(--type-body-sm); }
/*
 * The size comes from WPForms' own variable, because its geometry rules read
 * that variable and nothing else. Setting `inline-size` here changed nothing —
 * measured 16px on the live page with the rule in place. The plugin declares
 * `--wpforms-field-size-checkbox-size: 16px` on the form container under an ID
 * selector (`#wpforms-1348`), which outranks any class-only rule: the same wall
 * the field-width override above ran into. So `!important` on the one
 * variable, which is a smaller intervention than fighting the geometry rules it
 * feeds, and it keeps working if the form is rebuilt with a new id.
 */
.contact-form .wpforms-container { --wpforms-field-size-checkbox-size: 1.5rem !important; }
.contact-form .wpforms-field-checkbox input { flex: none; margin-block-start: 0.6rem; }

.contact-form button[type="submit"] {
  min-block-size: 3.5rem;
  min-inline-size: 10rem;
  padding-inline: var(--space-3);
  border: 1px solid var(--control-bg);
  border-radius: var(--radius-sm);
  background-color: var(--control-bg);
  color: #fff;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

.contact-form button[type="submit"]:hover { background-color: var(--control-bg-hover); border-color: var(--control-bg-hover); }
.contact-form button[type="submit"]:focus-visible { outline: 3px solid var(--color-focus-ring); outline-offset: 2px; }

/*
 * On a phone every control above it is full width; a 160px button under them
 * reads as a minor action rather than as the end of the form.
 */
@media (max-width: 600px) {
  .contact-form button[type="submit"] { inline-size: 100%; }
}

/* Errors must never rely on colour alone — WPForms already prints text; this
   only makes sure that text is readable against the design system's surface. */
/*
 * The required marker, at AA.
 *
 * WPForms ships its asterisk in a red measuring 4.48:1 on white — under the
 * 4.5:1 floor by a hair, which is still a failure, and it is the marker
 * telling someone which fields they cannot skip on the page that generates
 * the leads.
 *
 * Overriding WPForms' own custom property rather than its selector. A
 * class-pair rule of ours loses to a class-pair rule of theirs purely on
 * source order — the first attempt at this did exactly that and changed
 * nothing — and the alternative, another `!important`, would be a second
 * specificity fight to lose later. The variable is the seam the plugin
 * provides, so it is the one to use.
 */
.contact-form { --wpforms-label-error-color: var(--color-error); }

/*
 * The CAPTCHA fallback notice.
 *
 * Warning colours, not error colours: nothing has gone wrong from the
 * visitor's point of view, they have two working ways through, and a red panel
 * for an unavailable third-party dependency would read as though they had
 * mistyped something.
 *
 * The accent rule down its leading edge is what separates it from an ordinary
 * bordered paragraph — it has to look like a deliberate status component,
 * because directly above it is a black Cloudflare error box that looks like an
 * accident. Sitting them together, in that order, immediately above the submit
 * button, is the whole point: the explanation has to arrive before the action
 * it is about, not after it.
 */
/*
 * The long selector is not decoration. The notice now lives INSIDE the form, so
 * that it can sit between the security widget and the button — and WPForms
 * resets every `p` inside its form with a selector carrying more weight than a
 * single class. Measured after the move: border, padding and background all
 * computed to 0 and the notice rendered as a bare paragraph. This matches the
 * plugin's specificity instead of adding another `!important`.
 */
.contact-form .wpforms-container .wpforms-form p.contact-form__captcha-fallback,
.contact-form__captcha-fallback {
  margin-block: var(--space-1-5) var(--space-4);
  padding: var(--space-2) 1.125rem;
  border: 1px solid var(--color-border-strong);
  border-inline-start: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-raised);
  font-size: var(--type-body-sm);
  line-height: 1.5;
}

/*
 * Turnstile and its fallback are one state, so they sit as one block.
 *
 * WPForms separates the widget from whatever follows it with a literal `<br>`,
 * which left roughly 45-50px between the challenge box and the sentence
 * explaining it — far enough apart to read as two unrelated things. The break
 * is presentational, so it goes, and the notice keeps a normal small gap above
 * and a full one below, before the button.
 */
.contact-form .cf-turnstile-br { display: none; }
.contact-form .wpforms-recaptcha-container { margin-block-end: var(--space-2); }


.contact-form .wpforms-error { color: var(--color-error); font-size: var(--type-body-sm); }
.contact-form input.wpforms-error,
.contact-form textarea.wpforms-error { border-color: var(--color-error); }
.contact-form .wpforms-confirmation-container-full { padding: var(--space-3); border: 1px solid var(--color-success); border-radius: var(--radius-md); background-color: var(--color-success-bg); }

/* ==================================================== TECHNICAL DETAILING */

/*
 * A hairline grid on the dark surfaces.
 *
 * The design system already calls the `#` a layout engine; this makes that
 * visible on the two panels that carry the most weight. It is drawn with a
 * gradient rather than an image — no request, no asset to maintain — and sits
 * at roughly 4% opacity, so it reads as engineered texture at arm's length and
 * disappears at reading distance. It must never compete with the content:
 * every value on these panels is still text on flat colour.
 */
.proof-panel,
.cta-band {
  background-image:
    repeating-linear-gradient(to right, rgb(255 255 255 / 4%) 0 1px, transparent 1px 4rem),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 4%) 0 1px, transparent 1px 4rem);
}

/* The quadrant tiles paint their own background over the grid, so the texture
   belongs on the tile rather than only on the panel behind it. */
.proof-panel__stack { background-image: inherit; }
.proof-panel__quadrant { background-image: inherit; }

/*
 * Corner ticks — the hash reduced to its intersection.
 *
 * Two short accent rules in the top-left corner of a structural block. It is
 * the same device the logo uses, at component scale, and it costs one
 * pseudo-element with no extra markup.
 */
.capability-matrix__item,
.service-range__group--lead { position: relative; }

.capability-matrix__item::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: var(--space-3);
  block-size: 2px;
  background-color: var(--color-accent);
}

/* Numbers in the process rail get the same accent tick beneath them, so the
   sequence reads as a measured series rather than as decoration. */
.process__step { position: relative; }

@media (prefers-reduced-motion: no-preference) {
  .card--project .card__media::after {
    content: "";
    position: absolute;
    inset-block-end: 0;
    inset-inline-start: 0;
    inline-size: 0;
    block-size: 2px;
    background-color: var(--color-accent);
    transition: inline-size var(--motion-standard) var(--ease-standard);
  }

  /* The rule draws itself on hover: a measurement being taken, not a flourish. */
  .card--project:hover .card__media::after,
  .card--project:focus-within .card__media::after { inline-size: 100%; }
}

.card__meta-sep { margin-inline: 0.35em; color: var(--color-text-muted); }
