Skip to content
BIDWELL

Design notes

Why this one looks like this

Written by the designer, first person, after the fact. Bidwell is a concept brand built for a portfolio. The agency is invented; the design decisions are not.

Who it’s actually for

Bidwell is an eleven-person performance media agency in Leeds, and the person I designed for isn’t the founder of the ecommerce brand. It’s whoever inside that brand has already been burned once: someone with a £60,000-a-month media budget, a previous agency they let go, and a finance director asking what the money did. That reader arrives sceptical and skim-reads for numbers. The whole page is arranged so that a sceptical skim keeps snagging on something concrete.

The art direction, and what I threw out

The instruction I held hardest was: no rounded corners anywhere. I made that structural rather than a habit. The Tailwind radius token namespace is deleted in globals.css with --radius-*: initial, so rounded-lgdoesn’t exist as a class on this build, and a base rule zeroes the radius browsers put on form controls. A constraint you can’t break by accident is worth more than one you have to remember.

Archivo does the heavy lifting at 125% width, the variable font’s width axis pushed near the top of its range, because the hero is a single number and that number has to read as architecture rather than as a headline. Everything else is deliberately smaller than it wants to be so the number keeps its authority.

That width axis is also what broke the first build, and the way it broke is worth writing down. The number was set at min(23vw, 320px), sized from a measurement I had taken at the font’s default width. At wdth 125with tabular figures and −0.035em tracking, “£41.6m” is 4.43em wide, not 3.54em. So the glyph run came out at 1.02 × the content box and the whole document scrolled sideways at 390, 834 and 1440 alike. I had measured the type without the axis the same page boasts about two paragraphs earlier.

The fix is not a smaller number, it is a different unit. .hero-num is a container (container-type: inline-size) and the number is set in min(21.5cqw, 300px), so it is sized against the box it actually sits in rather than against a viewport that includes the scrollbar and excludes the padding. 21.5 × 4.43 = 95.2% of the container at every width, with the same five per cent of air on both sides at 390 and at 1440. html also carries overflow-x: clip — clip, not hidden, so the sticky header still sticks — as a structural backstop rather than as the fix.

Two long lockups had the same disease in reverse. “TELL US WHAT’S ACTUALLY WRONG” and “SEVEN THINGS WE WON’T DO” had hard <br/> tags in them to protect a two-line break that the type was too wide to hold anyway. Rather than shrink them I moved them down the width axis to font-stretch: 100%, which is 20% narrower, and deleted the manual breaks. Same face, same weight, and the line now breaks where the column tells it to.

The palette is white, #0A0A0A, #E5E5E3 and #E02B20. An earlier version of this write-up claimed the red was “rationed to five jobs”. That was wishful. I counted: there are 57 references to it across the application, in nine distinct roles. Four are navigational (the logo mark, the primary button, the header CTA, the mobile menu numerals), three are state (active filter, focus ring, form error, chart hover), and two are structural (the 6px top border that opens a section, and the bullets and rules that carry a list). The honest rule is narrower than the one I wrote and stricter than it sounds: red never marks a value, only a change of state or an edge. In the before-and-after tables it is the “Now” column header that is red, not the figures under it, because the figure is the evidence and the header is the label.

I ran the contrast rather than trusting my eye. #E02B20 is 4.63:1 on white, so it is safe at body size there, but 4.28:1 on ink, which is fine for display type and UI edges and not for paragraphs. So no red running text ever appears on the black bands. The footer’s muted text failed this properly: white at 50% opacity on #1C1C1A measures 4.32:1, under the bar for 12px legal copy. It is now 65%, which measures 7.01:1. The full audit, with before and after ratios for every pair, is on the research page.

What I rejected: a dark hero, because another site in this portfolio owns the dark-software look and a dark agency page would have read as its sibling; anything resembling a logo wall; and photography as a hero device. I also abandoned photography inside the case studies. I went looking for cookware product shots for the Bramfield story and every result was food in a pan rather than a pan, so instead of forcing a near-miss the case studies became pure typography and hand-drawn SVG. That was the better answer anyway.

The order the objections get handled

Above the fold: the number, one sentence explaining what it is, and an admission that three accounts went backwards. The admission is load-bearing. Every agency page claims to be good, so volunteering an unflattering fact in the first screen is the cheapest way past the reader’s first defence.

After that the sections follow the order this buyer actually raises objections in. First, does it work: three long cases where “what we walked into” is longer than the results table. Then the working method, as a week-numbered ninety-day sequence rather than a four-icon process graphic. Then the catch, which is seven things Bidwell won’t do, set on black and the most opinionated block on the site. Then whether it pays, through a calculator whose headline output is the break-even lift, the number that makes it easy to fire them. Then eleven named people, then four published prices, then the form.

Three breakpoints, three layouts

At 1440 the page runs on twelve columns with deliberately uneven spans: case studies 4/8, calculator 5/7, contact 5/7. Nothing is ever three equal columns, because equal columns are what make a page look generated. At 834 the twelve-column spans go, but three blocks get a designed state of their own rather than a stack: pricing runs 2 × 2 on sm:grid-cols-2, the ninety-day method switches to an eight-column grid with the numeral and week range in a narrow left rail and a 2:1 crop on the photography, and the three short case studies put their metric strip across the full width in two columns. The stat band goes from six across to three and the team from four to two. The first two of those did not exist before this pass: pricing and method were lg:-only and rendered at 834 as four 712px-wide cards and a stretched mobile list. That was the honest gap in the responsive story and it is now closed.

At 390 the hero number fills the measure at 95% of the content box, tables get a minimum width and their own keyboard-reachable scroll container rather than wrapping into mush, and every chart carries a “show the numbers” toggle that reveals the identical data as a real table. On a phone that table is more useful than the chart. The calculator’s payoff comparison used to be a fixed-viewBox SVG, which meant its 13px currency figures scaled down to about 6.7 CSS px on a 390 screen. It is now two bars in real DOM on a shared track, so the figures are live text at 17px and scale with the reader rather than with the container.

The interactions, and what each is for

The stat counters run once on intersection with a cubic ease-out and no overshoot, and they jump straight to the final figure when reduced motion is requested. The case study filter works on two axes at once, sector and channel, and has a written empty state for combinations the agency hasn’t taken on. Six accounts is a small enough set that dead ends are likely and pretending otherwise would be worse. The charts are all inline SVG with a shared hover readout. The calculator is the piece I care about most: three sliders, and an output nobody in this category publishes, which is how much blended return has to improve just to cover the fee. And the contact form answers you before you submit: choosing “under £15,000 a month” tells you not to hire them.

The trade-off

The counters, the filter and the calculator all push meaningful content into client components, which costs first-paint weight on a site whose entire argument is discipline about performance. I kept the case study prose, the method, pricing and footer on the server and only paid for interactivity where it earns its place. The honest version, though, is that the calculator could have been a static table and I chose the interaction anyway, because letting a sceptic put their own numbers in is worth more than the kilobytes it costs.

The related bug was worse than the trade-off. The stat counters started at useState(0) and animated up on intersection, which meant the prerendered HTML shipped the entire proof band as £0.0m / 0 / 0.00 / 0.0 yrs, directly under a headline claiming £41.6m. With JavaScript off, that is what the page said. They now render the real figure on the server and only wind back to zero if the element starts below the fold, where the animation would actually be seen by somebody.

Last thing, because it cost me a day. This build environment has no route to Google Fonts, so every screenshot I took renders the system fallback rather than Archivo. That is why I stopped signing off type from screenshots and started sizing it from the font’s own advance widths, which is how the hero bug got found. The layout, spacing, grid and hierarchy in the shots are real; the letterforms are not, and any judgement about the type in them is worthless. The rest of the working, including the research and the full accessibility audit, is on the research page.