/* The software page, dialedinclub.com/<route to be decided>.

   Loads after style.css, build3.css and pages.css, so it inherits the whole
   site for free: Koe's one heading style, the accent, the grain, the cursor
   lift, the word-by-word reveals, the dither field behind the page header and
   the accent hairline above the footer.

   ONE SCREEN. Sabby, 2026-09-17: Liam Ottley's lander at diy.aimakeover.io is
   993px tall against a 900px viewport, so the whole offer is read without
   scrolling, and that is the thing he wanted copied. The first build here
   spread the same words over five screens.

   What makes it fit is the panel: picture on the left, the list and the ask on
   the right, the way his does it. Everything that was its own section before
   is either inside that panel now or gone. The FAQ went entirely, because
   everyone arriving here has just watched a long video and does not need the
   page to explain the thing again.

   Two calls to action and no others. Skool or buy. */

.softwarepage .wrap-wide { max-width: min(1180px, 92vw); }

/* ---------- the DIY breadcrumb ---------- */

/* Liam's "AI Makeover > DIY". No bar behind it, Sabby's call: this is a side
   door off the main site, and a full navigation bar would say otherwise. */
.softwarepage .pagenav .wrap {
  justify-content: flex-start;
  gap: 12px;
}
.softwarepage .crumb {
  font-size: 15px;
  line-height: 1;
  color: rgba(232, 232, 232, .32);
  transform: translateY(-1px);
}
.softwarepage .diy {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 3px;
  line-height: 1;
  text-transform: uppercase;
  color: var(--accent);
}

/* ---------- the hero ---------- */

/* Tight. Every value in here is smaller than the other inner pages use,
   because the panel underneath has to start above the fold. */
.softwarepage .pagehead {
  padding-bottom: 0;
  text-align: center;
}
/* 84px, which is what pages.css gives every other inner page. This override
   used to be 22px, bought to keep the panel above the fold, and the cost was
   that the claim count sat almost under the wordmark and read as part of the
   nav rather than as the first thing on the page. Sabby asked for the space
   back on 2026-09-17. It is the site's own number rather than a new one, so
   the software page now opens with the same gap as apply and story. */
.softwarepage .pagehead > .wrap {
  max-width: min(1180px, 92vw);
  margin-top: 84px;
}

/* 940px, and balanced. At the 24ch the other inner pages use, an eight-word
   headline runs to three lines at 52px and buries the last word on its own. */
/* 1120, not 940. Sabby's headline is 74 characters and at 940 it broke to
   three lines, which pushed the two buttons off a 900px-tall laptop screen,
   the one thing this layout exists to prevent. */
.softwarepage .pagehead h1 {
  max-width: 1120px;
  margin-bottom: 16px;
  text-wrap: balance;
}

/* The claim count, first thing on the page, the way Liam opens. Sabby's call:
   100+ runs now and the number goes up when the real one passes it. */
/* ---------- the claim count, with faces ---------- */

.claimed {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 4px;
  line-height: 1;
  text-transform: uppercase;
  color: var(--label-dim);
  margin: 0 0 16px;
}
.claimed strong {
  font-weight: 600;
  color: var(--accent);
}

/* Overlapped, like his. The ring is the page's own black rather than a
   border colour, so the circles read as stacked rather than outlined. */
.faces { display: flex; align-items: center; }
.faces img {
  display: block;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  object-fit: cover;
  /* The photos arrive in colour and the page carries one. Desaturated most of
     the way so five strangers' shirts don't become the brightest thing above
     the fold, with a little left in so they still read as people. */
  filter: grayscale(.85) contrast(1.05);
  box-shadow: 0 0 0 2px var(--bg);
}
.faces img + img { margin-left: -9px; }

.softwarepage .pagehead .lede {
  max-width: 56ch;
  margin: 0 auto;
}

/* ---------- the three badges ---------- */

/* Outlined pills, like his, in our palette rather than his emoji. Three
   saturated colours would be the only place on this site where something
   other than the accent carries meaning. */
.badges {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.badges li {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px;
  border: 1px solid rgba(232, 232, 232, .16);
  border-radius: 2px;
  font-size: 13px;
  line-height: 1.2;
  color: var(--label-dim);
}

/* Drawn rather than emoji, so they take the accent. An emoji is a bitmap the
   font supplies and no filter recolours it reliably. */
.badges svg {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- the panel ---------- */

/* Not the site's 110px section padding. That alone is a quarter of a laptop
   screen, and the whole point of this page is that it does not need one. */
/* 68px above, up from 24px, Sabby's call on 2026-09-17. At 24px the three
   badges and the top edge of the panel were close enough to read as one
   block, so the badges looked like a caption on the panel rather than the
   last line of the hero. They are the end of the pitch; the panel is the
   product. The gap is what says so. */
.panelwrap { padding: 68px 0 48px; }
.panelwrap + footer { border-top-color: transparent; }

/* Built out of the homepage's measurement grid: hairline gaps on a rule-
   coloured bed, so the two halves read as one object with a seam rather than
   two cards floating side by side. */
.panel {
  display: grid;
  grid-template-columns: 1.04fr 1fr;
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}

/* Edge to edge, no padding, the way Liam's image fills its half. Padding
   plus a max-height had the drawing rendering at about 590px wide inside a
   600px column, which made every label on it too fine to read, and an
   unreadable picture of software proves nothing. */
.panel-art {
  background: var(--bg);
  padding: 0;
  overflow: hidden;
  min-height: 0;
}

.panel-art img {
  display: block;
  width: 100%;
  height: 100%;
  /* Contain, not cover. Cropping ran the dashboard off all four edges, which
     read as a fragment rather than a product shot. The picture now carries
     its own black margin, so it sits inside the panel with room around it and
     the word "Overview" stays in frame. Image black and panel black are the
     same value, so where one stops and the other starts is invisible. */
  object-fit: contain;
  object-position: center;
}

.panel-list {
  background: var(--bg);
  padding: 24px 30px 26px;
  display: flex;
  flex-direction: column;
}

.panel-list .label { margin-bottom: 12px; }

/* ---------- what's inside ---------- */

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Number, title and line are siblings rather than a nested block, so all
   three name their own cell. Left to auto-placement the paragraph drops into
   the number column and sets itself one word per line. */
.steps li {
  display: grid;
  grid-template-columns: 42px 1fr;
  align-items: start;
  padding: 8px 0 8px 4px;
  border-bottom: 1px solid var(--rule);
}
.steps li:first-child { border-top: 1px solid var(--rule); }

/* The first item carries a wash and a bar, the way Liam marks his. It is the
   one that says what the thing actually is, so it is worth the eye. */
/* CLOSED on the right, Sabby 2026-09-17. It used to carry margin-right:-12px,
   so the wash ran off the edge of the column and bled into the panel's seam.
   An open edge says the thing continues; this item is the whole point of the
   page, so it should read as one closed object. The accent bar on the left
   and a hairline on the other three sides shut it. */
.steps li.is-lead {
  background: rgba(var(--accent-rgb), .05);
  box-shadow: inset 3px 0 0 var(--accent);
  border: 1px solid rgba(var(--accent-rgb), .22);
  border-left: none;
  padding-left: 14px;
  padding-right: 14px;
  margin-right: 0;
}
/* The row below would otherwise draw its own top border a pixel under this
   one's bottom border, which reads as a double rule. */
.steps li.is-lead + li { border-top: none; }
.steps li.is-lead em { padding-left: 0; }

.steps em {
  grid-column: 1;
  grid-row: 1;
  font-style: normal;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1px;
  line-height: 1.6;
  color: var(--accent);
  padding-top: 2px;
}

.steps h3 {
  grid-column: 2;
  grid-row: 1;
  font-size: 15.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.1px;
  color: var(--head);
  margin: 0 0 3px;
}

.steps p {
  grid-column: 2;
  grid-row: 2;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--fg);
  margin: 0;
}

/* ---------- the choice, its own block under the panel ---------- */

/* Sabby, 2026-09-18: picture and list in one box, the ask below it.

   It is deliberately NOT bordered into the panel above. The panel is the
   product and this is the decision about it, and a page with one continuous
   object in it gives a reader nowhere to stop and choose. The gap is the
   full stop. */
.choose {
  margin-top: 42px;
  text-align: center;
}

.doors-head {
  margin: 0 0 8px;
  font-size: 26px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.4px;
  color: var(--head);
  text-wrap: balance;
}

/* ONE LINE on a desktop, Sabby 2026-09-18. It was breaking after "inside the"
   and leaving "community." on a row of its own, which reads as a mistake
   rather than a line break. The measure was 52ch and the sentence is 68
   characters, so it was the max-width doing it and not the column. 72ch is
   wide enough for the whole thing and still narrow enough to wrap like prose
   rather than a banner if the copy ever grows. */
.doors-sub {
  margin: 0 auto;
  max-width: 72ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--label-dim);
}

/* Same hairline grid as the panel, so the two blocks are recognisably the
   same family without being welded together. */
.doors {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  /* 30px, up from 24. Sabby asked for more air here once the subheadline came
     back to one line, and a one-line subhead needs more space under it than a
     two-line one did, or the block reads as tighter than it was before. */
  margin-top: 30px;
  background: var(--rule);
  border: 1px solid var(--rule);
  text-align: left;
}

/* The two doors finish level however long the copy in each runs, and each
   button sits on its own door's floor. */
.door {
  background: var(--bg);
  padding: 22px 24px 24px;
  display: flex;
  flex-direction: column;
}

/* The name and the price on one line, pushed apart, so the two prices sit in
   a column and read against each other without hunting. */
.door-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 4px;
}

.door-name {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--head);
}

/* The accent on BOTH prices, including the $0. Colouring only the $997 would
   make the paid route the answer to a question the reader has not been asked
   yet. */
.door-price {
  flex: 0 0 auto;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* The list that replaced the prose. A tick per line in the accent, drawn as a
   background image rather than an <svg> per item, because eight inline SVGs
   for eight ticks is a lot of markup for one shape.

   The gap under the list lives HERE, not as a margin-top on the button, and
   that is not a style preference. A `.door-list + .btn` rule was the first
   attempt and it silently broke the levelling: a later, more specific rule
   setting margin-top beats the `auto` that pushes each button to its own
   floor, so the two buttons sat 20px out of line whenever one list ran a line
   longer than the other. Put the gap on the thing above and `auto` survives. */
.door-list {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
}

.door-list li {
  position: relative;
  padding-left: 22px;
  margin-bottom: 7px;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--fg);
}
.door-list li:last-child { margin-bottom: 0; }

.door-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  width: 13px;
  height: 11px;
  background: var(--accent);
  /* The same tick the apply page's thank-you panel uses, as a mask so it takes
     the accent from one place instead of being recoloured in two files. */
  -webkit-mask: no-repeat center/13px 11px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 15'%3E%3Cpath d='M1 7.5L7 13.5L19 1.5' fill='none' stroke='%23fff' stroke-width='2.4'/%3E%3C/svg%3E");
  mask: no-repeat center/13px 11px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 15'%3E%3Cpath d='M1 7.5L7 13.5L19 1.5' fill='none' stroke='%23fff' stroke-width='2.4'/%3E%3C/svg%3E");
}

.door .btn {
  margin-top: auto;
  padding: 13px 18px;
  text-align: center;
  font-size: 13.5px;
  letter-spacing: 0.2px;
}

/* ---------- the buttons ---------- */

/* White is the site's primary and stays on the free door, which is the action
   this page exists for. The accent marks the other one without either
   shouting. */
.btn-accent { background: var(--accent); color: #000; }
.btn-accent:hover { background: var(--accent); color: #000; opacity: .82; }


/* The two halves come up together, the list a beat behind the picture.

   Gated on .swjs, which software.js adds to <html> itself. That is the rule
   pages.js already follows with .pjs: a starting state that hides content must
   never depend on a DIFFERENT file having loaded, or one failed request leaves
   the page blank where the content should be. If this script never runs, the
   panel is simply visible. */
.swjs .panel-art,
.swjs .panel-list {
  opacity: 0;
  transform: translate3d(0, 16px, 0);
  transition: opacity .7s ease var(--d, 0ms),
              transform .7s cubic-bezier(.16, 1, .3, 1) var(--d, 0ms);
}
.swjs .panel.is-in .panel-art,
.swjs .panel.is-in .panel-list { opacity: 1; transform: none; }
.panel-list { --d: 110ms; }

/* ---------- footer ---------- */

/* No joke line here, unlike the rest of the site. On a page built to be read
   without scrolling, the only thing the footer owes anyone is the compliance
   line, which is not optional. */
.softwarepage footer { padding: 24px 0 30px; }
/* pages.css gives .fineprint 42px of top margin, which is the gap between it
   and the joke line above. There is no joke line on this page, so that margin
   is 42px of nothing. */
.softwarepage footer .fineprint { margin: 0 0 6px; }
.softwarepage footer .colophon { margin: 0; }

/* ---------- responsive ---------- */

/* ---------- the squiggle under the free line ---------- */

/* A hand-drawn orange sweep under "Everything you need is free.", the
   underline every landing page has had since about 2021. Three shallow waves
   rather than a repeating sine, because a tiled wave reads as a spellcheck
   error and a single sweep reads as a pen.

   It is a MASK over `background: var(--accent)`, not a coloured background
   image, and that is deliberate. A colour baked into a data URI would be the
   sixth place the accent lives, and this site's whole recolour story is that
   the accent is set in five places in style.css and nowhere else. The tick in
   `.door-list li::before` is done the same way for the same reason, so
   ?theme=gold moves the squiggle too.

   preserveAspectRatio='none' lets one 220-wide drawing stretch to whatever the
   sentence measures. The stretch is almost all horizontal, so the stroke keeps
   its thickness where it matters. */
.squiggle {
  position: relative;
  display: inline-block;
}

.squiggle::after {
  content: "";
  position: absolute;
  /* Wider than the words at both ends, the way a hand overshoots. */
  left: -5px;
  right: -5px;
  bottom: -0.42em;
  height: 11px;
  background: var(--accent);
  -webkit-mask: no-repeat center/100% 100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 14' preserveAspectRatio='none'%3E%3Cpath d='M3%209.4%20C%2034%203.2,%2060%2012.4,%2092%207.2%20C%20124%202.1,%20152%2011.6,%20182%206.6%20C%20197%204.1,%20209%205.6,%20217%208.4' fill='none' stroke='%23fff' stroke-width='3.1' stroke-linecap='round'/%3E%3C/svg%3E");
  mask: no-repeat center/100% 100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 14' preserveAspectRatio='none'%3E%3Cpath d='M3%209.4%20C%2034%203.2,%2060%2012.4,%2092%207.2%20C%20124%202.1,%20152%2011.6,%20182%206.6%20C%20197%204.1,%20209%205.6,%20217%208.4' fill='none' stroke='%23fff' stroke-width='3.1' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* ---------- the doors, collapsed on a phone ---------- */

/* Added by software.js, and only at phone widths. The class goes on .doors
   rather than living in a media query on its own, because the collapsing is
   done by script: if that script never runs, nothing here applies and a phone
   gets both doors fully open, which is what it got before. A reader must never
   lose the list because an animation failed.

   On a desktop .door-body is display:contents, so the <ul> and the <a> stay
   direct flex children of .door and the `margin-top: auto` that levels the
   two buttons still works. */
.door-body { display: contents; }

.doors-collapsible .door-body {
  display: block;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height .34s cubic-bezier(.22, .61, .36, 1), opacity .24s ease;
}

.doors-collapsible .door.is-open .door-body {
  opacity: 1;
}

/* The tap target. A quiet row of text with a chevron, sitting right under the
   name and the price, NOT a filled box. Sabby, 2026-09-18: the first version
   was an orange panel and it read as the thing to press on this door, which
   is wrong, because the thing to press is the button at the bottom. An accent
   underline and a chevron say "opens" without competing with a call to action.

   Full width even so, because the visible text is short and a thumb is about
   44px across. The row is the target, the words are just where it is. */
.door-tap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  margin: 8px 0 0;
  padding: 9px 0;
  background: none;
  border: 0;
  border-top: 1px solid rgba(var(--accent-rgb), .22);
  font-family: var(--f);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .2px;
  color: var(--accent);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: rgba(var(--accent-rgb), .16);
}

.door-tap-label {
  text-decoration: underline;
  text-decoration-color: rgba(var(--accent-rgb), .45);
  text-underline-offset: 3px;
}

.door-tap:active { opacity: .65; }

/* Same chevron shape and the same mask trick as everything else here. */
.door-chev {
  flex: 0 0 auto;
  width: 11px;
  height: 7px;
  background: var(--accent);
  transition: transform .3s ease;
  -webkit-mask: no-repeat center/11px 7px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  mask: no-repeat center/11px 7px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.door.is-open .door-chev { transform: rotate(180deg); }

/* The gap above the list is a MARGIN on the list, not padding on the wrapper.
   Padding survives `max-height: 0` (it sits outside the content box that
   max-height limits), so a closed door kept a strip of nothing under its tap
   row. A margin inside the overflow:hidden wrapper is clipped with everything
   else. */
.doors-collapsible .door-list { margin: 13px 0 0; }

/* The button is no longer inside the collapsing wrapper, so it needs its own
   gap above it, and that gap has to work in both states: right under the tap
   row when the list is closed, and under the last tick when it is open. */
.doors-collapsible .door .btn { margin-top: 14px; }

@media (max-width: 900px) {
  .panel { grid-template-columns: 1fr; }
  /* Picture first on a phone too. It is the proof, and it is the one thing
     on the page that isn't words. */
  /* The box has to match the picture's own shape, or `contain` fits the
     picture to whichever side is tighter and leaves black down the other. It
     was 16/9 for the old 2:1 desktop shot, which was near enough. The iPad
     shot is 1.09:1, and in a 16/9 box it would have rendered at about 62% of
     the column width with black either side. Same number as the file. */
  .panel-art {
    aspect-ratio: 1042 / 956;
    padding: 0;
  }
  .panel-list { padding: 24px 22px 26px; }
}

@media (max-width: 767px) {
  /* FLUID, and scoped to this page's fold only. Sabby on a 440px phone,
     2026-09-17: the headline ran to five lines and he wants four.

     It cannot be fixed at --head-size, which is 39px on phones in style.css:
     h1, h2 and .head all read that variable, so moving it takes every section
     heading on every page with it, plus the apply and story headlines.

     Why a vw and not a number. This headline is 75 characters, three times the
     length of the one this fold used to carry, so its line count is very
     sensitive to width: at a flat 36px it is four lines on a 440px phone and
     five on a 390px one. Scaling the type with the measure keeps the count
     steady instead, because both sides of the ratio move together. 8.2vw is
     the number that lands on four lines at 440, 430 and 390. The floor stops
     it shrinking past readable on the oldest phones, where it takes five
     lines and that is fine. */
  .softwarepage .pagehead h1 {
    max-width: 100%;
    font-size: clamp(29px, 8.2vw, 36px);
  }
  /* Faces above the words, not beside them. At 390px wide the line broke
     after "100+" and left FOUNDERS on a row of its own next to the
     avatars, which reads as a mistake. */
  .claimed {
    flex-direction: column;
    gap: 10px;
    letter-spacing: 3px;
    margin-bottom: 22px;
  }

  /* THEY WRAP, they do not stack. Sabby, 2026-09-17, pointing at Liam's
     lander: his three badges break over two rows, one on the first and two on
     the second, and three full-width bars in a column is what ours was doing
     instead.

     The column came from an earlier set of labels and it was the wrong
     instinct. A stack of three identical bars reads as a list of features,
     which makes a reader work through it; two rows read as a row of stamps,
     which a reader takes in at a glance. That is the whole job of this line.

     So: no column, no stretch, and the font drops from 13px to 12 with
     tighter padding, which is what buys the second and third badge enough
     room to share a row. Flex wrap then does the arranging, which means it
     stays right at any width rather than at the one width it was tuned to. */
  .badges {
    flex-wrap: wrap;
    gap: 8px;
  }
  .badges li {
    justify-content: flex-start;
    font-size: 12px;
    padding: 8px 12px;
    gap: 7px;
  }
  .badges svg { width: 14px; height: 14px; }

  /* The same two gaps as desktop, scaled down. A phone is already scrolling,
     so the space costs nothing here, but it should not be so large that the
     badges and the panel stop feeling like one page. */
  .panelwrap { padding: 56px 0 56px; }
  /* One door above the other. Side by side at 311px each door gets 155px,
     which puts "Have us do it for you" on three lines and its price on a line
     of its own. */
  .doors { grid-template-columns: 1fr; }
  .door { padding: 20px 20px 22px; }
  .doors-head { font-size: 22px; }
  .choose { margin-top: 34px; }
  .steps li { grid-template-columns: 34px 1fr; }
}
