/* The public pages: the header, the hero, the work, the sections, the footer.

   Loaded on top of main.css, which holds everything shared with the signed-in
   side. Split because the studio never draws a laptop and the public pages
   never draw a sidebar, and one file carrying both is one file where a change
   to a card in the studio can move a card on the front page.

   Linked once, by `core/base_public.html`. It used to be linked by each page
   instead, and `base_legal.html` did not declare the block - so the privacy and
   cookie pages rendered with no layout at all. A stylesheet that belongs to a
   shell belongs in the shell. */

/* --- The public bar --------------------------------------------------------- */
.public-head {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 24px;
  padding: 12px 24px;
  background: rgb(255 255 255 / 0.88);
  /* The blur is the reason the bar can be translucent and still legible over a
     screenshot scrolling under it. Where it is unsupported the rgba ground is
     opaque enough on its own. */
  backdrop-filter: saturate(1.6) blur(10px);
  border-bottom: 1px solid var(--line);
}
.public-brand { flex: none; }
.public-nav { display: flex; gap: 22px; margin-left: auto; }
.public-nav a {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--ink-muted); font-size: 0.92rem; font-weight: 550;
  padding: 4px 0; border-bottom: 2px solid transparent;
}
.public-nav a:hover { color: var(--brand); border-bottom-color: var(--brand); text-decoration: none; }
.public-nav .icon { width: 0.95rem; height: 0.95rem; }
.public-actions { display: flex; align-items: center; gap: 14px; }
.public-phone {
  display: inline-flex; align-items: center; gap: 9px;
  color: var(--brand); font-size: 0.82rem;
}
.public-phone:hover { text-decoration: none; }
.public-phone span { display: flex; flex-direction: column; line-height: 1.25; }
.public-phone small { color: var(--ink-faint); font-size: 0.72rem; }

@media (max-width: 1080px) {
  .public-nav { display: none; }
  .public-actions { margin-left: auto; }
}
@media (max-width: 720px) {
  .public-head { padding: 10px 14px; gap: 12px; }
  .public-phone span { display: none; }
}

/* Below here the bar has more in it than the window is wide, and something has
   to give before the whole document starts scrolling sideways. At 350px this
   row wanted 437px - a wordmark, a number, two languages and a way in - and
   because the header sets the document's width, every other section on the page
   was dragged out with it and the cookie bar at the foot went widest of all.
   That is the sideways scrollbar, and it was never the cookie bar's doing.

   What goes is words, in the order they can be spared; every control stays
   where it was and stays reachable. */
@media (max-width: 520px) {
  .public-head { gap: 10px; }
  .public-actions { gap: 10px; }
  .public-actions .btn { padding: 8px 10px; }
  /* The glyph is the button now. Hidden the way a label is hidden and never
     with `display: none` - a link with nothing in it but an aria-hidden icon
     has no name at all - so the words are still read out, and `title` on the
     link names it for a long press. */
  .public-actions .btn-text {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
}

/* The last of the width, on the phones that actually have 350px. The switcher
   keeps its flags and drops the two letters beside them: the language name is
   already in the switcher's own visually-hidden span and in each button's
   `title`, so nothing is lost that was being read out. */
@media (max-width: 420px) {
  .brand-logo { height: 26px; }
  .public-actions .lang-code { display: none; }
  .public-actions .lang-option { padding: 5px 7px; }
}

/* --- Shared section furniture ------------------------------------------------ */
.inner { max-width: var(--measure); margin: 0 auto; padding: 0 24px; }
.section { padding: 76px 0; }
.section-tinted { background: var(--canvas); border-block: 1px solid var(--line); }
.section-head { max-width: 720px; margin: 0 auto 44px; text-align: center; }
.section-head .lede { margin: 0; }
.article-page aside.inner {
  margin-top: 40px;
  padding-top: 16px;
}
.section-head-row {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
  max-width: none; text-align: left;
}
@media (max-width: 720px) {
  .section { padding: 52px 0; }
  .section-head-row { flex-direction: column; align-items: flex-start; }
}

/* --- Hero -------------------------------------------------------------------- */
.hero {
  position: relative;
  padding: 84px 24px 64px;
  text-align: center;
  /* A wash of the logo's own pale blue rather than a flat panel: the mark's
     colours are used where they are only ever a fill, and the text sits on
     white where the contrast is measured. */
  background:
    radial-gradient(1100px 420px at 50% -8%, var(--brand-light), transparent 70%),
    linear-gradient(180deg, var(--brand-tint), var(--surface));
  border-bottom: 1px solid var(--line);
}
.hero-inner { max-width: 860px; margin: 0 auto; }
.hero-eyebrow {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 14px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line-strong);
  color: var(--ink-muted); font-size: 0.8rem; font-weight: 600;
  margin-bottom: 22px;
}
.hero h1 { margin-bottom: 18px; }
/* The one place the pale logo blue carries a word - and it is a word inside a
   heading at 3rem, where 3:1 is the standard for large text rather than 4.5. */
.hero h1 .accent { color: var(--logo-blue); }
.hero .lede { max-width: 620px; margin: 0 auto 30px; font-size: 1.16rem; }
.hero-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.hero-points {
  list-style: none; padding: 0; margin: 34px 0 0;
  display: flex; gap: 26px; justify-content: center; flex-wrap: wrap;
  font-size: 0.9rem; color: var(--ink-muted);
}
.hero-points li { display: flex; align-items: center; gap: 8px; }
.hero-points .icon { color: var(--ok); }

.hero-stats {
  display: flex; justify-content: center; gap: 12px; flex-wrap: wrap;
  max-width: 720px; margin: 48px auto 0; padding: 0;
}
.hero-stats > div {
  flex: 1 1 180px;
  padding: 16px 20px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.hero-stats dt {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--ink-faint); font-weight: 700;
}
.hero-stats dd { margin: 4px 0 0; font-size: 1.4rem; font-weight: 700; color: var(--brand); }

/* --- The hall of fame -------------------------------------------------------- */
.work-grid { display: grid; gap: 34px; }
.work-card {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 40px; align-items: center;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.work-card:hover { box-shadow: var(--shadow-lg); border-color: var(--brand-light); }
/* Alternating sides, so five cards down the page do not read as five rows of
   the same table. `:nth-child(even) .device { order: 2 }` would need the grid to
   be direction-aware; swapping the column instead keeps the source order, which
   is what a screen reader follows. */
.work-card:nth-child(even) .device { order: 2; }
@media (max-width: 900px) {
  .work-card { grid-template-columns: 1fr; gap: 24px; padding: 20px; }
  .work-card:nth-child(even) .device { order: 0; }
}
/* Neither the card nor the laptop in it may insist on its own width.
   A grid item's `min-width: auto` is its min-content width, and this one's
   min-content came from the address printed on the browser bar inside the
   picture - `admin.iconaccounting.ie`, set in a monospace face and told not to
   wrap. That floor propagated all the way out: the laptop grew past the card,
   the card past its column, and on a 350px screen the whole document came with
   it, which is what put a sideways scrollbar under every page. The address is
   already given `text-overflow: ellipsis` further down and could have been
   shortened at any point; it was never allowed to be. */
.work-card, .device { min-width: 0; }

/* --- The laptop --------------------------------------------------------------
   Drawn in CSS around a plain screenshot rather than composited into the image.
   The screenshot can then be replaced from the admin without matching a frame,
   it costs no extra pixels, and the lid scales with the column instead of being
   a fixed-width picture of a lid. */
.device { margin: 0; }
.device-lid {
  padding: 10px 10px 12px;
  background: linear-gradient(160deg, #2b3440, #171d26);
  border-radius: 14px 14px 6px 6px;
  box-shadow:
    0 22px 40px rgb(16 24 40 / 0.22),
    inset 0 0 0 1px rgb(255 255 255 / 0.08);
}
.device-screen {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  background: var(--surface);
  /* The screenshots are 16:10, which is a laptop's ratio. Fixed here so a card
     keeps its shape while an image is still loading - without it the whole row
     jumps when the picture arrives. */
  aspect-ratio: 1280 / 845;
}
/* The browser bar, so the address is part of the picture rather than a caption
   under it. 45px of the 845 above; the screenshot fills the rest. */
.device-chrome {
  display: flex; align-items: center; gap: 6px;
  height: 45px; padding: 0 14px;
  background: linear-gradient(180deg, #f4f5f7, #e8eaee);
  border-bottom: 1px solid #d8dbe0;
}
.device-chrome .dot { width: 10px; height: 10px; border-radius: 50%; background: #ff5f57; }
.device-chrome .dot:nth-child(2) { background: #febc2e; }
.device-chrome .dot:nth-child(3) { background: #28c840; }
.device-url {
  margin-left: 12px; padding: 3px 14px;
  background: #fff; border-radius: 999px;
  font-family: var(--mono); font-size: 0.68rem; color: #5c6672;
  /* `min-width: 0` is what makes the ellipsis reachable. Without it this flex
     item's automatic minimum is the whole address, so the bar never gets narrow
     enough to trim anything - it widens its way out through the picture, the
     card and the page instead. The three properties beside it were the visible
     half of the intent; this is the half that lets them happen. */
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.device-screen img {
  display: block; width: 100%; height: calc(100% - 45px);
  /* `top` rather than `center`: a screenshot cropped from the middle loses the
     header, which is the part that identifies the site. */
  object-fit: cover; object-position: top center;
}
.device-blank {
  display: flex; align-items: center; justify-content: center;
  height: calc(100% - 45px); color: var(--ink-faint); background: var(--canvas);
}
/* The wedge under the lid, with the notch a MacBook has in its front edge. */
.device-base {
  position: relative;
  height: 13px;
  margin: 0 -18px;
  background: linear-gradient(180deg, #c9ced6, #9aa2ad);
  border-radius: 0 0 10px 10px;
  box-shadow: 0 8px 18px rgb(16 24 40 / 0.18);
}
.device-notch {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 84px; height: 6px;
  background: #8b939e;
  border-radius: 0 0 7px 7px;
}

/* --- What a card says -------------------------------------------------------- */
.work-body { min-width: 0; }
.work-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.work-head h3 { margin: 0; font-size: 1.35rem; }
.platform-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  font-size: 0.74rem; font-weight: 650;
  background: var(--brand-light); color: var(--brand);
}
.platform-wordpress { background: #e5eef5; color: #21759b; }
.work-summary { font-size: 1.02rem; }
.stack-chips {
  list-style: none; display: flex; flex-wrap: wrap; gap: 7px;
  padding: 0; margin: 16px 0 20px;
}
.stack-chips li {
  padding: 3px 10px; border-radius: 6px;
  background: var(--canvas); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 0.75rem; color: var(--ink-muted);
}
.work-actions { display: flex; gap: 10px; flex-wrap: wrap; }

.work-cta {
  display: flex; align-items: center; justify-content: space-between; gap: 28px;
  margin-top: 40px; padding: 26px 30px;
  background: linear-gradient(135deg, var(--brand-tint), var(--brand-light));
  border: 1px solid var(--brand-light);
  border-radius: var(--radius);
}
.work-cta h3 { display: flex; align-items: center; gap: 9px; margin: 0 0 4px; }
.work-cta p { margin: 0; }
.work-cta-actions { display: flex; gap: 10px; flex-wrap: wrap; flex: none; }
@media (max-width: 780px) { .work-cta { flex-direction: column; align-items: flex-start; } }

/* --- Services and steps ------------------------------------------------------ */
.feature-grid {
  display: grid; gap: var(--gap);
  /* `min(280px, 100%)` and not a bare 280px: a track floor is a floor even
     when the window is narrower than it, and on a 320px screen a 280px
     minimum plus the section's own gutters is wider than the page - which
     the page then becomes. `min()` lets the last card give up its floor
     rather than the document giving up its width. */
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}
.feature {
  padding: 26px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.feature:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); border-color: var(--brand-light); }
/* The mark and the heading on one line. Stacked, each card was three rows deep
   before the sentence that carries the meaning - a tile, then a heading under
   it, then the words. Side by side the icon reads as a bullet for its own
   heading, and the card is two rows: what it is, and what that means. */
.feature-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.feature-mark {
  display: inline-flex; align-items: center; justify-content: center;
  /* `flex: none` because a long heading would otherwise squeeze the tile out of
     square - it is a flex item now, and a 38px box with nothing to stop it
     shrinking is a 38px box that becomes 20px next to "Deployment and hosting". */
  width: 38px; height: 38px; flex: none;
  border-radius: 11px;
  background: var(--brand-light); color: var(--brand);
  font-size: 1.05rem;
}
.feature h3 { margin: 0; }
.feature p { margin: 0; color: var(--ink-muted); font-size: 0.95rem; }

.steps {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  counter-reset: step;
}
.steps li { position: relative; padding: 24px; border-top: 3px solid var(--brand-light); }
/* Same change as the features above, and for the same reason: the number is a
   label for the heading beside it, not a heading of its own. */
.step-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.step-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex: none; border-radius: 50%;
  background: var(--brand); color: #fff;
  font-size: 0.82rem; font-weight: 700;
}
.steps h3 { margin: 0; font-size: 1.05rem; }
.steps p { margin: 0; font-size: 0.94rem; }

/* --- Posts ------------------------------------------------------------------- */
.post-grid {
  display: grid; gap: var(--gap);
  /* Same floor, same reason as `.feature-grid` above. */
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
}
.post-card {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.post-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.post-cover { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--canvas); }
.post-cover img { width: 100%; height: 100%; object-fit: cover; }
.post-card-body { padding: 20px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.post-card-body h3 { margin: 0; font-size: 1.1rem; }
.post-card-body h3 a { color: var(--ink); }
.post-card-body h3 a:hover { color: var(--brand); text-decoration: none; }
.post-card-body p { margin: 0; font-size: 0.92rem; }
.post-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 0; }
/* The row has a gap; a link inside it is one flex item and needs its own. */
.post-meta a { display: inline-flex; align-items: center; gap: 5px; }

.tag-chips { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; padding: 0; margin: auto 0 0; }
.tag-chips a {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 11px; border-radius: 999px;
  background: var(--canvas); border: 1px solid var(--line);
  font-size: 0.78rem; color: var(--ink-muted);
}
.tag-chips a:hover, .tag-chips a.is-active {
  background: var(--brand-light); border-color: var(--brand-light);
  color: var(--brand); text-decoration: none;
}

.blog-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; margin-bottom: 30px;
}
.search-form { position: relative; display: flex; gap: 8px; align-items: center; }
/* The box wants 260px so the search bar does not read as an afterthought beside
   the heading - but it was asking with `min-width`, which is a demand, and on a
   320px screen the box plus its button demanded more than the window had. As a
   flex basis the 260 is a preference: it holds wherever there is room and gives
   way to the button where there is not. */
.search-form .control { padding-left: 36px; flex: 1 1 260px; min-width: 0; }
.search-icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--ink-faint); pointer-events: none; display: flex;
}
.pager { display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: 40px; }

/* --- One post ---------------------------------------------------------------- */
.article-page { padding: 56px 0 76px; }
.article { max-width: 760px; margin: 0 auto; padding: 0 24px; }
.article-head { margin-bottom: 28px; }
.article-head .post-meta { margin-bottom: 14px; }
.article-byline { display: flex; align-items: center; gap: 12px; margin-top: 20px; flex-wrap: wrap; }
.article-byline > div:not(.article-langs) { display: flex; flex-direction: column; line-height: 1.3; }
.article-langs { margin-left: auto; display: flex; gap: 8px; }
.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: linear-gradient(135deg, var(--brand), var(--brand-dark));
  color: #fff; font-weight: 700; font-size: 0.9rem; flex: none;
}
.article-cover { width: 100%; height: auto; border-radius: var(--radius); margin-bottom: 28px; }
.article-tags { margin-top: 32px; }

/* The post body. `markish` emits p, h2, ul, strong, code and a - nothing else -
   so this is the complete list of what can appear here. */
.prose { font-size: 1.06rem; line-height: 1.75; }
.prose h2 { margin: 32px 0 10px; font-size: 1.4rem; }
.prose p { margin: 0 0 18px; }
.prose ul { margin: 0 0 18px; padding-left: 22px; }
.prose li { margin-bottom: 6px; }
.prose code { font-size: 0.9em; }
.prose img.inline-image-300 {
  float: right; width: 300px; height: auto; margin: 0 0 14px 22px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--canvas);
  box-shadow: 0 14px 28px rgb(0 0 0 / 0.08);
}
@media (max-width: 600px) {
  .prose img.inline-image-300 {
    float: none; display: block; width: min(220px, 68vw); margin: 0 auto 18px;
  }
}

/* --- Forms as pages ---------------------------------------------------------- */
.form-page { max-width: 1000px; }
.form-layout { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: 32px; align-items: start; }
@media (max-width: 860px) { .form-layout { grid-template-columns: 1fr; } }
.form-privacy { margin: 12px 0 0; text-align: center; }
.contact-aside h2 { font-size: 1.05rem; margin-bottom: 14px; }
.demo-points { list-style: none; padding: 0; margin: 0 0 24px; display: grid; gap: 10px; }
.demo-points li { display: flex; align-items: flex-start; gap: 9px; font-size: 0.93rem; }
.demo-points .icon { color: var(--ok); margin-top: 4px; }
.demo-product {
  padding: 14px 16px; margin-bottom: 12px;
  background: var(--canvas); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.demo-product h3 { font-size: 0.98rem; margin-bottom: 4px; }
.demo-product p { margin-bottom: 6px; }

/* --- About ------------------------------------------------------------------- */
.section-about { background: var(--canvas); border-top: 1px solid var(--line); }
.about-inner { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 48px; align-items: start; }
.about-inner .hero-actions { justify-content: flex-start; margin-top: 24px; }
@media (max-width: 860px) { .about-inner { grid-template-columns: 1fr; gap: 32px; } }
.about-facts { list-style: none; padding: 0; margin: 0; display: grid; gap: 14px; }
.about-facts li { display: flex; align-items: flex-start; gap: 12px; }
.about-facts .icon { color: var(--brand); margin-top: 4px; }
.about-facts strong { display: block; font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-faint); }

/* --- Legal documents ---------------------------------------------------------- */
.legal { max-width: 800px; margin: 0 auto; padding: 56px 24px 76px; }
.legal-head { padding-bottom: 24px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.legal-updated { display: flex; align-items: center; gap: 7px; font-size: 0.82rem; color: var(--ink-faint); margin: 12px 0 0; }
.legal-section { padding: 28px 0; border-bottom: 1px solid var(--line-soft); }
.legal-section h2 { font-size: 1.25rem; margin-bottom: 12px; }
.legal-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 9px; }
.legal-list li { display: flex; align-items: flex-start; gap: 9px; font-size: 0.95rem; }
.legal-list .icon { color: var(--brand); margin-top: 5px; }
.legal-more { padding-top: 28px; }
.legal-more h2 { font-size: 1rem; }
.legal-nav { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 16px; }
.legal-nav li { display: flex; align-items: center; gap: 7px; font-size: 0.9rem; }
.legal-nav .icon { color: var(--ink-faint); }
.legal .table { font-size: 0.88rem; }
.legal .table td { vertical-align: top; }

/* --- The footer ---------------------------------------------------------------
   In the flow of the page. The old one was `fixed-bottom`, so it covered the
   last two lines of every page permanently. */
.site-footer { background: var(--ink); color: #c4ccd6; padding: 56px 0 0; }
.footer-main {
  display: grid; gap: 36px;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  max-width: var(--measure); margin: 0 auto; padding: 0 24px 40px;
}
@media (max-width: 880px) { .footer-main { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .footer-main { grid-template-columns: 1fr; } }
.footer-col h2 {
  font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: #8d97a3; margin-bottom: 14px;
}
.footer-brand .brand-logo {
  /* No filter. The old raster was a single ink and had to be flattened to white
     to be seen here; the SVG carries both brand tones, and #769FCD measures
     4.4:1 against this footer's ground - so it is legible as itself, and the
     pale strapline stays pale instead of disappearing into the wordmark. */
  height: 54px;
  margin-bottom: 14px;
}
.footer-links, .footer-contact, .site-footer .legal-nav {
  list-style: none; padding: 0; margin: 0; display: grid; gap: 10px;
}
.site-footer .legal-nav { display: grid; }
.footer-contact li { display: flex; align-items: flex-start; gap: 9px; font-size: 0.88rem; }
.site-footer a { color: #dbe3ec; font-size: 0.9rem; }
.site-footer a:hover { color: #fff; }
.site-footer .icon { color: #7f8b98; margin-top: 4px; }
.footer-base {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  max-width: var(--measure); margin: 0 auto; padding: 18px 24px 26px;
  border-top: 1px solid rgb(255 255 255 / 0.08);
  font-size: 0.82rem; color: #8d97a3;
}
.footer-registers { display: flex; align-items: center; gap: 10px; }
.footer-registers a { font-size: 0.82rem; }

/* --- Keeping the footer down ---------------------------------------------------
   A short page - a policy, a single post, a 404 - is shorter than the viewport,
   and without this the footer ends halfway down with white under it, which reads
   as the page having failed to finish loading.

   On <body class="public"> only. The studio has its own full-height grid and the
   sign-in screen centres a card in the viewport; applying it to every <body>
   would fight both. */
body.public { min-height: 100vh; display: flex; flex-direction: column; }
body.public .public-main { flex: 1; }

/* --- Error pages ----------------------------------------------------------------
   `.empty` already centres a glyph over a line of text; these add the room a
   whole page needs, where the empty state is a panel inside one. */
.error-page { padding: 72px 24px; }
.error-page h1 { margin: 8px 0 4px; }
.error-page .lede { max-width: 480px; }
.error-page .hero-actions { margin-top: 22px; }

/* --- The "not a robot" box -------------------------------------------------------
   A panel rather than a loose checkbox, so the last thing read before pressing
   Send looks like a step rather than an afterthought floating under the message
   box. `core/field.html` puts the input inside its own label, which is what
   makes the words clickable - the row here only has to hold it. */
.confirm-human {
  padding: 12px 14px;
  margin-bottom: 16px;
  background: var(--canvas);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.confirm-human .field { margin-bottom: 0; }
.confirm-human .field > label { margin-bottom: 0; font-weight: 550; }
/* A tick box at the browser's default 13px next to 0.86rem text reads as a
   stray mark; at this size it looks like something to press. */
.confirm-human input[type="checkbox"] { width: 17px; height: 17px; accent-color: var(--brand); }
.confirm-human .field-error { margin-top: 6px; }

/* The proof-of-work line under the tick box: what the browser is doing, in one
   sentence. Three states, and the colour is never the only difference between
   them - the wording says which one it is, because somebody who cannot tell the
   green from the red still has to be able to read the answer. */
.pow-status {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 8px 0 0;
  font-size: 0.78rem;
  color: var(--ink-muted);
}
.pow-status svg { width: 14px; height: 14px; flex: none; }
.pow-status[data-state="done"] { color: var(--ok); }
.pow-status[data-state="failed"] { color: var(--danger); }
.pow-status a { color: inherit; }
