/* ---------------------------------------------------------------------------
   RorickTECH hub -- everything this site adds on top of the base template.

   main.css is the template, edited only where it had to be: the accent colour,
   a self-hosted font, and the attribution stripped. Keeping the additions in
   their own file means the next template update is a diff of one file, not an
   archaeology exercise.

   The accent is #ee8b00, sampled straight off the logo.
--------------------------------------------------------------------------- */

:root {
  /* `light dark`, and then a dark theme below that is the light one again.

     Phones in dark mode force-darken pages: the white body is inverted to
     near-black and the photo left alone, which is what "the page is black on
     my phone" is. Chrome's Auto Dark Theme honours the `only light` opt-out
     (verified with AUTODARK=1 in tools/snapshot.mjs), but Samsung Internet's
     forced dark does not know that keyword -- it steps aside only for a page
     that DECLARES dark support here and then applies whatever that page's
     `prefers-color-scheme: dark` styles are. So the page says it supports
     both, and its dark styles re-assert the light palette. Every engine then
     reaches the same place: the site is left to draw itself, and it draws
     itself light. The <meta> in the markup says the same thing, and both are
     set because the meta is read before this file arrives, and because Blink
     follows the computed value here over the meta if they differ. */
  color-scheme: light dark;

  --accent: #ee8b00;
  --accent-dark: #c47300;
  --ink: #5b5b5b;
  --ink-soft: #8a8a8a;
  --rule: rgba(224, 224, 224, 0.75);
  /* The hero sits on a pale photo, so it has its own, much darker, ink. That
     same near-black is what every button on the site is filled with. */
  --hero-ink: #241a12;
  --hero-ink-soft: #4a3b2e;
  /* The fill for every button and the logo disc. The same near-black as the
     hero ink on a wide screen; the stacked layout softens it (see the 980px
     block), where a column of solid black pills on a phone reads as harsh. */
  --button-bg: #241a12;
}

/* The page's "dark theme". Nothing in this file branches on the scheme, so
   the light rules already apply; this block exists so that a browser which
   looks for dark styles before deciding whether to invent its own finds them,
   and so the few things a dark UA sheet would otherwise supply (the canvas
   behind the body, the caret, the form controls) are pinned to the light
   values on purpose rather than by default. */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: light dark;
  }

  html,
  body {
    background: #ffffff;
  }

  body,
  input,
  select,
  textarea {
    caret-color: var(--ink);
    color: var(--ink);
  }

  .feature,
  .box {
    background: #ffffff;
  }

  .feature .image {
    background: #f4f4f4;
  }
}

/* --- the hero ------------------------------------------------------------
   The photo behind this is a pale sunset, so the template's white-on-dark
   header is inverted: near-black text on a light scrim (the scrim is the
   middle background layer, set in main.css next to the wave that changes with
   the breakpoint).

   Measured rather than guessed: the sky runs from luminance 0.10 to 0.61, and
   white text fails at the bright end while dark text fails at the dark end. A
   46-56% white scrim lifts the floor to ~0.46, which puts #241a12 at better
   than 8:1 across the whole image. */

#header {
  color: var(--hero-ink-soft);
  /* Compressed. The template budgeted for a full-screen splash; this is a
     signpost, and the services are the point. The bottom padding still has to
     clear the 460px wave sitting at the foot of it. */
  padding: 4em 0 13em 0;
}

#header h1,
#header h2,
#header h3 {
  color: var(--hero-ink);
}

/* The template's centre line was light grey, for a dark photo. */
#header::before,
#header::after {
  background: rgba(36, 26, 18, 0.18);
}

/* The mark is orange AND white -- roughly the top half of it is white. On a
   white disc that half simply vanished. The disc is dark now, which makes the
   whole mark legible and gives the pale hero something solid to sit on. */
#header .logo {
  align-items: center;
  background: var(--button-bg);
  border-radius: 100%;
  box-shadow: 0 0.5em 2.5em rgba(36, 26, 18, 0.35);
  display: inline-flex;
  font-size: 1em;
  height: 7rem;
  justify-content: center;
  line-height: normal;
  margin: 0 0 1rem 0;
  padding: 0;
  width: 7rem;
}

#header .logo img {
  display: block;
  height: auto;
  width: 68%;
}

#header h1 {
  letter-spacing: 0.02em;
}

#header p {
  margin: 0.4em auto 0 auto;
  max-width: 34em;
  padding: 0 1.5em;
}

/* --- the section buttons -------------------------------------------------
   One per section, generated in lib/page.js. They are the navigation for a
   page with no navigation bar, so they have to work at every width: a centred
   row that wraps, and full-width stacked on a phone where three side by side
   would each be too narrow to read or to hit. */

#header .actions.jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75em;
  justify-content: center;
  margin: 1.75em auto 0 auto;
  max-width: 40em;
  padding: 0 1.5em;
}

#header .actions.jump li {
  margin: 0;
  padding: 0;
}

/* Dark on the pale sky, because orange behind white text is only 2.6:1 and
   these are the one thing on the hero anybody is meant to press. Orange is
   still the accent -- it is the hover, the rules and the hostnames. */
#header .actions.jump .button {
  background: var(--button-bg);
  border: 0;
  color: #ffffff;
  min-width: 9em;
  padding: 0 1.75em;
}

#header .actions.jump .button:hover,
#header .actions.jump .button:focus-visible {
  background: var(--accent);
  color: var(--hero-ink);
}

/* --- the quick links -----------------------------------------------------
   Every live entry by name, straight under the section buttons: one row per
   section, in the same order, generated in lib/page.js. The section buttons
   move you down the page; these leave it.

   Small and pale on purpose. Fourteen more of the dark fill would bury the
   three buttons that are the actual navigation, so these are the quiet tier:
   a wash of white with the hero ink on it (better than 12:1), and the same
   orange on hover as everything else that can be pressed.

   Scoped under #header for the reason the who-bar is: the template's
   `#header a` is an ID selector, and would turn these white. */

/* Wide enough that a section sits on one line on a desktop. `relative` lifts
   the chips above the hero's centre hairline, which is absolutely positioned
   and would otherwise be drawn across whichever chip lands in the middle. */
#header .quick {
  margin: 1.5em auto 0 auto;
  max-width: 56em;
  padding: 0 1.5em;
  position: relative;
  z-index: 1;
}

/* The line between the two tiers: the section buttons above move you down
   the page, the quick links below leave it, and without something between
   them they read as one pile of buttons in two sizes.

   It is the rule from under the section titles -- the same orange bar, the
   same 2.5em by 3px -- with a hairline in the hero ink running out either
   side of it and fading before it gets anywhere. One element, two background
   layers: the bar is painted over the middle of the hairline. Kept narrower
   than the row of buttons above so it sits inside them rather than
   underlining them. */
#header .quick::before {
  background:
    linear-gradient(var(--accent), var(--accent)) center / 2.5em 3px no-repeat,
    linear-gradient(to right,
      rgba(36, 26, 18, 0),
      rgba(36, 26, 18, 0.3) 32%,
      rgba(36, 26, 18, 0.3) 68%,
      rgba(36, 26, 18, 0)) center / 100% 1px no-repeat;
  content: '';
  display: block;
  height: 3px;
  margin: 0 auto 1.25em auto;
  max-width: 22em;
}

/* Inline blocks in a centred line box rather than a flex row, and the reason
   is `text-wrap: balance`. Flex wraps greedily: seven chips in a space that
   holds six gives six and one, and the one sits alone under the rest looking
   like a mistake. Balancing gives four and three. It only works on inline
   content, so that is what these are; a browser without it wraps the greedy
   way, which is merely untidy.

   The zero line height stops the list's own text metrics padding each line
   out, so the spacing is exactly the margins below and nothing else. */
#header .quick ul {
  line-height: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  text-align: center;
  text-wrap: balance;
}

/* Added to the chips' own margins, so the step between two sections is
   wider than the step between two lines of the same one: a row that wraps
   still reads as one group. */
#header .quick ul + ul {
  margin-top: 0.4em;
}

#header .quick li {
  display: inline-block;
  margin: 0.25em 0.15em;
  padding: 0;
  vertical-align: top;
}

#header .quick .chip {
  background: rgba(255, 255, 255, 0.62);
  border: solid 1px rgba(36, 26, 18, 0.2);
  border-radius: 999px;
  color: var(--hero-ink);
  display: block;
  font-size: 0.7em;
  font-weight: 600;
  letter-spacing: 0.03em;
  line-height: 1.2;
  padding: 0.55em 1.15em;
  transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out,
              color 0.2s ease-in-out;
  white-space: nowrap;
}

#header .quick .chip:hover,
#header .quick .chip:focus-visible {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--hero-ink);
}

/* --- who bar -------------------------------------------------------------
   Who this browser is, and the way to stop being them. Small and out of the
   way: it is the least interesting thing on the page until the moment it is
   the only thing you want. */

.whobar {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 1.1em 1.5em;
  font-size: 0.7em;
  letter-spacing: 0.05em;
  color: var(--hero-ink-soft);
}

#header .whobar .who-email {
  max-width: 16em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#header .whobar .who-sep {
  opacity: 0.4;
}

/* Scoped under #header on purpose. "Access" is an <a>, and the template's
   `#header a { color: rgba(255,255,255,0.8) }` is an ID selector -- it beats
   two classes, so an unscoped `.whobar .who-link` left that link white on what
   is now a pale background, i.e. invisible. */
#header .whobar .who-link {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: dotted 1px rgba(36, 26, 18, 0.4);
  color: var(--hero-ink);
  cursor: pointer;
  font: inherit;
  letter-spacing: inherit;
  padding: 0;
}

#header .whobar .who-link:hover,
#header .whobar .who-link:focus-visible {
  border-bottom-color: transparent;
  color: var(--accent-dark);
}

/* --- section dividers ----------------------------------------------------
   Services, then Tools, then Games. The rule does the dividing; the heading
   just says what changed. */

/* There used to be a grey rule ABOVE each heading, which read as a line hanging
   under the previous section's last card. The only rule now is the orange one
   directly beneath the title, which is the thing it is actually dividing. */
.section-head {
  margin: 0 0 3.5em 0;
  padding: 4.5em 0 0 0;
  text-align: center;
}

/* The first one opens the page rather than dividing anything, so it sits
   closer to the header. */
.section-head:first-child {
  padding-top: 0;
}

.section-head h2 {
  color: var(--ink);
  font-size: 1.5em;
  letter-spacing: 0.25em;
  margin: 0;
  text-transform: uppercase;
}

/* Tight against the baseline of the title. The h2 carries the template's line
   height, so the negative top margin is what closes the gap that leaves. */
.section-head h2::after {
  background: var(--accent);
  content: '';
  display: block;
  height: 3px;
  margin: -0.15em auto 0 auto;
  width: 2.5em;
}

/* --- cards ---------------------------------------------------------------
   The template's feature block, with the giant icon-glyph overlay replaced by
   a still that fades into a short clip and eases in on hover. */

.feature {
  margin-bottom: 3em;
}

.feature .image {
  background: #f4f4f4;
  border: 0;
  overflow: hidden;
}

/* Kills the template's dotted underline and its hover colour change on the
   image link -- there is nothing to underline, it is a photo. */
.feature .image,
.feature .image:hover {
  border-bottom: 0;
}

/* The template pins the image at its natural size against one corner of the
   box and lets overflow:hidden crop whatever does not fit -- which works only
   if the file happens to be about the size of the card. Anything larger shows
   a corner of itself. object-fit does the job properly, so any image dropped
   into images/services/ fills the card and crops from the centre.

   The .left/.right selectors are repeated because the template sets `right`
   and `left` at that specificity, and `inset` has to beat them. */
.feature.left .image img,
.feature.right .image img,
.feature .image img,
.feature .image video {
  display: block;
  height: 100%;
  inset: 0;
  min-height: 0;
  min-width: 0;
  object-fit: cover;
  object-position: center;
  position: absolute;
  transition: transform 0.55s cubic-bezier(0.2, 0.7, 0.3, 1),
              opacity 0.35s ease-in-out;
  width: 100%;
  will-change: transform;
}

/* The clip is a picture that moves, nothing more: no hover of its own, no
   click of its own. A click goes through it to the anchor it sits in. */
.feature .image video {
  pointer-events: none;
}

/* The template lays a dotted texture over every .image. It was there to sit
   under a giant icon glyph; over real artwork it just looks like dirt. */
.feature .image::after {
  display: none;
}

.feature .image:hover img,
.feature .image:hover video,
.feature .image:focus-visible img,
.feature .image:focus-visible video {
  transform: scale(1.07);
}

/* The clip sits first in the markup so it paints beneath the still. Nothing
   changes until hub.js has seen it actually start playing and adds
   `has-motion`; from then on hovering fades the still out over it. Layering
   rather than swapping is what avoids a blank frame while the first bytes
   arrive, and it means a clip that never plays changes nothing. */
.feature .image .motion {
  opacity: 0;
}

.feature .image.has-motion:hover .still,
.feature .image.has-motion:focus-visible .still {
  opacity: 0;
}

.feature .image.has-motion:hover .motion,
.feature .image.has-motion:focus-visible .motion {
  opacity: 1;
}

/* A card for something not built yet. Greyed, and not a link -- see
   lib/page.js for why it is not a disabled anchor. */
.feature .image.is-soon img {
  filter: grayscale(0.85) contrast(0.92);
  opacity: 0.75;
}

.feature .image.is-soon:hover img {
  transform: none;
}

/* Title, then the kind of thing it is, then what it does, then the way in.
   Stacked rather than strung along one line: at two columns the old
   name-plus-tag row wrapped awkwardly on the longer names, and a label under
   the title is what it reads as anyway.

   Only the block's POSITION mirrors on a right-image card. The words inside it
   still start at the left, because ragged-left body copy is hard to read and
   there is no reason for half the page to be harder than the other half. */
.feature .content,
.feature.right .content {
  text-align: left;
}

.feature .content h3 {
  color: var(--ink);
  margin: 0;
}

/* Close to the title -- it belongs to it. */
.feature .content .tag {
  color: var(--ink-soft);
  font-size: 0.7em;
  font-weight: 600;
  letter-spacing: 0.18em;
  margin: 0.4em 0 0 0;
  text-transform: uppercase;
}

/* ...and a clear step away from it before the prose starts. */
.feature .content .blurb {
  margin: 1.4em 0 0 0;
}

.feature .content .badge {
  border-radius: 0.5em;
  display: inline-block;
  font-size: 0.85em;
  font-weight: 600;
  letter-spacing: 0.14em;
  margin-left: 0.5em;
  padding: 0.3em 0.8em;
  text-transform: uppercase;
  white-space: nowrap;
}

.feature .content .badge.soon {
  background: rgba(238, 139, 0, 0.12);
  color: var(--accent-dark);
}

.feature .content .badge.private {
  background: rgba(84, 77, 85, 0.1);
  color: #6b636c;
}

.feature .content .go {
  margin: 1.6em 0 0 0;
}

/* The same dark pill as the section buttons at the top of the page. Two
   departures: the template's 15em minimum would be wider than some of the
   cards, and the label is a hostname, so it keeps its own case instead of
   being shouted in caps with letter-spacing pulling it apart. */
.feature .content .go .button {
  background: var(--button-bg);
  font-size: 0.8em;
  letter-spacing: 0.02em;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  padding: 0 1.6em;
  text-overflow: ellipsis;
  text-transform: none;
  white-space: nowrap;
}

.feature .content .go .button:hover,
.feature .content .go .button:focus-visible {
  background: var(--accent);
  color: var(--hero-ink);
}

.feature .content .go .arrow {
  display: inline-block;
  margin-left: 0.5em;
  transition: transform 0.2s ease-in-out;
}

.feature .content .go .button:hover .arrow {
  transform: translateX(0.35em);
}

/* Something not built yet gets the address as plain text. See lib/page.js. */
.feature .content .go .host.muted {
  color: #aaaaaa;
  font-size: 0.8em;
  letter-spacing: 0.04em;
}

/* --- footer --------------------------------------------------------------
   The template's contact form and social row are gone; what is left is one
   line, centred, with room to breathe. */

#footer .closing {
  font-size: 1.35em;
  font-weight: 600;
  letter-spacing: 0.03em;
  margin: 0;
  padding: 1em 0 0 0;
  text-align: center;
}

/* --- the gate, the Access panel and break glass --------------------------
   Plain, centred, and deliberately quiet. Nothing on the sign-in screen hints
   at what is behind it, including how much of it there is. */

body.gated #main,
body.admin #main {
  padding-top: 4em;
}

.gate {
  margin: 0 auto;
  max-width: 26em;
  text-align: center;
}

.gate h2 {
  color: var(--ink);
  font-size: 1.3em;
  letter-spacing: 0.15em;
  margin: 0 0 0.6em 0;
  text-transform: uppercase;
}

.gate .gate-sub {
  color: var(--ink-soft);
  font-size: 0.95em;
  margin: 0 0 2em 0;
}

.gate label {
  color: var(--ink);
  display: block;
  font-size: 0.75em;
  font-weight: 600;
  letter-spacing: 0.15em;
  margin-bottom: 0.75em;
  text-align: left;
  text-transform: uppercase;
}

.gate input[type="email"],
.gate input[type="text"],
.gate input[type="password"] {
  width: 100%;
}

.gate .gate-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.6em;
  letter-spacing: 0.4em;
  text-align: center;
}

.gate .button {
  margin-top: 1.25em;
  width: 100%;
}

.gate .gate-note {
  color: var(--ink-soft);
  font-size: 0.8em;
  line-height: 1.7em;
  margin: 1.5em 0 0 0;
}

.gate .gate-error,
.gate .gate-ok {
  font-size: 0.8em;
  line-height: 1.6em;
  margin: 1em 0 0 0;
  min-height: 1px;
}

.gate .gate-error {
  color: #c0392b;
}

.gate .gate-ok {
  color: #2e7d4f;
}

.gate .gate-error:empty,
.gate .gate-ok:empty {
  margin: 0;
}

.gate .linkbutton {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: dotted 1px;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  padding: 0;
}

.gate .linkbutton:hover {
  border-bottom-color: transparent;
}

.gate .linkbutton[disabled] {
  color: #bbbbbb;
  cursor: default;
}

/* --- Access panel --------------------------------------------------------
   Wider than the gate, because it is tables. Everything in it is written into
   the DOM with textContent; there is no innerHTML path in admin.js. */

.panel {
  margin: 0 auto;
  max-width: 62em;
}

.panel h2 {
  color: var(--ink);
  font-size: 1.3em;
  letter-spacing: 0.15em;
  margin: 0 0 0.3em 0;
  text-transform: uppercase;
}

.panel h3 {
  border-top: solid 1px var(--rule);
  color: var(--ink);
  font-size: 0.85em;
  letter-spacing: 0.18em;
  margin: 3em 0 1em 0;
  padding-top: 1.75em;
  text-transform: uppercase;
}

.panel .note {
  color: var(--ink-soft);
  font-size: 0.85em;
}

/* Every state this warns about is invisible from outside, which is exactly why
   it is worth a coloured box: a gate nobody can pass looks identical to one
   working fine. */
.panel .alert {
  background: rgba(238, 139, 0, 0.08);
  border-left: solid 3px var(--accent);
  font-size: 0.85em;
  line-height: 1.7em;
  margin: 0 0 2em 0;
  padding: 1.25em 1.5em;
}

.panel .alert strong {
  display: block;
  color: var(--accent-dark);
}

.panel .alert span {
  display: block;
  margin-bottom: 1em;
}

.panel .alert span:last-child {
  margin-bottom: 0;
}

.panel .add-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75em;
  margin-bottom: 1.5em;
}

.panel .add-row input {
  flex: 1 1 12em;
}

.panel .add-row .button {
  flex: 0 0 auto;
}

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

.panel table {
  font-size: 0.8em;
  width: 100%;
}

.panel table td,
.panel table th {
  vertical-align: middle;
}

.panel table .actions-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em;
  justify-content: flex-end;
}

.panel table tr.dead {
  opacity: 0.45;
}

.panel .mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
}

.panel .pill {
  border-radius: 0.5em;
  display: inline-block;
  font-size: 0.85em;
  font-weight: 600;
  letter-spacing: 0.05em;
  padding: 0.2em 0.7em;
  white-space: nowrap;
}

.panel .pill[data-tone="good"] { background: rgba(46, 125, 79, 0.12); color: #2e7d4f; }
.panel .pill[data-tone="bad"]  { background: rgba(192, 57, 43, 0.12);  color: #c0392b; }
.panel .pill[data-tone="warn"] { background: rgba(238, 139, 0, 0.14);  color: var(--accent-dark); }
.panel .pill[data-tone="none"] { background: rgba(0, 0, 0, 0.05);      color: var(--ink-soft); }

.panel .button.small {
  font-size: 0.75em;
  height: 2.75em;
  line-height: 2.75em;
  padding: 0 1.25em;
}

.panel .button.danger {
  background: #c0392b;
  color: #ffffff;
}

.panel .button.danger:hover {
  background: #a93226;
}

.panel .invite-out {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75em;
  margin-bottom: 1.5em;
}

.panel .invite-out input {
  flex: 1 1 20em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75em;
}

/* One allowlisted address on the break-glass page. Not scoped to .panel: that
   page puts these inside .gate, where the full-width button rule would
   otherwise stretch "Sign in as this address" across the card. */
.bg-row {
  align-items: center;
  border-bottom: solid 1px var(--rule);
  display: flex;
  gap: 1em;
  justify-content: space-between;
  padding: 1em 0;
  text-align: left;
}

.bg-row b {
  display: block;
  color: var(--ink);
}

.bg-row em {
  color: var(--ink-soft);
  display: block;
  font-size: 0.8em;
  font-style: normal;
  line-height: 1.5em;
}

.gate .bg-row .button {
  margin-top: 0;
  width: auto;
}

/* --- the two-column card, rebuilt as flex --------------------------------
   The template gives .feature a FIXED height and floats the image into half of
   it. That works for three cards of two sentences each. It does not work once
   a card is a title, a label, a paragraph and a button: the tallest ones
   simply overflow their box and run into the card below, and the failure is
   invisible until somebody writes a long enough blurb.

   Flex makes the row as tall as whatever is in it, and `aspect-ratio` gives
   the image a shape of its own instead of inheriting a height from the text
   beside it -- which is also what lets the 8:5 artwork in images/services/ be
   shown at 8:5 rather than cropped to whatever the text column happened to
   dictate.

   Scoped above the template's own stacking breakpoint, so the single-column
   layout below 980px is left exactly as the template wrote it. */

@media screen and (min-width: 981px) {
  /* `stretch`, not `center`: the text column is made exactly as tall as the
     picture, and is laid out as a column with the title held to the top and
     the button to the bottom. Every card then has the same shape whatever the
     length of its blurb -- the blurb just has more or less air around it.

     The picture's 8:5 is the FLOOR for the row. A blurb too long for that
     height would stretch the picture taller and crop it, which is what the
     length limit in lib/sites.js is there to prevent. */
  .feature {
    align-items: stretch;
    display: flex;
    gap: 3em;
    height: auto;
    margin-bottom: 4.5em;
  }

  /* The inline-block spacer that did the vertical centring, and the float
     clearer that went with it. Both are dead weight in a flex row. */
  .feature::before,
  .feature::after {
    content: none;
  }

  .feature.right {
    flex-direction: row-reverse;
  }

  .feature .image {
    aspect-ratio: 8 / 5;
    flex: 0 0 50%;
    float: none;
    height: auto;
    width: auto;
  }

  .feature .content {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    padding: 0;
    width: auto;
  }

  /* Title and tag at the top, button at the bottom, the blurb takes the
     middle. The blurb's own margin is dropped in favour of the gap, so the
     spacing above and below it is the same and it sits visually centred. */
  .feature .content .blurb {
    flex: 1 1 auto;
    margin: 0;
    padding: 1em 0;
  }

  .feature .content .go {
    margin: 0;
  }
}

/* --- narrow screens ------------------------------------------------------
   The template stacks .feature at 980px on its own. These are the bits it
   does not know about. */

@media screen and (max-width: 980px) {
  /* Solid near-black pills stacked down a phone are harsh; a warm dark grey
     keeps the same weight without the glare. Still 9:1 against the white
     label, and the hover/focus text stays the deep ink so it holds on orange. */
  :root {
    --button-bg: #4a423b;
  }

  #header .logo {
    box-shadow: 0 0.5em 2.5em rgba(74, 66, 59, 0.3);
  }

  .whobar {
    justify-content: center;
    left: 0;
    padding: 0.9em 1em;
  }

  #header .whobar .who-email {
    max-width: 10em;
  }

  /* Room for the who-bar, which centres itself across the top at this width. */
  #header {
    padding-top: 6em;
  }

  /* Small is the brief, but at this width the quick links are pressed with a
     thumb. A little more type and padding takes them from 28px tall to 33. */
  #header .quick .chip {
    font-size: 0.78em;
    padding: 0.65em 1.2em;
  }

  /* The template centres the stacked card's text. Left everywhere is what the
     two-column layout does, and centred prose is harder to read than ragged
     right, so the one-column version matches rather than diverges. */
  .feature .content,
  .feature.right .content {
    text-align: left;
  }
}

@media screen and (max-width: 736px) {
  #header {
    padding: 5em 0 10em 0;
  }

  #header .logo {
    height: 5.5rem;
    width: 5.5rem;
  }

  #header .actions.jump {
    gap: 0.6em;
  }

  .section-head {
    padding-top: 3em;
  }

  .section-head h2 {
    font-size: 1.25em;
    letter-spacing: 0.18em;
  }

  .panel table .actions-cell {
    justify-content: flex-start;
  }
}

/* Below this the row of three would give each button about six characters of
   width, which is neither readable nor a comfortable tap target. They stack
   full width instead, which is also the easiest thing to hit one-handed. */
@media screen and (max-width: 480px) {
  #header .actions.jump {
    display: grid;
    gap: 0.6em;
    grid-template-columns: 1fr;
    max-width: 18em;
  }

  #header .actions.jump .button {
    min-width: 0;
    width: 100%;
  }

  /* The buttons are a narrow stack here, so the divider narrows with them. */
  #header .quick::before {
    max-width: 12em;
  }
}

/* --- the quiet pages -----------------------------------------------------
   The gate, the Access panel and break glass are a single card on an
   otherwise empty page. The full-height header that introduces the hub would
   push that card below the fold, and the template's centre spine -- which
   exists to hang alternating cards off -- reads as a rendering artefact with
   nothing either side of it. */

body.gated #header,
body.admin #header {
  padding: 3em 0 11em 0;
}

/* The template runs a hairline down the centre of the whole page. It is the
   spine the alternating cards hang off in the original, but with real text in
   two columns it cuts straight through the words. It stays in the hero, where
   there is nothing for it to collide with, and stops there -- which also means
   it must not reappear in the footer below the gap. */
#main::before,
#footer::before {
  display: none;
}

/* The template parallaxes the header photo with background-attachment: fixed.
   It looks the same on a short header, costs a full-viewport repaint on every
   scroll frame, and iOS Safari has never handled it well. */
#header {
  background-attachment: scroll, scroll, scroll;
}

/* The template's footer is sized for a contact form, a row of social icons and
   a copyright line. This one holds a single sentence, so the 10em of space
   underneath it reads as a mistake rather than as room to breathe. */
#footer {
  padding-bottom: 5em;
}
