/* =========================================================================
   hero-v1.css — the settled Next 12 hero, consolidated.

   Everything that survived the exploration, in one file, replacing the
   stack of layered comparison stylesheets. Self-contained: it does not
   load site.css, so the hero can be judged without inheriting the older
   shell's accumulated overrides.

   The decisions it encodes, and why:

   - Black ground, not charcoal. Charcoal lifts the photograph's shadows
     and flattens the sunset; the split stays legible without it because
     the type holds the lower edge.
   - A 50/50 split. Widening the panel from 1.24fr gave the three services
     room and let the menu run to the right gutter instead of stopping
     mid-photograph.
   - One gutter for every left edge on the panel: claim, numerals, titles,
     buttons. That single alignment is most of why this reads as
     engineered rather than arranged.
   - No headline. The three service names are unusually literal, so the
     hero says what it does without one, and the offerings become the
     largest type — the right hierarchy for a page whose job is routing.
   - The credibility claim above the list, in sand caps, no rule. It
     differs from its surroundings by case and colour rather than by size;
     smaller alone reads as "less important" rather than "a different sort
     of thing". The rule it used to sit in earned its place only while it
     was on the list's boundary doing structural work.
   - 64px above the list and 64px below it, matched.
   - One filled button. Two equal buttons split the decision.

   Motion: hover states only. Nothing moves on its own.
   ========================================================================= */

:root{
  --n12-black:#000;
  --n12-black-rgb:0,0,0;
  --n12-cream:#F6F1EA;
  --n12-line:rgba(246,241,234,.16);
  /* Sand, taken from the lit edge of the dune. The only chromatic value on
     the panel, which is what lets one line of it register without volume. */
  --n12-sand:#D6A473;
  --n12-photo:image-set(url("/assets/images/hero-rally-car.avif") type("image/avif"),url("/assets/images/hero-rally-car.jpg") type("image/jpeg"));
  --n12-gutter:44px;

  /* Cream. Black measured better against the sky (4.9:1 against 3.8:1) but
     the wordmark is the brand's, not a contrast problem to be solved, and
     it belongs in the site's own white. */
  --n12-mark:var(--n12-cream);
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--n12-black);
  color:var(--n12-cream);
  font-family:'Questrial',sans-serif;
  -webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}

/* ============================== layout ============================== */

.n12-hero{
  position:relative;
  display:grid;
  grid-template-columns:1fr 1fr;
  min-height:100vh;
}

/* ============================== header ==============================
   Full width across both halves, on the same grid as the hero, so the
   wordmark sits over the photograph and the menu over the panel. */

/* STICKY, BUT ONLY WHEN IT HAS SOMETHING TO SAY.

   It was absolutely positioned inside each hero, so it scrolled away
   with the picture and the pages are long enough that getting back to
   the navigation meant flicking to the top. Fixed, it followed people
   around at 104px tall, which is a lot of chrome to carry down a
   reading page.

   Three states, driven by n12-head.js:

     (no class)  transparent over the hero, full size -- unchanged
     .is-stuck   past the hero: 64px, near-black, one hairline
     .is-away    scrolling down: translated out of the way

   position:fixed rather than sticky, because the header lives INSIDE
   the hero section on every page and a sticky element cannot leave its
   own parent. It was already out of flow, so nothing moves and there
   is no space to reserve -- the heroes' top padding was always sized
   for a header painted over them. */

/* A FOCUS RING FLOOR. Most components draw their own -- the filter
   chips, the pricing switch, the app mock's buttons, the contact
   fields -- but the ones that did not showed nothing at all when tabbed
   to: the blog search field, and every link inside a post body. A
   keyboard user could not tell where they were.

   This is a single type-less :focus-visible at (0,1,0), so every
   component rule already written beats it and keeps its own ring; it
   only paints where nothing else does. :focus-visible rather than
   :focus, so a mouse click does not leave a ring behind. */
:focus-visible{
  outline:2px solid var(--n12-accent,#B28479);
  outline-offset:2px;
}

/* SKIP TO CONTENT. Every page opens with the wordmark, eight nav links
   and the menu button -- ten tab stops between landing on the page and
   reaching anything it is about, on all 25 pages, with no way past
   them. This is the way past.

   Off-screen rather than display:none, because a hidden element is not
   focusable and an unfocusable skip link is decoration. It comes back
   on focus, painted over the header it sits under, above everything
   including the fixed header's own z-index.

   #n12-content is its landing: a zero-size, absolutely positioned span
   just after the mobile menu, so it is out of flow and cannot become a
   grid or flex item of the hero. tabindex="-1" makes it a focus target
   without putting it in the tab order itself. */
.n12-skip{
  position:absolute;left:-9999px;top:0;
  z-index:100000;
  padding:12px 18px;
  background:var(--n12-cream,#F6F1EA);color:#0F0D0C;
  font-family:'League Spartan',sans-serif;
  font-size:14.5px;font-weight:700;letter-spacing:.02em;
  text-decoration:none;border-radius:0;
}
.n12-skip:focus{left:16px;top:16px;outline:2px solid #0F0D0C;outline-offset:2px}
#n12-content{position:absolute;width:0;height:0;overflow:hidden}
#n12-content:focus{outline:none}

.n12-head{
  position:fixed;
  top:0;
  left:0;
  right:0;
  z-index:50;
  display:grid;
  grid-template-columns:1fr 1fr;
  align-items:center;
  padding:26px 0;
  border-bottom:1px solid transparent;
  transition:
    transform .28s cubic-bezier(.33,1,.68,1),
    padding .22s ease,
    background-color .22s ease,
    border-color .22s ease;
}
/* THE SOLID STATE. rgba over a blur rather than a flat fill, so a
   bright band of a photograph passing underneath does not make the bar
   look like it is switching on and off. A hairline, not a shadow:
   shadows on a dark page read as a smudge. */
.n12-head.is-stuck{
  padding:0;
  height:64px;
  background:rgba(12,10,10,.93);
  -webkit-backdrop-filter:blur(12px);
  backdrop-filter:blur(12px);
  border-bottom-color:rgba(246,241,234,.10);
}
.n12-head.is-stuck .n12-logo{font-size:34px}
.n12-head.is-stuck .n12-nav{font-size:14px;gap:15px}
/* HIDDEN ON THE WAY DOWN, back on the way up. Only ever from the stuck
   state -- the transparent header over a hero has nothing to get out
   of the way of. */
.n12-head.is-stuck.is-away{transform:translateY(-101%)}

.n12-logo,.n12-nav{transition:font-size .22s ease}

/* SO THE BAR DOES NOT LAND ON A HEADING. Anything reached by #hash --
   the project deep links on /ideas, the form's #messy -- would
   otherwise arrive with its first line underneath the header. */
html{scroll-padding-top:80px}

/* ========================= ONE HERO HEADLINE SIZE =========================
   Nine page heroes were running nine different clamps. Measured at
   1440: planning 64, about 62, software 56, ideas 56, blog 52, pricing
   50, privacy 48, contact 42. At 390: 42, 40, 40, 34, 33.5, 33.5, 36,
   32. Nothing chose those numbers -- each page was tuned on its own and
   they drifted apart.

   52/33 is the middle of that range and it is the size the blog
   masthead already uses, which is the hero the rest are being matched
   to. Every headline on the site fits it:

     planning  stop winging it.                          1 line
     software  one place to plan, meet, and get...       2 lines
     ideas     things we've made computers do.           1 line
     pricing   one. two. or all three.                   1 line
     blog      useful ideas for running a less...        2 lines
     about     built from the operator's seat.           2 lines
     contact   what brought you here?                    1 line
     privacy   privacy policy.                           1 line

   The 5.2vw middle term hits 52 at 1000px and holds there, so the
   headline is at full size on any laptop and scales only on tablets.

   ARTICLE TITLES ARE NOT IN THIS. A post's h1 is a document title
   written for search -- "What Should You Fix First? Plan, Software or
   Automation?" is 56 characters and would take four lines at 52px. */
:root{--n12-h1:clamp(37px,5.2vw,52px)}

@media(prefers-reduced-motion:reduce){
  .n12-head,.n12-logo,.n12-nav{transition:none}
  .n12-head.is-stuck.is-away{transform:none}
}
.n12-logo{
  grid-column:1;
  justify-self:start;
  padding-left:var(--n12-gutter);
  font-family:'League Spartan',sans-serif;
  /* 800 and tighter tracking, so the n and the e close up the way they do
     in the real wordmark. At 700/-.03em they sat apart as separate letters
     rather than as a mark. */
  font-weight:800;
  /* 52, NOT 42, AND DECLARED ONCE.

     42 was the base here and every page that wanted the real size
     overrode it: planning-n12.css, software-n12.css and shift-anim.css
     each carried their own `.n12-logo{font-size:52px}`. Three copies of
     one value, which is three chances to drift -- and the automation
     page, which loads none of those files, fell through to 42 and had a
     visibly smaller masthead than the other three. Nav went with it,
     13.5 against 15.

     The three overrides are deleted. This is the size now. */
  font-size:52px;
  line-height:1;
  letter-spacing:-.055em;
  white-space:nowrap;
  color:var(--n12-mark);
}
.n12-nav{
  grid-column:2;
  justify-self:end;
  display:flex;
  align-items:center;
  gap:17px;
  padding-right:var(--n12-gutter);
  /* 14, down from 15. The masthead carries eight items beside a 52px
     wordmark, and at 15 the row read as heavy for what it is -- a set
     of quiet destinations under a large name, not a second headline.
     One step down is the whole change; the gap, the colour and the
     wordmark all stay where they were. */
  font-size:14px;
}
.n12-nav a{color:rgba(246,241,234,.72);white-space:nowrap;transition:color .15s ease}
.n12-nav a:hover{color:var(--n12-cream)}
/* The page you are on is the one item at full cream, so the nav says where
   you are as well as where you can go. aria-current="page" rather than a
   class, because the same attribute is what tells a screen reader, and one
   marker is easier to keep honest than two.

   Colour alone, no rule or weight change: at 13.5px on .72 a bolder or
   underlined item would read as the emphasised link rather than the
   current one. Both navs, so the phone menu marks it too. */
.n12-nav a[aria-current="page"],
.n12-menu a[aria-current="page"]{color:var(--n12-cream)}

/* For the page's h1. The hero has no visible headline by design -- the
   three offerings ARE the headline, and each is a link, so none of them
   can carry it. That left the document starting at h2 with no h1 at all,
   which is a real gap for search and for anyone navigating by headings.
   This carries it for them without adding anything to the design.

   The clip pattern rather than display:none, because display:none is not
   read out either. */
.n12-sr{
  position:absolute;width:1px;height:1px;
  padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);clip-path:inset(50%);
  white-space:nowrap;border:0;
}

.n12-toggle{display:none;flex-direction:column;gap:6px;padding:0;border:0;background:none;cursor:pointer}
.n12-toggle span{display:block;width:28px;height:2px;border-radius:2px;background:var(--n12-mark)}
.n12-menu{display:none}

/* =========================== photograph ===========================
   The fade resolves to the PANEL's black, not to a near-black, and holds
   there for a band at each end. A 12-value difference between the two
   sides is invisible in isolation and clearly visible as a vertical seam
   exactly where the halves are meant to merge. Holding to 16% rather than
   touching black only at 0% gives a merge zone deep enough that the
   photograph emerges out of the dark instead of starting at an edge. */

/* Two layers rather than one, because a CSS filter applies to the whole
   element and the brief is selective: the sun and the dust keep their
   warmth while everything else loses saturation. The base is desaturated,
   and a full-colour copy sits over it masked to the glow. Both share the
   same crop values, so they must stay in step — hence --n12-crop. */

.n12-photo{
  --n12-crop:73% 46%;
  position:relative;
  overflow:hidden;
  background-color:var(--n12-black);
}

/* base — desaturated, warmed slightly so the greys do not go cold */
.n12-photo::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:0;
  background-image:
    linear-gradient(rgba(44,37,35,.22),rgba(44,37,35,.22)),
    var(--n12-photo);
  background-size:cover;
  background-position:var(--n12-crop);
  background-repeat:no-repeat;
  /* .62 rather than .45: at .45 the dune read as a grey slope rather than
     as sand. It costs nothing elsewhere — the wordmark sits on sky, not on
     the dune, so its contrast is unchanged at 3.71:1, and the dune is dark
     enough that added warmth does not compete with the glow.

     Exposure is deliberately NOT reduced here. A global brightness cut
     dims the sun and dust as well, which is the one region meant to stay
     bright, and it drops the black wordmark from 3.70:1 to 3.07:1 at -12%
     and to 2.60:1 at -22%, which fails outright. A vignette is the right
     tool if this ever needs more depth. */
  filter:saturate(.62);
}

/* sky — a heavily desaturated copy masked to the upper band. The base sits
   at .62 so the dune reads as sand, but that left the sky bluer than it
   wanted to be; a third layer takes the colour out of the top without
   touching the sand below it. */
.n12-photo-sky{
  position:absolute;
  inset:0;
  z-index:1;
  background-image:
    linear-gradient(rgba(44,37,35,.22),rgba(44,37,35,.22)),
    var(--n12-photo);
  background-size:cover;
  background-position:var(--n12-crop);
  background-repeat:no-repeat;
  filter:saturate(.14);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 26%,rgba(0,0,0,.55) 38%,transparent 50%);
  mask-image:linear-gradient(180deg,#000 0%,#000 26%,rgba(0,0,0,.55) 38%,transparent 50%);
}

/* glow — the same frame at full colour, revealed only where the sun and
   the dust plume are. The mask is an ellipse rather than a circle because
   the plume runs horizontally across the lower left of the crop. */
.n12-photo-glow{
  position:absolute;
  inset:0;
  z-index:2;
  background-image:var(--n12-photo);
  background-size:cover;
  background-position:var(--n12-crop);
  background-repeat:no-repeat;
  -webkit-mask-image:radial-gradient(ellipse 62% 34% at 14% 52%,#000 0%,rgba(0,0,0,.85) 38%,rgba(0,0,0,.35) 64%,transparent 84%);
  mask-image:radial-gradient(ellipse 62% 34% at 14% 52%,#000 0%,rgba(0,0,0,.85) 38%,rgba(0,0,0,.35) 64%,transparent 84%);
}

/* fade — bottom only, sitting above both image layers.
   The photograph runs at full strength from the top edge so the sky reads,
   which is why the wordmark is dark rather than cream. */
.n12-photo::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:3;
  pointer-events:none;
  background:linear-gradient(180deg,
    rgba(var(--n12-black-rgb),.12) 0%,
    rgba(var(--n12-black-rgb),.12) 56%,
    rgba(var(--n12-black-rgb),.24) 72%,
    rgba(var(--n12-black-rgb),.52) 85%,
    rgba(var(--n12-black-rgb),.84) 94%,
    rgb(var(--n12-black-rgb)) 100%);
}

/* ============================== panel ============================== */

.n12-panel{display:flex;flex-direction:column;justify-content:center}

/* 28px, not 64: row 01 adds its own 36px padding-top beneath this, and the
   64px we settled on is the distance between the two pieces of TEXT. */
.n12-claim{
  margin:0 0 25px;
  padding:0 var(--n12-gutter);
  font-size:10.5px;
  font-weight:700;
  line-height:1.4;
  letter-spacing:.2em;
  text-transform:uppercase;
  /* Cream, not the sand tone. The caps and the letterspacing already mark
     this as a different kind of text from the lowercase service titles, so
     colour was a second signal for a job already done — and a warm accent
     on an otherwise monochrome panel read as a highlight rather than an
     aside. Held back to 74% so it stays quieter than the offerings. */
  color:rgba(246,241,234,.74);
}

.n12-services{list-style:none;margin:0;padding:0}
.n12-services a{
  display:grid;
  /* 30px, not auto. Each row is its own grid, and an auto first column is
     sized by its own content -- so the numeral column measured 19.81px for
     "01", 23.44px for "02" and 22.97px for "03", because League Spartan
     draws proportional figures and its 1 is narrower than its 2 and 3.
     That staggered the three offering titles by up to 3.6px, which is
     plainly visible at a 42px headline.

     A fixed column makes every title start on the same left edge whatever
     the digits are. tabular-nums on the numeral below does the matching
     job inside the column. */
  grid-template-columns:30px 1fr auto;
  align-items:center;
  gap:20px;
  padding:36px var(--n12-gutter);
  border-top:1px solid var(--n12-line);
  transition:background .18s ease,padding-left .18s ease;
}
.n12-services li:first-child a{border-top:0}
.n12-services a:hover{background:rgba(246,241,234,.05);padding-left:52px}
.n12-services b{
  align-self:start;
  /* CENTRED ON THE TITLE'S FIRST LINE, not floating above it.

     align-self:start put the numeral at the top of a two-line title and
     padding-top:6px nudged it down by a fixed amount, which lands
     nowhere in particular: the title's line box is font-size x .95 and
     its font-size is a clamp, so the distance to the centre of line one
     changes with the viewport while 6px does not.

     Giving the numeral the TITLE'S line-height instead makes its line
     box exactly as tall as the first line of the title beside it, so
     the two centre on each other at every width with no magic number.
     The declaration is repeated rather than shared because these are
     siblings, and .95 has to stay in step with .n12-services strong. */
  /* A BOX EXACTLY ONE TITLE-LINE TALL, with the glyph centred in it.

     Setting the numeral's line-height to the title's was not enough:
     leading is distributed around a glyph, not centred on it, so the
     digits still sat 6.5 to 12px above the title's ink. Measured on
     painted pixels -- my earlier check compared LINE BOXES, agreed to
     within 3px and passed while the screenshot showed it plainly wrong.

     The offset also varied per row, because ink extent depends on the
     word: "one-page" has descenders and no ascenders, "custom workflow"
     the reverse. So ink is not a stable target and the line box is.
     height + flex centring puts the digits in the middle of the title's
     first line whatever the word and whatever the viewport. */
  display:flex;
  align-items:center;
  height:calc(clamp(23px,2.5vw,35px) * .95);
  line-height:1;
  font-family:'League Spartan',sans-serif;
  /* Same advance width for every digit, so 01/02/03 sit on one axis
     rather than each centring on its own glyph widths. */
  font-variant-numeric:tabular-nums;
  font-size:13px;
  font-weight:700;
  letter-spacing:.2em;
  opacity:.55;
}
.n12-services strong{
  font-family:'League Spartan',sans-serif;
  font-size:clamp(23px,2.5vw,35px);
  font-weight:700;
  line-height:.95;
  letter-spacing:-.035em;
  text-transform:lowercase;
}
.n12-arrow{display:flex;opacity:.5;transition:transform .18s ease,opacity .18s ease}
.n12-arrow svg{width:24px;height:24px}
.n12-services a:hover .n12-arrow{transform:translateX(6px);opacity:1}

/* ============================= actions =============================
   Left-aligned onto the same gutter as everything above. One filled
   button carries the primary weight; the second is a text link, so the
   pair reads as a choice with an obvious default rather than two
   competing offers. */

.n12-actions{
  display:flex;
  align-items:center;
  gap:26px;
  flex-wrap:wrap;
  /* Mirrors the claim's 28px: row 03's padding-bottom supplies the rest,
     landing the button 64px below the last service title.

     48 now, not 28. The three service rows each close with a rule, so
     the button sits under a full-width hairline rather than under text,
     and the same measurement reads tighter than it does elsewhere --
     the same reason .st-foot went 48 -> 68. */
  padding:48px var(--n12-gutter) 0;
}
.n12-cta{
  display:inline-flex;
  align-items:center;
  padding:15px 28px;
  background:var(--n12-cream);
  color:var(--n12-black);
  font-size:15px;
  font-weight:700;
  white-space:nowrap;
  transition:background .16s ease,transform .16s ease;
}
.n12-cta:hover{background:#fff;transform:translateY(-1px)}
.n12-help{
  display:inline-flex;
  align-items:center;
  gap:9px;
  padding:0;
  border:0;
  background:none;
  color:var(--n12-cream);
  font-family:'Questrial',sans-serif;
  font-size:14px;
  white-space:nowrap;
  cursor:pointer;
}
.n12-help span{transition:transform .18s ease}
.n12-help:hover span{transform:translateX(4px)}

/* =========================== responsive ===========================
   One column: the photograph leads, the panel follows, and the menu
   collapses behind the toggle. The gutter is restated once per
   breakpoint and every left edge follows it. */

@media(max-width:1024px){
  :root{--n12-gutter:32px}
  .n12-hero{grid-template-columns:1fr;min-height:0}
  .n12-head{grid-template-columns:auto auto;justify-content:space-between}
  .n12-logo{font-size:34px}
  .n12-nav{display:none}
  .n12-toggle{display:flex;grid-column:2;justify-self:end;margin-right:var(--n12-gutter)}
  .n12-photo{min-height:min(560px,70vh)}
  .n12-panel{padding:72px 0 88px}
  .n12-claim{margin-bottom:44px}
  .n12-services a{padding:30px var(--n12-gutter)}
  .n12-actions{padding-top:44px}

  /* THE MOBILE MENU LIVES IN mobile-n12.css, WHICH LOADS AFTER THIS FILE
     AND OWNS IT ENTIRELY -- the full-screen panel, its ground, its type
     and the fade.

     This block used to carry a second, contradictory definition here: an
     absolutely positioned bar at top:84px animating max-height 0 -> 420.
     It had not rendered in a long time, because every declaration in it
     was already being beaten downstream. Deleted rather than updated,
     which is the only safe thing to do with a rule that still matches a
     live selector and no longer describes what you see. */
}

@media(max-width:640px){
  :root{--n12-gutter:20px}
  .n12-photo{min-height:min(480px,64vh)}
  .n12-services a{padding:24px var(--n12-gutter);gap:14px}
  .n12-services a:hover{padding-left:24px}
  .n12-actions{flex-direction:column;align-items:stretch;gap:18px}
  .n12-cta{width:100%;justify-content:center}
  .n12-help{align-self:center}
}

@media(prefers-reduced-motion:reduce){
  .n12-services a,.n12-arrow,.n12-cta,.n12-help span,.n12-menu{transition:none}
}
