/* Page styles for base/templates/base/group_site.html.
   Moved out of the template unchanged; linked from the same point in the
   page, so these rules still resolve in exactly the order they used to.
   (Since the group's own nav-bar mark landed, this is linked from the head
   rather than from inside `content`: it now dresses the bar, which is rendered
   first, and a stylesheet arriving after that shows the wrong theme's logo for
   a frame.) */

/* --- The group's own nav-bar mark ------------------------------------------
   Two <img> elements, one per theme, of which CSS shows one. The alternative —
   one <picture> with a `prefers-color-scheme` source — cannot work here: dark
   mode in this app is a CLASS on <body> that a theme toggle writes and
   localStorage remembers, and a media query cannot see it. A visitor who chose
   dark on a light-set machine would get the light logo on the dark bar.

   Sized by HEIGHT with width auto, like the app bar's own wordmark: tenants
   upload marks of every proportion, and letting an upload's width drive the
   layout lets one of them push the nav links off the row. The intrinsic
   width/height on each <img> come from the stored header, so the box is
   reserved before the bytes arrive and the bar does not jump.

   `max-width` keeps a very wide wordmark from doing it anyway — at that point
   the mark shrinks below 46px rather than the bar breaking. */
.gs-navlogo {
  display: block;
  height: 46px;
  width: auto;
  max-width: min(260px, 42vw);
  object-fit: contain;
  object-position: left center;
}
/* Light is the default face, so the dark one is the one that hides. Stated in
   this order so a page that somehow loses its theme class still shows a mark
   rather than none. */
.gs-navlogo--dark { display: none; }
body.dark-mode .gs-navlogo--light { display: none; }
body.dark-mode .gs-navlogo--dark { display: block; }

@media (max-width: 768px) {
  .gs-navlogo { height: 36px; max-width: 45vw; }
}

  /*
    The same full-viewport hero the deployment's own landing page uses
    (.hero-container in site.css, background image and all) — a group site
    should feel like a site, not like a list. The clamp() sizing is lifted from
    aboutus.html for the same reason it exists there: site.css's bare 8.5rem
    title overflows a phone, and a tenant name is usually longer than "Geronimo
    IoT", so the title clamps a little smaller here.
*/
  /* The top padding is zeroed ONLY for a page that opens on a hero — see the
     `.gs-hero-first` rule near the foot of this file. It used to be zeroed here
     for every page that links this sheet, whether or not it had a hero to fill
     the space, which put the <h2> of the Dashboards / Maps / Analytics listings
     (and of any site whose first section is not a hero) underneath the 62px
     fixed bar: clipped glyph-tops, then untitled cards (operator, 2026-09-04).
     Neither escape hatch reached them — `gs-dressed` is emitted by `bar_class`
     alone, and those pages wear the site's own `body_class`. With this gone the
     clearance falls back to site.css's `.page-content` (96px / 86px), which is
     what every other page of the shell gets. */
  /* A hero that brings its own imagery (single photo or backdrop slides) must
     not show the platform's default photograph underneath while its own
     picture downloads — the default is a cached static file and won the race
     every time (operator, 2026-09-04). The slide then loads over the page
     colour, which reads as loading rather than as the wrong site. */
  main .hero-container.gs-hero--own { background-image: none; }
  /* …except on a platform page that only WEARS the bar (bar_class emits
     gs-dressed): there the platform's own clearance must survive this sheet, or
     the fixed bar sits on the page header. Values mirror site.css
     (.page-content: 96px, 86px under 768px). Kept ABOVE the gs-logo-* rules:
     a taller logo's bigger padding wins the specificity tie by order. */
  .gs-dressed .page-content { padding-top: 96px; }
  @media (max-width: 768px) { .gs-dressed .page-content { padding-top: 86px; } }
  main .hero-container {
    width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
    min-height: 100vh; overflow: hidden;
  }
  .hero-text { width: min(1300px, 100%); margin: 0 auto;
               padding: 0 clamp(16px, 5vw, 72px) 8vh; box-sizing: border-box; }
  .hero-text h1 { margin: 0; line-height: 0.95; }
  .hero-text .hero-kicker {
    display: block; font-size: clamp(0.85rem, 1.6cqw, 1.15rem); line-height: 1.4;
    /* Not bold, not capitals, by default (2026-08-27): a kicker is plain text
       the author formats like any paragraph — B, or the Aa toggle for caps. */
    margin-bottom: clamp(8px, 1.5vh, 20px);
  }
  .hero-text .hero-title {
    display: block; font-size: clamp(2.4rem, 7cqw, 6rem); line-height: 1.03;
    /* break-word, NOT anywhere: `anywhere` feeds min-content sizing, so a
       brand name that FIT the line still broke mid-word on a 390px hero —
       "Geroni / mo IoT" (audit L1-1/L4-2, 2026-09-07). break-word keeps the
       overflow safety and only splits a word longer than the whole line. */
    overflow-wrap: break-word;
  }
  .hero-text .hero-sub {
    max-width: 46ch; margin: clamp(12px, 2vh, 24px) 0 0;
    font-size: clamp(1rem, 1.9cqw, 1.375rem); line-height: 1.5; font-weight: 400;
  }
  /* The landing page's measure: a real screen's width, not a column. It used
     to say "max-w-6xl" because that was what the home page's sections were
     set to; both are the shell's ordinary measure now, so a tenant's public
     site and the platform's own front page still line up. */
  .gs-wrap { max-width: var(--nh-page-measure, 1400px); margin: 0 auto; padding: 48px 24px 64px; }
  .gs-preview {
    border: 1px solid var(--warning); background: var(--warning-tint); color: var(--warning-ink);
    border-radius: var(--r-md); padding: 12px 16px; margin-bottom: 24px; font-size: 0.9rem;
  }
  .gs-hero { padding: 8px 0 28px; border-bottom: 1px solid var(--line); margin-bottom: 28px; }
  .gs-hero h1 { font-size: 2.4rem; margin: 0 0 6px; color: var(--ink); }
  .gs-hero .tagline { font-size: 1.1rem; color: #2887b1; font-weight: 600; margin: 0 0 14px; }
  .gs-hero .about { color: var(--ink-2); font-size: 1rem; line-height: 1.6; max-width: 70ch;
                    white-space: pre-wrap; margin: 0; }
  .gs-sec { margin-bottom: 36px; }
  .gs-sec h2 { font-size: 0.78rem; font-weight: inherit; color: var(--ink-3); margin: 0 0 14px; }
  .gs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
             gap: 16px; }
  .gs-card {
    display: block; text-decoration: none; color: inherit; background: var(--surface);
    border: 1px solid var(--line); border-radius: var(--r-md); padding: 18px 20px;
    transition: border-color .15s, box-shadow .15s, transform .12s;
  }
  .gs-card:hover { border-color: var(--accent-ring); box-shadow: 0 4px 14px rgba(40,135,177,.12);
                   transform: translateY(-2px); }
  .gs-card h3 { margin: 0 0 4px; font-size: 1.05rem; color: var(--ink); }
  .gs-card p { margin: 0; font-size: 0.86rem; color: var(--ink-3); line-height: 1.45; }
  .gs-card .count { display: block; margin-top: 8px; font-size: 0.75rem; color: var(--ink-3); }
  .gs-empty { color: var(--ink-3); font-size: 0.92rem; }
  .gs-links { display: flex; gap: 12px; flex-wrap: wrap; }
  .gs-link {
    display: inline-flex; align-items: center; gap: 10px; text-decoration: none;
    padding: 12px 20px; border-radius: var(--r-md); font-weight: 600; font-size: 0.95rem;
    background: var(--accent); color: #fff; border: 1px solid rgba(255,255,255,.18);
  }
  .gs-link:hover { background: var(--accent); }
  .gs-link--quiet { background: var(--surface-2); color: var(--ink-2); border-color: var(--line); }
  .gs-link--quiet:hover { background: var(--surface-2); }
  .gs-foot { margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--line);
             color: var(--ink-3); font-size: 0.82rem; }
  @media (max-width: 640px) {
    .gs-hero h1 { font-size: 1.8rem; }
    .gs-link { width: 100%; justify-content: center; }
  }

/* --- The owner-built page (site_layout blocks) ------------------------------
   Same tokens as the rest of the shell, so a section reads in both themes
   without a second palette. The card rules deliberately reuse the landing
   page's `.svc-*` names (aboutus.css is NOT loaded here — it wants Tailwind
   Play — so the few rules a card needs are restated). */
.gs-hero--photo { background-size: cover; background-position: center; background-repeat: no-repeat; }
.gs-hero--photo .hero-text { text-shadow: 0 1px 12px rgba(0,0,0,.45); }
/* Titles carry no weight or letter-case of their own (2026-08-27): whatever
   the author set on the text — the same B / Aa / size / colour a paragraph
   gets — is what shows. Existing layouts were migrated to explicit bold so
   nothing already published changed. */
.gs-h2 { font-size: clamp(1.6rem, 3.2cqw, 2.4rem); font-weight: inherit; color: var(--ink);
         margin: 0 0 14px; font-family: 'Sen', var(--font-ui), sans-serif; }
.gs-intro { font-size: 1.1rem; color: var(--ink-2); max-width: 60ch; margin: 0 0 28px; line-height: 1.55; }
.gs-intro--center { margin-left: auto; margin-right: auto; }
.gs-prose p { font-size: 1.1rem; line-height: 1.65; color: var(--ink-2); margin: 0 0 1rem; max-width: 70ch; }
.gs-prose p:last-child { margin-bottom: 0; }
.gs-text--with-image { display: grid; grid-template-columns: 3fr 2fr; gap: 40px; align-items: start; }
.gs-text--image-left { grid-template-columns: 2fr 3fr; }
.gs-text--image-left .gs-text__figure { order: -1; }
.gs-text__figure { margin: 0; }
.gs-text__figure img { width: 100%; height: auto; border-radius: var(--r-md); border: 1px solid var(--line); }
.gs-steps { border: 1px solid var(--line); background: var(--surface-2); border-radius: 1rem; padding: 2rem; max-width: 640px; }
.gs-steps__head { font-size: 0.8rem; font-weight: inherit; color: #a86d12; margin: 0 0 1.25rem; }
.gs-steps__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.gs-steps__title { font-weight: inherit; color: var(--ink); }
.gs-steps__text { color: var(--ink-2); }
.gs-band { background: var(--surface-2); width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); }
/* `.gs-cards` is the card section's outer element whether or not it is a band
   (site_layout CARD_BANDS): the band's grey full-bleed strip is one class, the
   section's generous vertical rhythm is this rule, and turning the strip off
   must not also flatten the section against its neighbours. */
.gs-band .gs-wrap, .gs-cards > .gs-wrap { padding-top: 56px; padding-bottom: 56px; }
.gs-cardgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: 24px; }
/* An explicit column count (site_layout CARD_COLUMNS). `auto-fill` gives four
   columns at the 1400px measure; aboutus.html says `lg:grid-cols-3` and gets
   three, and until these existed there was no way to say so in the studio.
   `minmax(0, 1fr)` rather than `1fr`: a grid track's automatic minimum is its
   content, so one long unbreakable word in a card would otherwise widen its
   column and push the row past the page. */
.gs-cardgrid--1 { grid-template-columns: minmax(0, 1fr); }
.gs-cardgrid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gs-cardgrid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gs-cardgrid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.svc-card { display: flex; flex-direction: column; padding: 1.75rem; border: 1px solid var(--line);
            border-radius: 1rem; background: var(--surface); box-shadow: 0 1px 3px rgba(0,0,0,.06);
            transition: box-shadow .2s, transform .2s; }
.svc-card:hover { box-shadow: 0 10px 24px rgba(0,0,0,.10); transform: translateY(-2px); }
.svc-card__img { width: 100%; height: 160px; object-fit: cover; border-radius: 0.6rem; margin-bottom: 1rem; }
.svc-title { font-size: 1.15rem; font-weight: inherit; color: var(--ink); margin: 0 0 0.75rem; }
/* `list-style: disc` is explicit because base.html loads Tailwind's preflight,
   which resets every <ul> to no marker — the landing page's aboutus.css
   restores it, this file did not, and the bullets vanished on the real page.

   The list is a BLOCK, and it does not grow. It used to be
   `display: grid; gap: .35rem; flex: 1`, which is the whole of the "bullets
   are spread out in the studio" report (2026-08-29): `flex: 1` stretched the
   list to whatever height the card's tallest neighbour forced on it, and a
   grid with auto rows distributes its spare height BETWEEN the rows — so a
   card with three bullets beside one with five got loose, ragged spacing
   between its bullets and no space at the bottom. aboutus.css never did this
   (a plain block list with `li { margin-bottom }`), which is why the real
   landing page always looked right and the studio's copy of it did not.

   Slack belongs to the CARD, at the end: the list keeps its natural spacing,
   and `.svc-link`'s `margin-top: auto` pushes the "… →" link — the one thing
   that should line up across a row — to the bottom of the card. A card with no
   link simply ends early, which is what the equal-height grid is for. */
.svc-list { margin: 0; padding-left: 1.1rem; color: var(--ink-2); line-height: 1.5;
            display: block; flex: 0 0 auto; list-style: disc; }
.svc-list li { display: list-item; margin-bottom: 0.35rem; }
.svc-list li:last-child { margin-bottom: 0; }
.svc-link { margin-top: auto; padding-top: 1rem; font-weight: 600; color: var(--link); text-decoration: none; }
.svc-link:hover { text-decoration: underline; }
.gs-figure { margin: 0 auto; }
.gs-figure--medium { max-width: 720px; }
.gs-figure img { width: 100%; height: auto; border-radius: var(--r-md); border: 1px solid var(--line); }
.gs-figure figcaption { text-align: center; color: var(--ink-3); font-size: 0.9rem; margin-top: 8px; }
.gs-linkgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr)); gap: 14px; }
.gs-card--link { display: flex; align-items: center; gap: 12px; font-weight: 600; }
.gs-card--link i { font-size: 1.4rem; color: var(--accent); width: 1.6rem; text-align: center; }
.gs-cta { text-align: center; padding-top: 64px; padding-bottom: 64px; }
.gs-buttons { display: flex; flex-wrap: wrap; gap: 14px; margin-top: clamp(16px, 3vh, 28px); }
.gs-buttons--center { justify-content: center; }
.gs-btn { display: inline-block; padding: 12px 30px; border-radius: 999px; font-weight: 700; text-decoration: none;
          transition: background .15s, border-color .15s; }
.gs-btn--primary { background: #1f6d8f; color: #fff; border: 2px solid #1f6d8f; }
.gs-btn--primary:hover { background: #175571; border-color: #175571; }
.gs-btn--secondary { background: transparent; color: var(--ink); border: 2px solid var(--line-strong); }
.gs-btn--secondary:hover { border-color: var(--ink-3); }
.gs-hero--photo .gs-btn--secondary { color: #fff; border-color: rgba(255,255,255,.7); }
.gs-footer__platform { margin-top: 6px; }
@media (max-width: 768px) {
  .gs-text--with-image, .gs-text--image-left { grid-template-columns: 1fr; }
  .gs-text--image-left .gs-text__figure { order: 0; }
}


/* --- side-by-side sections (site_layout: columns) ---------------------------- */
.gs-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: start; }
.gs-columns--wide-left { grid-template-columns: 3fr 2fr; }
.gs-columns--wide-right { grid-template-columns: 2fr 3fr; }
/* A proportion the three named splits do not name (site_layout SPAN_MIN/MAX),
   written by dragging the divider between the halves in the studio. Twelfths,
   so the drag snaps to a grid and a row is always one of nine classes rather
   than an inline width — which is also what keeps this out of a style
   attribute. Stated AFTER the named splits so a span wins the tie, and BEFORE
   the container query below so a phone still stacks them. */
.gs-columns--span-2  { grid-template-columns: 2fr 10fr; }
.gs-columns--span-3  { grid-template-columns: 3fr 9fr; }
.gs-columns--span-4  { grid-template-columns: 4fr 8fr; }
.gs-columns--span-5  { grid-template-columns: 5fr 7fr; }
.gs-columns--span-6  { grid-template-columns: 6fr 6fr; }
.gs-columns--span-7  { grid-template-columns: 7fr 5fr; }
.gs-columns--span-8  { grid-template-columns: 8fr 4fr; }
.gs-columns--span-9  { grid-template-columns: 9fr 3fr; }
.gs-columns--span-10 { grid-template-columns: 10fr 2fr; }
/* A half is a section without the page frame: the row already has it. */
.gs-columns .gs-wrap { max-width: none; padding: 0; margin: 0; }
.gs-columns .gs-sec { margin-bottom: 0; }
.gs-columns .gs-band { width: auto; margin-left: 0; margin-right: 0; border-radius: 12px; }
.gs-columns .gs-band .gs-wrap { padding: 24px; }
.gs-columns .gs-cardgrid { grid-template-columns: 1fr; }
@media (max-width: 800px) { .gs-columns, .gs-columns--wide-left, .gs-columns--wide-right { grid-template-columns: 1fr; gap: 28px; } }

/* --- the owner's typography (site_layout: brand.font / brand.text_size) ------ */
/* Local stacks only: the page must not fetch a font from a third party. */
.gs-font-humanist { font-family: "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; }
.gs-font-serif { font-family: Georgia, "Times New Roman", Times, serif; }
.gs-font-slab { font-family: "Roboto Slab", Rockwell, "Courier New", Georgia, serif; }
.gs-font-rounded { font-family: Nunito, "Trebuchet MS", "Segoe UI", Verdana, sans-serif; }
.gs-font-mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; }

/* --- the owner's typography on a DRESSED page (site_layout.bar_class) -------
   A published dashboard / map / analytics page wears the group's bar, not its
   page (operator, 2026-09-03: the group's page background and text scale must
   not restyle a chart the group did not author). Type is carried the same
   narrow way: the bar, the page's own heading and the footer take the group's
   face; the plot, the map, the legend and every control stay on the platform's.

   Note the selectors are the chrome's, not `body`'s — inheriting from <body>
   would put the face on the whole document, which is exactly the thing the bar
   subset exists to avoid. `system` emits no class at all, so an unbranded page
   matches none of this. */
.gs-barfont-humanist .navbar, .gs-barfont-humanist .page-head,
.gs-barfont-humanist > main > .page-content > h1, .gs-barfont-humanist .gs-footer
  { font-family: "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; }
.gs-barfont-serif .navbar, .gs-barfont-serif .page-head,
.gs-barfont-serif > main > .page-content > h1, .gs-barfont-serif .gs-footer
  { font-family: Georgia, "Times New Roman", Times, serif; }
.gs-barfont-slab .navbar, .gs-barfont-slab .page-head,
.gs-barfont-slab > main > .page-content > h1, .gs-barfont-slab .gs-footer
  { font-family: "Roboto Slab", Rockwell, "Courier New", Georgia, serif; }
.gs-barfont-rounded .navbar, .gs-barfont-rounded .page-head,
.gs-barfont-rounded > main > .page-content > h1, .gs-barfont-rounded .gs-footer
  { font-family: Nunito, "Trebuchet MS", "Segoe UI", Verdana, sans-serif; }
.gs-barfont-mono .navbar, .gs-barfont-mono .page-head,
.gs-barfont-mono > main > .page-content > h1, .gs-barfont-mono .gs-footer
  { font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; }
/* site.css pins `.navbar *` to 'Sen' with !important, so the bar's own links
   need the same weapon to follow the group's choice. Scoped to the bar under a
   `gs-barfont-*` body, which nothing but a branded dressed page carries. */
.gs-barfont-humanist .navbar * { font-family: inherit !important; }
.gs-barfont-serif .navbar *    { font-family: inherit !important; }
.gs-barfont-slab .navbar *     { font-family: inherit !important; }
.gs-barfont-rounded .navbar *  { font-family: inherit !important; }
.gs-barfont-mono .navbar *     { font-family: inherit !important; }
.gs-font-humanist .hero-title, .gs-font-serif .hero-title, .gs-font-slab .hero-title,
.gs-font-rounded .hero-title, .gs-font-mono .hero-title,
.gs-font-humanist .gs-h2, .gs-font-serif .gs-h2, .gs-font-slab .gs-h2,
.gs-font-rounded .gs-h2, .gs-font-mono .gs-h2 { font-family: inherit; }
/* Size scales the reading text and the headings together; the nav bar stays. */
.gs-size-s  { --gs-scale: 0.9; }
.gs-size-m  { --gs-scale: 1; }
.gs-size-l  { --gs-scale: 1.15; }
.gs-size-xl { --gs-scale: 1.32; }
.gs-body .gs-prose p, .gs-body .gs-intro, .gs-body .svc-list, .gs-body .gs-steps__text,
.gs-body .gs-steps__title, .gs-body .hero-sub, .gs-body .gs-figure figcaption,
.gs-body .gs-card--link, .gs-body .gs-empty, .gs-body .gs-footer { font-size: calc(1rem * var(--gs-scale, 1)); }
.gs-body .gs-h2, .gs-body .gs-steps__head { font-size: calc(1.6rem * var(--gs-scale, 1)); }
.gs-body .svc-title { font-size: calc(1.15rem * var(--gs-scale, 1)); }
.gs-body .hero-title { font-size: calc(3rem * var(--gs-scale, 1)); }
.gs-body .hero-kicker { font-size: calc(0.95rem * var(--gs-scale, 1)); }

/* --- inline formatting (site_layout runs → base/templatetags/site_rich.py) --- */
.rt-b { font-weight: 700; }
.rt-i { font-style: italic; }
/* Explicit weight / letter-case runs. A span's own font-weight and
   text-transform beat what it inherits from a heading, which is the point:
   a title is bold and a kicker is uppercase by default, and either can be
   turned off per run from the toolbar. */
.rt-w-normal { font-weight: 400; }
.rt-w-bold { font-weight: 700; }
.rt-caps-on { text-transform: uppercase; letter-spacing: 0.12em; }
.rt-caps-off { text-transform: none; letter-spacing: normal; }
.rt-font-system { font-family: inherit; }
.rt-font-humanist { font-family: "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; }
.rt-font-serif { font-family: Georgia, "Times New Roman", Times, serif; }
.rt-font-slab { font-family: "Roboto Slab", Rockwell, "Courier New", Georgia, serif; }
.rt-font-rounded { font-family: Nunito, "Trebuchet MS", "Segoe UI", Verdana, sans-serif; }
.rt-font-mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; }
.rt-size-s { font-size: 0.85em; }
.rt-size-l { font-size: 1.2em; }
.rt-size-xl { font-size: 1.5em; }
.rt-size-xxl { font-size: 2em; }
.rt-hl-yellow { background: #fff3a8; color: #1f2937; padding: 0 .15em; border-radius: 3px; }
.rt-hl-green  { background: #d4f5c8; color: #1f2937; padding: 0 .15em; border-radius: 3px; }
.rt-hl-blue   { background: #cfe8ff; color: #1f2937; padding: 0 .15em; border-radius: 3px; }
.rt-hl-pink   { background: #ffd6e7; color: #1f2937; padding: 0 .15em; border-radius: 3px; }
.rt-hl-orange { background: #ffe0b8; color: #1f2937; padding: 0 .15em; border-radius: 3px; }
.rt-hl-gray   { background: #e5e7eb; color: #1f2937; padding: 0 .15em; border-radius: 3px; }

/* --- backgrounds (site_layout BACKGROUNDS): sections and the page ---------- */
.gs-bg { --gs-bg: transparent; --gs-ink: inherit; background: var(--gs-bg); color: var(--gs-ink); }
.gs-bg-paper  { --gs-bg: #faf7f0; }
.gs-bg-mist   { --gs-bg: #f1f5f9; }
.gs-bg-sand   { --gs-bg: #f6e7c8; }
.gs-bg-sky    { --gs-bg: #dbeafe; }
.gs-bg-sage   { --gs-bg: #dcefe3; }
.gs-bg-forest { --gs-bg: #1f3d2b; --gs-ink: #f3f7f4; }
.gs-bg-ink    { --gs-bg: #111827; --gs-ink: #f3f4f6; }
.gs-bg-forest .gs-h2, .gs-bg-forest .gs-steps__head, .gs-bg-forest .svc-title, .gs-bg-forest .gs-intro, .gs-bg-forest .gs-prose p,
.gs-bg-ink .gs-h2, .gs-bg-ink .gs-steps__head, .gs-bg-ink .svc-title, .gs-bg-ink .gs-intro, .gs-bg-ink .gs-prose p,
.gs-bg-forest .gs-steps__text, .gs-bg-ink .gs-steps__text, .gs-bg-forest .gs-steps__title, .gs-bg-ink .gs-steps__title { color: var(--gs-ink); }
.gs-bg-forest .svc-card, .gs-bg-ink .svc-card { background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.15); color: var(--gs-ink); }
/* A coloured section spans the whole width like the card band does; its
   content keeps the measure — written off the token so a full-bleed section's
   text still lines up with the sections above and below it. The 24px floor is
   the gutter on a screen narrower than the measure. */
section.gs-wrap.gs-bg { max-width: none;
  padding-left:  max(24px, calc(50% - var(--nh-page-measure) / 2));
  padding-right: max(24px, calc(50% - var(--nh-page-measure) / 2)); }
.gs-columns .gs-wrap.gs-bg { padding: 24px; border-radius: 12px; }

/* --- a section stretched by dragging its corner ---------------------------
   `--gs-secw` is a percentage written by site_layout.sec_style, absent unless
   the owner has actually dragged (10..100, clamped server-side). A percentage
   rather than a computed width because it has to mean the same thing in three
   different parents: the page, a column half (where .gs-columns .gs-wrap drops
   the measure entirely) and a full-bleed coloured band.

   Named `--gs-secw`, and it MUST NOT be `--gs-scale`: that name is the
   site-wide text-size MULTIPLIER (`.gs-size-l { --gs-scale: 1.15 }` above),
   consumed by `calc(… * var(--gs-scale, 1))` on every title. When this width
   briefly shared the name (2026-09-06..07), a dragged section's inline
   `--gs-scale:60%` inherited into those calcs, which are invalid with a
   percentage factor — so every title inside a dragged section fell back to
   its INHERITED size (a dragged hero's title measured 136px against the 48px
   it was set to). That is the operator's "my size gets overridden by the
   site settings", and it is why these two customisations each keep a name.

   Two rules because a colour is a decision that the BAND spans the page. So a
   plain section narrows itself, and a coloured one keeps its band and narrows
   the content inside it — both answering the one question the drag asks, "how
   wide is this section's content". Stated after `section.gs-wrap.gs-bg` above
   and at the same specificity, so the later rule wins. */
section.gs-wrap.gs-scaled { max-width: var(--gs-secw); margin-left: auto; margin-right: auto; }
section.gs-wrap.gs-bg.gs-scaled { max-width: none;
  padding-left:  max(24px, calc(50% - var(--gs-secw) / 2));
  padding-right: max(24px, calc(50% - var(--gs-secw) / 2)); }
/* A hero is a .hero-container, not a .gs-wrap: its text column is what narrows,
   so the photograph behind it still spans the page. */
.hero-container.gs-scaled .hero-text { max-width: var(--gs-secw); margin-left: auto; margin-right: auto; }

/* --- the hero TEXT BOX, dragged by its own right-edge handle ---------------
   `--gs-herobox` / `gs-herobox` come from site_layout (`box`, 30..100, stored
   only once the owner has dragged the handle on the box itself). Two things
   change together, deliberately: the box takes the dragged width, AND the
   sub's 46ch typographic cap comes off — the DRAGGED BOX is the measure now,
   which is what makes the operator's "more wide, less tall" true (2026-09-07:
   before this, widening a hero could never push the sub past 46 characters,
   so the drag appeared to do nothing). Height has no knob on purpose: it
   follows the content, wider = shorter.

   Stated AFTER the gs-scaled rule above at equal specificity: a hero that
   still carries a legacy section-corner `scale` and a box width obeys the
   box, which is the handle the operator actually touched last (the studio
   clears `scale` from a hero when its box is dragged). */
.hero-container.gs-herobox .hero-text { max-width: var(--gs-herobox); margin-left: auto; margin-right: auto; }
.hero-container.gs-herobox .hero-text .hero-sub { max-width: none; }
/* On a phone every section is the width of the screen: a 30% column that was
   a deliberate choice on a desktop is unreadable at 380px. The hero box too —
   a phone's 380px is already narrower than any box the desktop drag chose, so
   the box goes back to full width and the sub keeps the released measure. */
@media (max-width: 700px) {
  section.gs-wrap.gs-scaled { max-width: none; }
  section.gs-wrap.gs-bg.gs-scaled { padding-left: 16px; padding-right: 16px; }
  .hero-container.gs-scaled .hero-text { max-width: none; }
  .hero-container.gs-herobox .hero-text { max-width: none; }
}
.hero-container.gs-bg { background-color: var(--gs-bg); }
.hero-container.gs-bg-paper, .hero-container.gs-bg-mist, .hero-container.gs-bg-sand, .hero-container.gs-bg-sky, .hero-container.gs-bg-sage { color: #1f2937; }
.hero-container.gs-bg-paper .hero-title, .hero-container.gs-bg-mist .hero-title, .hero-container.gs-bg-sand .hero-title,
.hero-container.gs-bg-sky .hero-title, .hero-container.gs-bg-sage .hero-title,
.hero-container.gs-bg-paper .hero-sub, .hero-container.gs-bg-mist .hero-sub, .hero-container.gs-bg-sand .hero-sub,
.hero-container.gs-bg-sky .hero-sub, .hero-container.gs-bg-sage .hero-sub { color: inherit; }
.gs-page-paper  { background: #faf7f0; }
.gs-page-mist   { background: #f1f5f9; }
.gs-page-sand   { background: #f6e7c8; }
.gs-page-sky    { background: #dbeafe; }
.gs-page-sage   { background: #dcefe3; }
.gs-page-forest { background: #1f3d2b; color: #f3f7f4; }
.gs-page-ink    { background: #111827; color: #f3f4f6; }
.gs-page-forest .gs-h2, .gs-page-ink .gs-h2, .gs-page-forest .gs-steps__head, .gs-page-ink .gs-steps__head,
.gs-page-forest .gs-prose p, .gs-page-ink .gs-prose p, .gs-page-forest .gs-intro, .gs-page-ink .gs-intro,
.gs-page-forest .gs-steps__text, .gs-page-ink .gs-steps__text, .gs-page-forest .gs-steps__title, .gs-page-ink .gs-steps__title { color: inherit; }

/* --- the nav bar's face, link colour and logo size (brand.nav_bg / nav_link / logo_size) --- */
.gs-navbg-white .navbar  { background-color: rgba(255,255,255,.92); }
.gs-navbg-paper .navbar  { background-color: rgba(250,247,240,.94); }
.gs-navbg-mist .navbar   { background-color: rgba(241,245,249,.94); }
.gs-navbg-sky .navbar    { background-color: rgba(219,234,254,.94); }
.gs-navbg-sage .navbar   { background-color: rgba(220,239,227,.94); }
.gs-navbg-forest .navbar { background-color: rgba(31,61,43,.92); }
.gs-navbg-ink .navbar    { background-color: rgba(17,24,39,.92); }
/* --brand-blue-deep, not the logo blue: this bar's links are white by
   default and white on #2887b1 is 4.05:1, under AA. Mirrored in
   site_editor.css so the studio preview shows the real colour. */
.gs-navbg-blue .navbar   { background-color: rgba(31,109,143,.94); }
/* Automatic link colour: ink on a light bar, white on a dark one. */
.gs-navbg-white .nav-links a, .gs-navbg-paper .nav-links a, .gs-navbg-mist .nav-links a,
.gs-navbg-sky .nav-links a, .gs-navbg-sage .nav-links a,
.gs-navbg-white .nav-logo, .gs-navbg-paper .nav-logo, .gs-navbg-mist .nav-logo,
.gs-navbg-sky .nav-logo, .gs-navbg-sage .nav-logo,
.gs-navbg-white .nav-toggle, .gs-navbg-paper .nav-toggle, .gs-navbg-mist .nav-toggle,
.gs-navbg-sky .nav-toggle, .gs-navbg-sage .nav-toggle { color: #1f2937; }
.gs-navlink-white .nav-links a { color: #ffffff; }
.gs-navlink-ink .nav-links a   { color: #1f2937; }
.gs-navlink-muted .nav-links a { color: #94a3b8; }
.gs-navlink-blue .nav-links a  { color: #2887b1; }
.gs-navlink-gold .nav-links a  { color: #cb8616; }
/* Explicit heights: .gs-navlogo sets height:46px, so a max-height can never
   enlarge it. A taller bar needs more room above the page content too. */
.gs-logo-s .gs-navlogo, .gs-logo-s .nav-logo img  { height: 32px; max-height: 32px; width: auto; }
.gs-logo-m .gs-navlogo, .gs-logo-m .nav-logo img  { height: 46px; max-height: 46px; width: auto; }
.gs-logo-l .gs-navlogo, .gs-logo-l .nav-logo img  { height: 70px; max-height: 70px; width: auto; }
.gs-logo-xl .gs-navlogo, .gs-logo-xl .nav-logo img { height: 96px; max-height: 96px; width: auto; }
.gs-logo-l .page-content { padding-top: 120px; }
.gs-logo-xl .page-content { padding-top: 146px; }
/* An exact height: `--gs-logo-h` is set on <body> by site_layout.body_style
   (validated 16-160px). The page's top padding follows it by the same ~50px
   the presets use (46->96, 70->120, 96->146), and on a phone the logo is
   capped at 44px exactly like the large presets. */
.gs-logo-custom .gs-navlogo, .gs-logo-custom .nav-logo img { height: var(--gs-logo-h, 46px); max-height: var(--gs-logo-h, 46px); width: auto; }
.gs-logo-custom .page-content { padding-top: calc(var(--gs-logo-h, 46px) + 50px); }
@media (max-width: 768px) {
  .gs-logo-l .gs-navlogo, .gs-logo-xl .gs-navlogo, .gs-logo-l .nav-logo img, .gs-logo-xl .nav-logo img { height: 44px; max-height: 44px; }
  .gs-logo-l .page-content, .gs-logo-xl .page-content { padding-top: 96px; }
  .gs-logo-custom .gs-navlogo, .gs-logo-custom .nav-logo img { height: min(var(--gs-logo-h, 46px), 44px); max-height: min(var(--gs-logo-h, 46px), 44px); }
  .gs-logo-custom .page-content { padding-top: calc(min(var(--gs-logo-h, 46px), 44px) + 52px); }
}
/* A page that opens on a hero has nothing to clear: the hero is a full-viewport
   picture that runs up under the translucent bar, exactly as the deployment's
   own landing page does. With a large logo the two rules above won this fight
   (class+class outranks main.page-content) and put a 120px white band between
   the bar and the photo. `gs-hero-first` is set by site_layout.body_class from
   the first block's type, so a page opening on text keeps its room. */
.gs-hero-first .page-content, .gs-logo-l.gs-hero-first .page-content,
.gs-logo-xl.gs-hero-first .page-content, .gs-logo-custom.gs-hero-first .page-content { padding-top: 0; }

/* --- custom (hex) colours arrive as custom properties ---------------------- */
.gs-bg-custom { background: var(--gs-bg); }
.gs-page-custom { background: var(--gs-page-bg); }
.gs-navbg-custom .navbar { background-color: var(--gs-nav-bg); }
.gs-navlink-custom .nav-links a { color: var(--gs-nav-link); }
.gs-text-custom, .gs-text-custom .gs-h2, .gs-text-custom .gs-steps__head, .gs-text-custom .gs-prose p,
.gs-text-custom .gs-intro, .gs-text-custom .gs-steps__text, .gs-text-custom .gs-steps__title,
.gs-text-custom .svc-title, .gs-text-custom .svc-list, .gs-text-custom .gs-figure figcaption { color: var(--gs-text); }
.rt-hl { padding: 0 .15em; border-radius: 3px; }

/* --- nothing may push past the page: a grid column defaults to min-width:auto,
       which lets long content overflow instead of wrapping (the "long panel
       runs off the page" report, 2026-08-26). --- */
.gs-col, .gs-text__body, .gs-steps, .svc-card, .gs-card { min-width: 0; }
.gs-columns > * { min-width: 0; }
.gs-prose, .gs-steps__text, .gs-steps__title, .svc-list li, .gs-h2, .gs-intro, .hero-sub, .gs-figure figcaption
  { overflow-wrap: anywhere; }
/* The hero title is a NAME, not prose — see the break-word note above. */
.hero-title { overflow-wrap: break-word; }
.gs-wrap, .gs-band { box-sizing: border-box; }
html, body.gs-body { overflow-x: hidden; }

/* --- heading colour (brand.heading_color): every title at once ------------- */
/* Section titles only — the hero over the photo has its own control below.

   THE PRECEDENCE CONTRACT (operator, 2026-09-07: "the manual color change for
   titles gets overrided by the site settings"): a site-wide setting is the
   DEFAULT for untouched text, and anything set on a selection through the
   text toolbar beats it. The mechanism, per property, so nobody "fixes" one
   side with !important:
   - colour/size: a formatted run carries them as an INLINE style on its own
     <span> (site_rich._run_html / site_editor runHtml), which no stylesheet
     rule can outrank — so these rules, which target only the heading
     ELEMENTS, colour exactly the text that has no colour of its own;
   - bold: expressed as classes (rt-b / rt-w-*) on the run, so the heading
     elements must not set font-weight themselves — see the .gs-body
     .hero-text h1 rule below and `font-weight: inherit` on .gs-h2/.svc-title.
   Never extend these selectors to the runs (no `… .gs-h2 span`), and never
   put a colour/size on a title element with !important: either one silently
   breaks the toolbar for every site. */
.gs-heading-custom .gs-h2, .gs-heading-custom .gs-steps__head, .gs-heading-custom .svc-title,
.gs-heading-custom .gs-sec h2, .gs-heading-custom .gs-steps__title { color: var(--gs-heading); }
/* The bold half of that contract, for the hero. site.css (which the published
   page loads and the studio canvas does not) says `.hero-text h1 { font-weight:
   bold }` for the platform's own landing hero; on a group's page that filled
   the gap an UN-bolded run leaves — the canvas showed regular, the published
   title snapped back to bold (2026-09-07). Titles have carried their bold as
   explicit runs since migration 0176, so giving the h1 a plain base weight
   changes nothing an owner has not asked for. */
.gs-body .hero-text h1 { font-weight: 400; }
/* The hero's DEFAULT text colour, stated here so the studio shows what the
   published page shows. Live, the title inherits `color: white` from site.css's
   .hero-container; the studio canvas does not load site.css, so the same title
   previewed dark grey and published white — which reads as a colour that
   cannot be changed (operator, 2026-09-02: "ensure user can adjust color of
   main title on landing page rn i think its stuck on white"). It can: per-word
   through the text toolbar, or site-wide through "Hero title colour" in the
   Site panel. Both override this, and so do the light background classes above,
   which carry more specificity. */
.hero-container { color: #fff; }
/* …and the picture the white is written on. The default hero photograph lives
   on `.hero-container` in site.css, and the studio canvas extends main.html,
   which does not link that sheet — so the studio's first section was white text
   on a white page: invisible, and with nothing to click, unselectable
   (operator, 2026-09-04). Restated here rather than linking site.css into the
   signed-in shell, which would restyle the app's own bar and page. Relative on
   purpose, like site.css's copy: a relative url() resolves against THIS
   stylesheet, so it follows STATIC_URL and collectstatic rewrites it to the
   hashed name. A hero with its own picture still overrides it below. */
.hero-container {
  background-image: url("../../images/geronimo-iot-background.b23f8126baea.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* The `main .hero-container.gs-hero--own` rule at the top of this file kills
   the default for a hero that brings its own imagery; that selector needs a
   <main> ancestor, which the published page and the studio canvas both have,
   but the class pair alone is stated here too so the override can never be the
   thing that depends on where the section is rendered. */
.hero-container.gs-hero--own { background-image: none; }

/* --- hero title colour (brand.hero_color): the title and kicker over the big picture --- */
.gs-hero-custom .hero-text .hero-title, .gs-hero-custom .hero-text .hero-kicker { color: var(--gs-hero); }

/* --- a coloured section colours the WHOLE thing ----------------------------
   The steps box and the cards paint their own surface over the section, so a
   background looked like a strip behind a white card. Inside a coloured
   section the steps box goes transparent (one continuous colour, its border a
   faint line of the text colour) and each card becomes a translucent tint of
   the section, so the grid still reads as cards. Dark presets keep their
   own card treatment (defined above). */
.gs-bg .gs-steps { background: transparent; border-color: rgba(0,0,0,.12); max-width: none; }
.gs-bg-forest .gs-steps, .gs-bg-ink .gs-steps { border-color: rgba(255,255,255,.18); }
.gs-bg .svc-card { background: rgba(255,255,255,.55); border-color: rgba(0,0,0,.10); box-shadow: none; }
.gs-bg .gs-card { background: rgba(255,255,255,.55); border-color: rgba(0,0,0,.10); }
.gs-bg .gs-card--link { background: rgba(255,255,255,.55); }
.gs-bg-forest .svc-card, .gs-bg-ink .svc-card, .gs-bg-forest .gs-card, .gs-bg-ink .gs-card { background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.15); }
.gs-bg .gs-band .gs-wrap { background: transparent; }

/* --- the section box: spacing, minimum height, alignment --------------------
   site_layout.section_classes emits these; every value is a key from
   SECTION_PADS / SECTION_HEIGHTS / SECTION_ALIGNS, so there is a class here
   for each one and nothing else can arrive. Each rule names TWO selectors —
   the class on a plain section (which is itself the `.gs-wrap`) and the class
   on a band or card section (whose padding lives on an inner `.gs-wrap`) — so
   one setting behaves the same whichever shape the section happens to be.
   Stated after `.gs-band .gs-wrap` so an explicit choice beats the default. */
.gs-pad-none, .gs-pad-none > .gs-wrap { padding-top: 0; padding-bottom: 0; }
.gs-pad-s,    .gs-pad-s    > .gs-wrap { padding-top: 20px;  padding-bottom: 24px; }
.gs-pad-l,    .gs-pad-l    > .gs-wrap { padding-top: 76px;  padding-bottom: 88px; }
.gs-pad-xl,   .gs-pad-xl   > .gs-wrap { padding-top: 112px; padding-bottom: 128px; }

.gs-minh-s      { min-height: 240px; }
.gs-minh-m      { min-height: 420px; }
.gs-minh-l      { min-height: 640px; }
/* svh with a vh fallback, for the reason aboutus.css states at .hero-container:
   a vh-only minimum on a phone measures the screen WITHOUT the URL bar. */
.gs-minh-screen { min-height: 100vh; min-height: 100svh; }
/* A section given a minimum height becomes a column box, so "middle" and
   "bottom" have something to push against. A columns row is already a grid and
   must stay one — it aligns its two halves with align-items instead. */
.gs-minh:not(.gs-columns) { display: flex; flex-direction: column; }
.gs-minh:not(.gs-columns).gs-align-center { justify-content: center; }
.gs-minh:not(.gs-columns).gs-align-bottom { justify-content: flex-end; }
.gs-columns.gs-align-center { align-items: center; }
.gs-columns.gs-align-bottom { align-items: end; }

.gs-dashboard__open { margin-top: 8px; }

/* --- slideshows (site_layout._slides; base/_site_slides.html) ---------------
   Two variants of one component. A `backdrop` is a layer behind a section's
   content; a `gallery` is the content. Both stack their slides and show the
   one carrying `is-on` — which the MARKUP puts on the first slide, so the
   picture is there whether or not static/js/site_slideshow.js ever runs. */
.nh-slides { position: relative; }
.nh-slides__list { list-style: none; margin: 0; padding: 0; }
.nh-slides__slide { position: absolute; inset: 0; margin: 0; opacity: 0; visibility: hidden; }
.nh-slides__slide.is-on { opacity: 1; visibility: visible; }
.nh-slides--fade .nh-slides__slide { transition: opacity .9s ease, visibility 0s linear .9s; }
.nh-slides--fade .nh-slides__slide.is-on { transition: opacity .9s ease, visibility 0s; }
.nh-slides__img { width: 100%; height: 100%; display: block; }
.nh-slides--fit-cover .nh-slides__img { object-fit: cover; object-position: center; }
.nh-slides--fit-contain .nh-slides__img { object-fit: contain; }
.nh-slides__cap {
  position: absolute; left: 0; right: 0; bottom: 0; margin: 0; padding: 10px 16px;
  color: #fff; font-size: 0.9rem; background: linear-gradient(transparent, rgba(0,0,0,.6));
}

/* Behind the section: a full-bleed layer, with the section's own content
   lifted above it. `isolation` keeps the stacking context local, so a section
   with a backdrop cannot paint over the nav bar. */
.gs-hasbackdrop { position: relative; isolation: isolate; }
.gs-hasbackdrop > *:not(.nh-slides) { position: relative; z-index: 1; }
.nh-slides--backdrop { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.nh-slides--backdrop .nh-slides__list { position: absolute; inset: 0; }
/* Pictures behind words need the words to stay legible whatever the picture
   is: the same scrim the hero photograph gets, over every backdrop. */
.nh-slides--backdrop::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(rgba(0,0,0,.28), rgba(0,0,0,.48));
}
.gs-hasbackdrop .hero-text, .gs-hasbackdrop .gs-h2, .gs-hasbackdrop .gs-intro,
.gs-hasbackdrop .gs-prose p, .gs-hasbackdrop .gs-steps__text,
.gs-hasbackdrop .gs-steps__title, .gs-hasbackdrop .gs-empty { color: #f8fafc; }
.gs-hasbackdrop .hero-text { text-shadow: 0 1px 12px rgba(0,0,0,.45); }

/* As the content: a framed picture the section is built around. */
.nh-slides--gallery { aspect-ratio: 16 / 9; border-radius: var(--r-md);
                      overflow: hidden; border: 1px solid var(--line); background: var(--surface-2); }
.nh-slides--gallery .nh-slides__list { position: absolute; inset: 0; }

/* The controls. Rendered by the script, so they exist only where they work. */
.nh-slides__nav, .nh-slides__dots, .nh-slides__pause { position: absolute; z-index: 3; }
.nh-slides__nav { inset: 0; display: flex; align-items: center; justify-content: space-between;
                  padding: 0 8px; pointer-events: none; }
.nh-slides__btn {
  pointer-events: auto; width: 34px; height: 46px; border: none; border-radius: var(--r-sm);
  background: rgba(0,0,0,.42); color: #fff; font-size: 1.4rem; line-height: 1; cursor: pointer;
  opacity: .55; transition: opacity .15s;
}
.nh-slides__btn:hover, .nh-slides__btn:focus-visible { opacity: 1; }
.nh-slides__dots { left: 0; right: 0; bottom: 10px; display: flex; justify-content: center; gap: 6px; }
.nh-slides--gallery .nh-slides__dots { bottom: 10px; }
.nh-slides__dot { width: 9px; height: 9px; border-radius: 50%; border: none; padding: 0;
                  background: rgba(255,255,255,.55); cursor: pointer; }
.nh-slides__dot.is-on { background: #fff; }
.nh-slides__pause {
  top: 10px; right: 10px; min-width: 32px; height: 28px; border: none; border-radius: var(--r-sm);
  background: rgba(0,0,0,.42); color: #fff; font-size: .8rem; cursor: pointer; opacity: .55;
  transition: opacity .15s;
}
.nh-slides__pause:hover, .nh-slides__pause:focus-visible { opacity: 1; }
.nh-slides__cap { padding-bottom: 26px; }
@media (prefers-reduced-motion: reduce) {
  /* The script starts no timer under this query (site_slideshow.js REDUCED);
     this is the other half — a picture the person steps to by hand cuts
     rather than fades. */
  .nh-slides--fade .nh-slides__slide,
  .nh-slides--fade .nh-slides__slide.is-on { transition: none; }
}

/* A gallery shown all at once. */
.gs-gallerygrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 16px; }
.gs-gallerygrid__cell { margin: 0; }
.gs-gallerygrid__cell img { width: 100%; aspect-ratio: 4 / 3; border-radius: var(--r-md);
                            border: 1px solid var(--line); background: var(--surface-2); display: block; }
.gs-gallerygrid__cell--cover img { object-fit: cover; }
.gs-gallerygrid__cell--contain img { object-fit: contain; }
.gs-gallerygrid__cell figcaption { color: var(--ink-3); font-size: 0.88rem; margin-top: 6px; }

/* --- container queries: the studio's phone/tablet views reflow like devices --
   The media queries above see the VIEWPORT, so a narrowed canvas never
   switched to the mobile layout. These mirror them against the nearest size
   container: the studio canvas (#seCanvas), or on the real page the content
   column, whose inline size is the viewport's minus the page margin — the
   navbar sits outside it and keeps its own media queries. */
.gs-body .page-content { container-type: inline-size; }
@container (max-width: 800px) {
  .gs-columns, .gs-columns--wide-left, .gs-columns--wide-right { grid-template-columns: 1fr; gap: 28px; }
}
@container (max-width: 900px) {
  /* An explicit three or four across is a DESKTOP instruction: below this a
     card is narrower than its own text. Two, then one at 768px with the rest. */
  .gs-cardgrid--3, .gs-cardgrid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (max-width: 768px) {
  .gs-wrap { padding-left: 16px; padding-right: 16px; }
  .gs-cardgrid--2, .gs-cardgrid--3, .gs-cardgrid--4 { grid-template-columns: minmax(0, 1fr); }
  /* A section told to be tall is told so for a desktop composition; on a phone
     it would be an empty screen the visitor has to scroll past. */
  .gs-minh-l { min-height: 420px; }
  .nh-slides--gallery { aspect-ratio: 4 / 3; }
  section.gs-wrap.gs-bg { padding-left: 16px; padding-right: 16px; }
  .gs-text--with-image, .gs-text--image-left { grid-template-columns: 1fr; }
  .gs-text--image-left .gs-text__figure { order: 0; }
  .gs-cardgrid { grid-template-columns: 1fr; }
  .gs-linkgrid { grid-template-columns: 1fr 1fr; }
  .gs-steps { padding: 1.25rem; }
  .hero-text { padding-bottom: 8vh; }
}
@container (max-width: 640px) {
  .gs-hero h1 { font-size: 1.8rem; }
  .gs-link { width: 100%; justify-content: center; }
  .gs-buttons { flex-direction: column; align-items: stretch; }
  .gs-buttons .gs-btn { text-align: center; }
  .gs-linkgrid { grid-template-columns: 1fr; }
}

/* The site title beside the mark in a group's bar (2026-09-01). The studio has
   always let an owner type one; this is where it shows on the live site.
   Inherits the bar's link colour so it stays readable on whichever nav_bg was
   chosen, and truncates rather than pushing the links off a phone. */
.gs-navtitle {
  font-weight: 700;
  font-size: clamp(0.95rem, 2.2vw, 1.2rem);
  line-height: 1.1;
  color: inherit;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: min(48vw, 22rem);
}
@media (max-width: 600px) { .gs-navtitle { max-width: 42vw; } }

/* A picture in a card: cropped to fill by default, or shown whole. Cropping
   cuts the top and bottom off anything portrait — a logo, a person — so the
   choice is the author's (2026-09-02). */
.svc-card__img--contain { object-fit: contain; background: rgba(0,0,0,.03); }
.svc-card__img--cover   { object-fit: cover; }

/* And the same choice for a standalone picture, whose default is the opposite:
   it IS the content, so it shows whole unless asked to fill. */
/* `cover` needs a HEIGHT to crop against. The base rule is
   `.gs-figure img { height: auto }`, so object-fit had nothing to work with and
   "Fill the frame" rendered identically to "Show the whole picture" — the
   option did nothing at all (2026-09-02 audit). A viewport-relative band, so a
   filled picture is a banner on any screen rather than a fixed pixel height. */
.gs-figure--cover img   { object-fit: cover; width: 100%; height: clamp(220px, 38vh, 460px); }
.gs-figure--contain img { object-fit: contain; }

/* A link with no label is its icon. Sized to be a comfortable target rather
   than a word-shaped card, since there is no word in it. */
.gs-card--icon {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 3.2rem; padding: 0.75rem;
}
.gs-card--icon i { font-size: 1.5rem; }
.gs-footer__icon { display: inline-flex; align-items: center; padding: 0 0.35rem; }

/* --- calendar section (community events) ---------------------------------- */
/* An upcoming-events list, deliberately plain: no grid, no month view. The
   date leads in the muted ink, the title carries the row, place and note hang
   under it. Colours ride the same tokens as the rest of the page so a group's
   text colour applies here too. */
.gs-cal { list-style: none; margin: 0; padding: 0; max-width: 46rem; }
.gs-cal__event { padding: 0.85rem 0; border-bottom: 1px solid var(--line, rgba(127, 127, 127, 0.25)); }
.gs-cal__event:last-child { border-bottom: 0; }
.gs-cal__date { display: block; font-size: 0.9rem; color: var(--gs-text, var(--ink-2)); opacity: 0.8; }
.gs-cal__title { display: block; font-size: 1.1rem; margin-top: 0.15rem; }
.gs-cal__place { display: block; font-size: 0.95rem; opacity: 0.85; }
.gs-cal__note { margin: 0.3rem 0 0; font-size: 0.95rem; }
.gs-body .gs-cal__title, .gs-body .gs-cal__note { font-size: calc(1.05rem * var(--gs-scale, 1)); }
