{"id":25,"date":"2026-09-04T09:04:11","date_gmt":"2026-09-04T09:04:11","guid":{"rendered":"https:\/\/preview.deltatheme.com\/kiln\/home\/"},"modified":"2026-10-21T15:16:54","modified_gmt":"2026-10-21T15:16:54","slug":"home","status":"publish","type":"page","link":"https:\/\/preview.deltatheme.com\/kiln\/","title":{"rendered":"Kiln"},"content":{"rendered":"\n  <section class=\"hero\">\n    <div class=\"hero__copy\">\n      <p class=\"hero__eyebrow eyebrow\"><span class=\"hero__dot\"><\/span>Offensive security, Tallinn and remote<\/p>\n      <h1 class=\"hero__title\">We check the <span class=\"hero__accent\">locks<\/span>.<\/h1>\n      <p class=\"hero__lead\">Kiln is a small security practice in Tallinn. We are hired to attack systems under agreed rules and to write down what we found, how we found it, and what we could not establish.<\/p>\n      <div class=\"cluster\">\n        <a class=\"btn btn--primary\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Arrange a call <span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"arrow-right\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l14 0\"\/>\n  <path d=\"M13 18l6 -6\"\/>\n  <path d=\"M13 6l6 6\"\/>\n<\/svg><\/span><\/a>\n        <a class=\"btn btn--secondary\" href=\"https:\/\/preview.deltatheme.com\/kiln\/blog\/\">Read our notes <span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"file-search\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M14 3v4a1 1 0 0 0 1 1h4\"\/>\n  <path d=\"M12 21h-5a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v4.5\"\/>\n  <path d=\"M14 17.5a2.5 2.5 0 1 0 5 0a2.5 2.5 0 1 0 -5 0\"\/>\n  <path d=\"M18.5 19.5l2.5 2.5\"\/>\n<\/svg><\/span><\/a>\n      <\/div>\n    <\/div>\n    <figure class=\"hero__figure\">\n      <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-c-retest-lens.jpg\" alt=\"Collage of a magnifying glass over redacted documents beside a closed padlock and a coiled chain\" width=\"2496\" height=\"1664\">\n    <\/figure>\n  <\/section>\n\n  <ul class=\"stats\" data-delta-component=\"stat-bar\">\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">2019<\/span>\n      <span class=\"stats__label\">Founded, Tallinn<\/span>\n    <\/li>\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">7<\/span>\n      <span class=\"stats__label\">People<\/span>\n    <\/li>\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">9<\/span>\n      <span class=\"stats__label\">Engagements a year<\/span>\n    <\/li>\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">19<\/span>\n      <span class=\"stats__label\">Advisories published<\/span>\n    <\/li>\n  <\/ul>\n\n  <div class=\"ticker\" data-delta-component=\"ticker\" aria-hidden=\"true\">\n    <div class=\"ticker__track\">\n      <ul class=\"ticker__run\">\n        <li class=\"ticker__item\">most findings are configuration, not code<\/li>\n        <li class=\"ticker__item\">the asset register is usually out of date<\/li>\n        <li class=\"ticker__item\">CI\/CD is production, whatever the diagram says<\/li>\n        <li class=\"ticker__item\">the failed routes are worth writing down<\/li>\n        <li class=\"ticker__item\">identity is where the boundaries actually are<\/li>\n        <li class=\"ticker__item\">a fix that holds at ninety days is a fix<\/li>\n      <\/ul>\n      <ul class=\"ticker__run\">\n        <li class=\"ticker__item\">most findings are configuration, not code<\/li>\n        <li class=\"ticker__item\">the asset register is usually out of date<\/li>\n        <li class=\"ticker__item\">CI\/CD is production, whatever the diagram says<\/li>\n        <li class=\"ticker__item\">the failed routes are worth writing down<\/li>\n        <li class=\"ticker__item\">identity is where the boundaries actually are<\/li>\n        <li class=\"ticker__item\">a fix that holds at ninety days is a fix<\/li>\n      <\/ul>\n    <\/div>\n  <\/div>\n\n  <section class=\"section\">\n    <header class=\"sechead\" data-delta-component=\"section-head\">\n      <p class=\"sechead__eyebrow eyebrow\">Capability<\/p>\n      <h2 class=\"sechead__title\">Our Services<\/h2>\n      <p class=\"sechead__lead\">Six kinds of engagement. All of them are people reading systems carefully; none of them is a product, and none of them runs without you.<\/p>\n    <\/header>\n    <ul class=\"cells cells--3\">\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"broadcast\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M18.364 19.364a9 9 0 1 0 -12.728 0\"\/>\n  <path d=\"M15.536 16.536a5 5 0 1 0 -7.072 0\"\/>\n  <path d=\"M11 13a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Adversary simulation<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 8 weeks<\/p>\n        <p class=\"feature__body\">An attack against your live estate, under rules you set. We work from the outside in and record the route as we go.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"file-search\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M14 3v4a1 1 0 0 0 1 1h4\"\/>\n  <path d=\"M12 21h-5a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v4.5\"\/>\n  <path d=\"M14 17.5a2.5 2.5 0 1 0 5 0a2.5 2.5 0 1 0 -5 0\"\/>\n  <path d=\"M18.5 19.5l2.5 2.5\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Application testing<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 6 weeks<\/p>\n        <p class=\"feature__body\">Review of web, mobile and API surfaces, with the source where you can share it. Findings come with something you can reproduce.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"server-bolt\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-2\"\/>\n  <path d=\"M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12\"\/>\n  <path d=\"M7 8v.01\"\/>\n  <path d=\"M7 16v.01\"\/>\n  <path d=\"M20 15l-2 3h3l-2 3\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Cloud and identity<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 4 weeks<\/p>\n        <p class=\"feature__body\">AWS, Azure and GCP tenancy review: role chains, trust boundaries, and credentials that outlived whoever issued them.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"bug\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M9 9v-1a3 3 0 0 1 6 0v1\"\/>\n  <path d=\"M8 9h8a6 6 0 0 1 1 3v3a5 5 0 0 1 -10 0v-3a6 6 0 0 1 1 -3\"\/>\n  <path d=\"M3 13l4 0\"\/>\n  <path d=\"M17 13l4 0\"\/>\n  <path d=\"M12 20l0 -6\"\/>\n  <path d=\"M4 19l3.35 -2\"\/>\n  <path d=\"M20 19l-3.35 -2\"\/>\n  <path d=\"M4 7l3.75 2.4\"\/>\n  <path d=\"M20 7l-3.75 2.4\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Vulnerability research<\/h3>\n        <p class=\"feature__meta\">Ongoing<\/p>\n        <p class=\"feature__body\">Research on software we and our clients depend on. Nineteen advisories published so far, all coordinated with the vendor.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/blog\/\">Read the advisories<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"activity\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M3 12h4l3 8l4 -16l3 8h4\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Detection engineering<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 3 weeks<\/p>\n        <p class=\"feature__body\">Turning an engagement into detections. We write rules for what we did, then check with your team whether they fire.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"lock-open\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2l0 -6\"\/>\n  <path d=\"M11 16a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\"\/>\n  <path d=\"M8 11v-5a4 4 0 0 1 8 0\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Incident response<\/h3>\n        <p class=\"feature__meta\">Retainer<\/p>\n        <p class=\"feature__body\">Help during and after an incident, for clients on a retainer. Containment first; attribution only where the evidence supports it.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n    <\/ul>\n  <\/section>\n\n  <section class=\"section\">\n    <header class=\"sechead\" data-delta-component=\"section-head\">\n      <p class=\"sechead__eyebrow eyebrow\">Team<\/p>\n      <h2 class=\"sechead__title\">Seven people.<\/h2>\n      <p class=\"sechead__lead\">You are told who will be working on your systems before the engagement starts. Four of us are below; three work under client agreements that do not allow a public profile.<\/p>\n    <\/header>\n    <ul class=\"cells cells--4\">\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-eleni-sarris.jpg\" alt=\"Eleni Sarris\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Principal<\/p>\n        <h3 class=\"person__name\">Eleni Sarris<\/h3>\n        <p class=\"person__line\">Writes the rules of engagement and leads the longer jobs.<\/p>\n      <\/li>\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-marcus-bramwell.jpg\" alt=\"Marcus Bramwell\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Head of research<\/p>\n        <h3 class=\"person__name\">Marcus Bramwell<\/h3>\n        <p class=\"person__line\">Most of our published advisories came out of his research.<\/p>\n      <\/li>\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-nadia-okonjo.jpg\" alt=\"Nadia Okonjo\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Cloud and identity<\/p>\n        <h3 class=\"person__name\">Nadia Okonjo<\/h3>\n        <p class=\"person__line\">Came from platform engineering; sends findings as pull requests.<\/p>\n      <\/li>\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-tomas-reinholt.jpg\" alt=\"Tomas Reinholt\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Detection engineering<\/p>\n        <h3 class=\"person__name\">Tomas Reinholt<\/h3>\n        <p class=\"person__line\">Works on the defensive half, and on whether the rules fire.<\/p>\n      <\/li>\n    <\/ul>\n    <div class=\"secfoot\">\n      <a class=\"secfoot__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/about\/\">More about the team<\/a>\n    <\/div>\n  <\/section>\n\n  <section class=\"next\">\n    <div class=\"next__copy inverted\">\n      <header class=\"sechead\" data-delta-component=\"section-head\">\n        <p class=\"sechead__eyebrow eyebrow\">Getting in touch<\/p>\n        <h2 class=\"sechead__title\">Start with a call.<\/h2>\n        <p class=\"sechead__lead\">Forty minutes, at no cost, to work out whether this is a job we can do well. Sometimes the answer is no, and we would rather find that out early.<\/p>\n      <\/header>\n      <div class=\"next__inner\">\n        <ul class=\"checks\" data-delta-component=\"checklist\">\n          <li class=\"checks__item\">\n            <span class=\"checks__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"check\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l5 5l10 -10\"\/>\n<\/svg><\/span><\/span>\n            <p class=\"checks__text\">We reply within a working day.<\/p>\n          <\/li>\n          <li class=\"checks__item\">\n            <span class=\"checks__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"check\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l5 5l10 -10\"\/>\n<\/svg><\/span><\/span>\n            <p class=\"checks__text\">An NDA before anything technical is discussed.<\/p>\n          <\/li>\n          <li class=\"checks__item\">\n            <span class=\"checks__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"check\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l5 5l10 -10\"\/>\n<\/svg><\/span><\/span>\n            <p class=\"checks__text\">You will be talking to someone who does the work.<\/p>\n          <\/li>\n        <\/ul>\n      <\/div>\n    <\/div>\n\n    <div class=\"next__form\">\n      <div class=\"intake\" data-delta-component=\"intake-form\">\n      <p class=\"prompt\"><span class=\"prompt__host\">kiln@intake:~$<\/span> new-engagement<\/p>\n      <form class=\"form\" novalidate>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-name\">Name <span class=\"field__req\">*<\/span><\/label>\n          <input class=\"field__in\" id=\"f-name\" name=\"name\" type=\"text\" required autocomplete=\"name\">\n        <\/div>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-org\">Organisation <span class=\"field__req\">*<\/span><\/label>\n          <input class=\"field__in\" id=\"f-org\" name=\"organisation\" type=\"text\" required autocomplete=\"organization\">\n        <\/div>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-email\">Work email <span class=\"field__req\">*<\/span><\/label>\n          <input class=\"field__in\" id=\"f-email\" name=\"email\" type=\"email\" required autocomplete=\"email\">\n        <\/div>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-type\">Engagement type<\/label>\n          <select class=\"field__in\" id=\"f-type\" name=\"type\">\n            <option>Adversary simulation<\/option>\n            <option>Application testing<\/option>\n            <option>Cloud and identity<\/option>\n            <option>Vulnerability research<\/option>\n            <option>Detection engineering<\/option>\n            <option>Incident response<\/option>\n          <\/select>\n        <\/div>\n        <div class=\"field field--wide\">\n          <label class=\"field__lbl\" for=\"f-brief\">What are you protecting? <span class=\"field__req\">*<\/span><\/label>\n          <textarea class=\"field__in field__in--area\" id=\"f-brief\" name=\"brief\" rows=\"6\" required><\/textarea>\n          <p class=\"field__hint\">Rough estate size, sector, and anything that has already gone wrong.<\/p>\n        <\/div>\n        <div class=\"form__foot\">\n          <div class=\"field__check\">\n            <input class=\"field__box\" id=\"f-nda\" name=\"nda\" type=\"checkbox\">\n            <label class=\"field__lbl field__lbl--inline\" for=\"f-nda\">Send me an NDA before we speak<\/label>\n          <\/div>\n        <\/div>\n        <button class=\"btn btn--primary form__send\" type=\"submit\">Send the brief<\/button>\n        <p class=\"form__msg\" role=\"status\"><\/p>\n        <p class=\"form__fine\">Encrypted in transit. We keep intake notes for ninety days, then delete them.<\/p>\n      <\/form>\n      <\/div>\n    <\/div>\n  <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Offensive security, Tallinn and remote We check the locks. Kiln is a small security practice in Tallinn. We are hired to attack systems under agreed rules and to write down what we found, how we found it, and what we could not establish. Arrange a call Read our notes 2019 Founded, Tallinn 7 People 9 Engagements a year 19 Advisories published most findings are configuration, not code the asset register is usually out of date CI\/CD is production, whatever the diagram says the failed routes are<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-25","page","type-page","status-publish","hentry"],"delta":{"html":"\n  <section class=\"hero\">\n    <div class=\"hero__copy\">\n      <p class=\"hero__eyebrow eyebrow\"><span class=\"hero__dot\"><\/span>Offensive security, Tallinn and remote<\/p>\n      <h1 class=\"hero__title\">We check the <span class=\"hero__accent\">locks<\/span>.<\/h1>\n      <p class=\"hero__lead\">Kiln is a small security practice in Tallinn. We are hired to attack systems under agreed rules and to write down what we found, how we found it, and what we could not establish.<\/p>\n      <div class=\"cluster\">\n        <a class=\"btn btn--primary\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Arrange a call <span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"arrow-right\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l14 0\"\/>\n  <path d=\"M13 18l6 -6\"\/>\n  <path d=\"M13 6l6 6\"\/>\n<\/svg><\/span><\/a>\n        <a class=\"btn btn--secondary\" href=\"https:\/\/preview.deltatheme.com\/kiln\/blog\/\">Read our notes <span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"file-search\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M14 3v4a1 1 0 0 0 1 1h4\"\/>\n  <path d=\"M12 21h-5a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v4.5\"\/>\n  <path d=\"M14 17.5a2.5 2.5 0 1 0 5 0a2.5 2.5 0 1 0 -5 0\"\/>\n  <path d=\"M18.5 19.5l2.5 2.5\"\/>\n<\/svg><\/span><\/a>\n      <\/div>\n    <\/div>\n    <figure class=\"hero__figure\">\n      <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-c-retest-lens.jpg\" alt=\"Collage of a magnifying glass over redacted documents beside a closed padlock and a coiled chain\" width=\"2496\" height=\"1664\">\n    <\/figure>\n  <\/section>\n\n  <ul class=\"stats\" data-delta-component=\"stat-bar\">\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">2019<\/span>\n      <span class=\"stats__label\">Founded, Tallinn<\/span>\n    <\/li>\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">7<\/span>\n      <span class=\"stats__label\">People<\/span>\n    <\/li>\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">9<\/span>\n      <span class=\"stats__label\">Engagements a year<\/span>\n    <\/li>\n    <li class=\"stats__cell\">\n      <span class=\"stats__figure\">19<\/span>\n      <span class=\"stats__label\">Advisories published<\/span>\n    <\/li>\n  <\/ul>\n\n  <div class=\"ticker\" data-delta-component=\"ticker\" aria-hidden=\"true\">\n    <div class=\"ticker__track\">\n      <ul class=\"ticker__run\">\n        <li class=\"ticker__item\">most findings are configuration, not code<\/li>\n        <li class=\"ticker__item\">the asset register is usually out of date<\/li>\n        <li class=\"ticker__item\">CI\/CD is production, whatever the diagram says<\/li>\n        <li class=\"ticker__item\">the failed routes are worth writing down<\/li>\n        <li class=\"ticker__item\">identity is where the boundaries actually are<\/li>\n        <li class=\"ticker__item\">a fix that holds at ninety days is a fix<\/li>\n      <\/ul>\n      <ul class=\"ticker__run\">\n        <li class=\"ticker__item\">most findings are configuration, not code<\/li>\n        <li class=\"ticker__item\">the asset register is usually out of date<\/li>\n        <li class=\"ticker__item\">CI\/CD is production, whatever the diagram says<\/li>\n        <li class=\"ticker__item\">the failed routes are worth writing down<\/li>\n        <li class=\"ticker__item\">identity is where the boundaries actually are<\/li>\n        <li class=\"ticker__item\">a fix that holds at ninety days is a fix<\/li>\n      <\/ul>\n    <\/div>\n  <\/div>\n\n  <section class=\"section\">\n    <header class=\"sechead\" data-delta-component=\"section-head\">\n      <p class=\"sechead__eyebrow eyebrow\">Capability<\/p>\n      <h2 class=\"sechead__title\">Our Services<\/h2>\n      <p class=\"sechead__lead\">Six kinds of engagement. All of them are people reading systems carefully; none of them is a product, and none of them runs without you.<\/p>\n    <\/header>\n    <ul class=\"cells cells--3\">\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"broadcast\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M18.364 19.364a9 9 0 1 0 -12.728 0\"\/>\n  <path d=\"M15.536 16.536a5 5 0 1 0 -7.072 0\"\/>\n  <path d=\"M11 13a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Adversary simulation<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 8 weeks<\/p>\n        <p class=\"feature__body\">An attack against your live estate, under rules you set. We work from the outside in and record the route as we go.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"file-search\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M14 3v4a1 1 0 0 0 1 1h4\"\/>\n  <path d=\"M12 21h-5a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v4.5\"\/>\n  <path d=\"M14 17.5a2.5 2.5 0 1 0 5 0a2.5 2.5 0 1 0 -5 0\"\/>\n  <path d=\"M18.5 19.5l2.5 2.5\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Application testing<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 6 weeks<\/p>\n        <p class=\"feature__body\">Review of web, mobile and API surfaces, with the source where you can share it. Findings come with something you can reproduce.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"server-bolt\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M3 7a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-2\"\/>\n  <path d=\"M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12\"\/>\n  <path d=\"M7 8v.01\"\/>\n  <path d=\"M7 16v.01\"\/>\n  <path d=\"M20 15l-2 3h3l-2 3\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Cloud and identity<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 4 weeks<\/p>\n        <p class=\"feature__body\">AWS, Azure and GCP tenancy review: role chains, trust boundaries, and credentials that outlived whoever issued them.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"bug\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M9 9v-1a3 3 0 0 1 6 0v1\"\/>\n  <path d=\"M8 9h8a6 6 0 0 1 1 3v3a5 5 0 0 1 -10 0v-3a6 6 0 0 1 1 -3\"\/>\n  <path d=\"M3 13l4 0\"\/>\n  <path d=\"M17 13l4 0\"\/>\n  <path d=\"M12 20l0 -6\"\/>\n  <path d=\"M4 19l3.35 -2\"\/>\n  <path d=\"M20 19l-3.35 -2\"\/>\n  <path d=\"M4 7l3.75 2.4\"\/>\n  <path d=\"M20 7l-3.75 2.4\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Vulnerability research<\/h3>\n        <p class=\"feature__meta\">Ongoing<\/p>\n        <p class=\"feature__body\">Research on software we and our clients depend on. Nineteen advisories published so far, all coordinated with the vendor.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/blog\/\">Read the advisories<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"activity\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M3 12h4l3 8l4 -16l3 8h4\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Detection engineering<\/h3>\n        <p class=\"feature__meta\">Typical engagement: 3 weeks<\/p>\n        <p class=\"feature__body\">Turning an engagement into detections. We write rules for what we did, then check with your team whether they fire.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n      <li class=\"feature\" data-delta-component=\"feature-card\">\n        <span class=\"feature__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"lock-open\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2l0 -6\"\/>\n  <path d=\"M11 16a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\"\/>\n  <path d=\"M8 11v-5a4 4 0 0 1 8 0\"\/>\n<\/svg><\/span><\/span>\n        <h3 class=\"feature__title\">Incident response<\/h3>\n        <p class=\"feature__meta\">Retainer<\/p>\n        <p class=\"feature__body\">Help during and after an incident, for clients on a retainer. Containment first; attribution only where the evidence supports it.<\/p>\n        <a class=\"feature__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/book-a-call\/\">Ask about this<\/a>\n      <\/li>\n    <\/ul>\n  <\/section>\n\n  <section class=\"section\">\n    <header class=\"sechead\" data-delta-component=\"section-head\">\n      <p class=\"sechead__eyebrow eyebrow\">Team<\/p>\n      <h2 class=\"sechead__title\">Seven people.<\/h2>\n      <p class=\"sechead__lead\">You are told who will be working on your systems before the engagement starts. Four of us are below; three work under client agreements that do not allow a public profile.<\/p>\n    <\/header>\n    <ul class=\"cells cells--4\">\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-eleni-sarris.jpg\" alt=\"Eleni Sarris\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Principal<\/p>\n        <h3 class=\"person__name\">Eleni Sarris<\/h3>\n        <p class=\"person__line\">Writes the rules of engagement and leads the longer jobs.<\/p>\n      <\/li>\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-marcus-bramwell.jpg\" alt=\"Marcus Bramwell\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Head of research<\/p>\n        <h3 class=\"person__name\">Marcus Bramwell<\/h3>\n        <p class=\"person__line\">Most of our published advisories came out of his research.<\/p>\n      <\/li>\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-nadia-okonjo.jpg\" alt=\"Nadia Okonjo\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Cloud and identity<\/p>\n        <h3 class=\"person__name\">Nadia Okonjo<\/h3>\n        <p class=\"person__line\">Came from platform engineering; sends findings as pull requests.<\/p>\n      <\/li>\n      <li class=\"person\" data-delta-component-opt-out=\"person\">\n        <figure class=\"person__fig\">\n          <img src=\"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/2026\/09\/kiln-tomas-reinholt.jpg\" alt=\"Tomas Reinholt\" width=\"600\" height=\"600\">\n        <\/figure>\n        <p class=\"person__role eyebrow\">Detection engineering<\/p>\n        <h3 class=\"person__name\">Tomas Reinholt<\/h3>\n        <p class=\"person__line\">Works on the defensive half, and on whether the rules fire.<\/p>\n      <\/li>\n    <\/ul>\n    <div class=\"secfoot\">\n      <a class=\"secfoot__link\" href=\"https:\/\/preview.deltatheme.com\/kiln\/about\/\">More about the team<\/a>\n    <\/div>\n  <\/section>\n\n  <section class=\"next\">\n    <div class=\"next__copy inverted\">\n      <header class=\"sechead\" data-delta-component=\"section-head\">\n        <p class=\"sechead__eyebrow eyebrow\">Getting in touch<\/p>\n        <h2 class=\"sechead__title\">Start with a call.<\/h2>\n        <p class=\"sechead__lead\">Forty minutes, at no cost, to work out whether this is a job we can do well. Sometimes the answer is no, and we would rather find that out early.<\/p>\n      <\/header>\n      <div class=\"next__inner\">\n        <ul class=\"checks\" data-delta-component=\"checklist\">\n          <li class=\"checks__item\">\n            <span class=\"checks__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"check\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l5 5l10 -10\"\/>\n<\/svg><\/span><\/span>\n            <p class=\"checks__text\">We reply within a working day.<\/p>\n          <\/li>\n          <li class=\"checks__item\">\n            <span class=\"checks__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"check\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l5 5l10 -10\"\/>\n<\/svg><\/span><\/span>\n            <p class=\"checks__text\">An NDA before anything technical is discussed.<\/p>\n          <\/li>\n          <li class=\"checks__item\">\n            <span class=\"checks__ico\"><span class=\"delta-icon\" data-delta-icon-pack=\"tabler-outline\" data-delta-icon=\"check\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n  <path d=\"M5 12l5 5l10 -10\"\/>\n<\/svg><\/span><\/span>\n            <p class=\"checks__text\">You will be talking to someone who does the work.<\/p>\n          <\/li>\n        <\/ul>\n      <\/div>\n    <\/div>\n\n    <div class=\"next__form\">\n      <div class=\"intake\" data-delta-component=\"intake-form\">\n      <p class=\"prompt\"><span class=\"prompt__host\">kiln@intake:~$<\/span> new-engagement<\/p>\n      <form class=\"form\" novalidate>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-name\">Name <span class=\"field__req\">*<\/span><\/label>\n          <input class=\"field__in\" id=\"f-name\" name=\"name\" type=\"text\" required autocomplete=\"name\">\n        <\/div>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-org\">Organisation <span class=\"field__req\">*<\/span><\/label>\n          <input class=\"field__in\" id=\"f-org\" name=\"organisation\" type=\"text\" required autocomplete=\"organization\">\n        <\/div>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-email\">Work email <span class=\"field__req\">*<\/span><\/label>\n          <input class=\"field__in\" id=\"f-email\" name=\"email\" type=\"email\" required autocomplete=\"email\">\n        <\/div>\n        <div class=\"field\">\n          <label class=\"field__lbl\" for=\"f-type\">Engagement type<\/label>\n          <select class=\"field__in\" id=\"f-type\" name=\"type\">\n            <option>Adversary simulation<\/option>\n            <option>Application testing<\/option>\n            <option>Cloud and identity<\/option>\n            <option>Vulnerability research<\/option>\n            <option>Detection engineering<\/option>\n            <option>Incident response<\/option>\n          <\/select>\n        <\/div>\n        <div class=\"field field--wide\">\n          <label class=\"field__lbl\" for=\"f-brief\">What are you protecting? <span class=\"field__req\">*<\/span><\/label>\n          <textarea class=\"field__in field__in--area\" id=\"f-brief\" name=\"brief\" rows=\"6\" required><\/textarea>\n          <p class=\"field__hint\">Rough estate size, sector, and anything that has already gone wrong.<\/p>\n        <\/div>\n        <div class=\"form__foot\">\n          <div class=\"field__check\">\n            <input class=\"field__box\" id=\"f-nda\" name=\"nda\" type=\"checkbox\">\n            <label class=\"field__lbl field__lbl--inline\" for=\"f-nda\">Send me an NDA before we speak<\/label>\n          <\/div>\n        <\/div>\n        <button class=\"btn btn--primary form__send\" type=\"submit\">Send the brief<\/button>\n        <p class=\"form__msg\" role=\"status\"><\/p>\n        <p class=\"form__fine\">Encrypted in transit. We keep intake notes for ninety days, then delete them.<\/p>\n      <\/form>\n      <\/div>\n    <\/div>\n  <\/section>\n","css":"\/* Home \u2014 page-scoped layout. The ruled cell grid and section foot are shared\n   utilities and live in site.css. *\/\n\n.hero {\n  display: grid;\n  border-bottom: var(--rule);\n}\n\n.hero__copy {\n  padding: var(--space-4xl) var(--pad);\n  align-self: center;\n}\n\n.hero__eyebrow {\n  display: flex;\n  align-items: center;\n  gap: var(--space-xs);\n  margin: 0 0 var(--space-lg);\n  color: var(--color-action);\n}\n\n.hero__dot {\n  inline-size: var(--space-xs);\n  block-size: var(--space-xs);\n  border-radius: var(--radius-full);\n  background: currentColor;\n  flex: none;\n}\n\n.hero__title {\n  margin: 0 0 var(--space-xl);\n  font-family: var(--font-display);\n  font-size: var(--title-display-size);\n  line-height: var(--title-display-leading);\n  letter-spacing: var(--title-display-tracking);\n  font-weight: var(--weight-bold);\n  text-transform: uppercase;\n  text-wrap: balance;\n}\n\n.hero__accent {\n  color: var(--color-action);\n}\n\n.hero__lead {\n  margin: 0 0 var(--space-xl);\n  max-width: var(--line-length-sm);\n  font-size: var(--text-lg-size);\n  line-height: var(--text-lg-leading);\n  letter-spacing: var(--text-lg-tracking);\n  color: var(--color-ink-muted);\n}\n\n\/* Fixed ratio plus overflow:hidden. aspect-ratio:auto with min-block-size would\n   depend on intrinsic pixel dimensions and lets the box escape its column. *\/\n.hero__figure {\n  margin: 0;\n  aspect-ratio: 4 \/ 5;\n  overflow: hidden;\n  border-left: var(--rule);\n  background: var(--color-surface-subtle);\n}\n\n.hero__figure img {\n  display: block;\n  inline-size: 100%;\n  block-size: 100%;\n  object-fit: cover;\n}\n\n\/* Home is exempt from the page-title hierarchy. Section heads across the site\n   step down to --title-lg so a page's h1 outranks the h2s under it. Home has no\n   h1 in a section head \u2014 the hero carries it at --title-display \u2014 so nothing\n   here would outrank anything, and dropping these three to lg only flattens a\n   page whose rhythm already works. They stay at xl.\n\n   h2 prefix for weight: 0,1,1 against the component's 0,1,0, so this wins\n   whichever order the two stylesheets load in. *\/\nh2.sechead__title {\n  font-size: var(--title-xl-size);\n  line-height: var(--title-xl-leading);\n  letter-spacing: var(--title-xl-tracking);\n}\n\n\/* Contact block \u2014 copy on the subtle surface, form on the body surface. *\/\n.next {\n  display: grid;\n}\n\n\/* The copy column takes the inverted context. On the subtle surface it was\n   1.1:1 against the page ground \u2014 the panel did not read as a panel at all. The\n   context class supplies the ground and rebinds ink, border and surface with\n   it, so the checklist rules inside stay legible without a rule of their own. *\/\n.next__copy {\n  padding: 0 0 var(--space-3xl);\n}\n\n.next__inner {\n  padding-inline: var(--pad);\n}\n\n\/* The form column sits one step off the page ground. The controls keep\n   --color-surface-body, so the fields read as cut into the panel rather than\n   floating on it. *\/\n.next__form {\n  padding: var(--space-3xl) var(--pad);\n  background: var(--color-surface-subtle);\n}\n\n\/* The intake form is a component: markup, type, grid and validation all travel\n   with it. This page only places it. *\/\n\n@media (max-width: 63.99rem) {\n  .hero__figure {\n    aspect-ratio: 3 \/ 2;\n    border-left: 0;\n    border-top: var(--rule);\n  }\n}\n\n@media (min-width: 64rem) {\n  .hero {\n    grid-template-columns: 1fr 1fr;\n  }\n\n  .next {\n    grid-template-columns: 1fr 1fr;\n  }\n\n  .next__copy {\n    border-right: var(--rule);\n  }\n}","js":"","styles":[{"handle":"21press-delta-tokens","url":"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/21press-delta\/site\/tokens.css","inline":""},{"handle":"21press-delta-engine","url":"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/themes\/delta\/assets\/frontend\/css\/base.css","inline":""},{"handle":"21press-delta-components","url":"https:\/\/preview.deltatheme.com\/kiln\/wp-content\/uploads\/sites\/2\/21press-delta\/site\/components.css","inline":"\/**\n * Site CSS \u2014 element defaults, composed properties, surface rows, context classes.\n * Delta's floor (reset, page frame, nav reset) lives in the theme's base.css.\n * Agent-authored via set-site-assets. Prefer var(--\u2026) from tokens.css.\n *\n * Colour works in rows. tokens.css holds the light row on :root. This file\n * holds the dark row and the contrast row, the same job names with other\n * values. A section switches rows with one class (surface-contrast); the\n * whole site switches with data-theme=\"dark\" on <html>. Nothing inside a\n * section changes: every element reads the same names.\n *\/\n\n:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {\n  outline: 2px solid var(--color-focus, var(--color-action));\n  outline-offset: 2px;\n}\n\nul.delta-nav ul {\n  padding-left: var(--space-md);\n}\n\nbody {\n  font-family: var(--font-text);\n  font-size: var(--text-md-size);\n  line-height: var(--text-md-leading);\n  letter-spacing: var(--text-md-tracking);\n}\n\nh1,\nh2,\nh3,\nh4 {\n  font-family: var(--font-title);\n  color: var(--color-ink);\n}\n\nh1 {\n  font-size: var(--title-xl-size);\n  line-height: var(--title-xl-leading);\n  letter-spacing: var(--title-xl-tracking);\n  font-weight: var(--weight-semibold);\n}\n\nh2 {\n  font-size: var(--title-lg-size);\n  line-height: var(--title-lg-leading);\n  letter-spacing: var(--title-lg-tracking);\n  font-weight: var(--weight-semibold);\n}\n\nh3 {\n  font-size: var(--title-md-size);\n  line-height: var(--title-md-leading);\n  letter-spacing: var(--title-md-tracking);\n  font-weight: var(--weight-semibold);\n}\n\ncode,\nkbd,\nsamp {\n  font-family: var(--font-mono);\n  font-size: var(--text-code-size);\n  line-height: var(--text-code-leading);\n}\n\npre {\n  font-family: var(--font-mono);\n  font-size: var(--text-code-size);\n  line-height: var(--text-code-leading);\n  overflow-x: auto;\n}\n\n\/* The block already took the code size; code inside it must not shrink again. *\/\npre code {\n  font-size: inherit;\n  line-height: inherit;\n}\n\n\/* Eyebrow: a kicker above a heading, set in the label step. Not a heading. *\/\n.eyebrow {\n  font-size: var(--text-label-size);\n  line-height: var(--text-label-leading);\n  letter-spacing: var(--text-label-tracking);\n  text-transform: uppercase;\n  font-weight: var(--weight-semibold);\n  color: var(--color-ink-muted);\n}\n\n\/**\n * Content rhythm. The floor zeroes browser margins; this puts space above each\n * text block, between siblings only, so the first and last never leave a gap.\n * Zero specificity (:where), so any template or recipe rule wins.\n *\/\n:where(p, ul, ol, dl, pre, blockquote, figure, table) + :where(p, ul, ol, dl, pre, blockquote, figure, table) {\n  margin-block-start: var(--space-sm);\n}\n\n:where(p) + :where(p) {\n  margin-block-start: var(--space-md);\n}\n\n:where(h1, h2, h3, h4, h5, h6) + :where(p, ul, ol, dl, pre, blockquote, figure, table) {\n  margin-block-start: var(--space-sm);\n}\n\n\/* A page title wants one step more under it than a heading in the flow. *\/\n:where(h1) + :where(p, ul, ol, dl, pre, blockquote, figure, table) {\n  margin-block-start: var(--space-md);\n}\n\n:where(p, ul, ol, dl, pre, blockquote, figure, table) + :where(h1, h2, h3, h4, h5, h6) {\n  margin-block-start: var(--space-lg);\n}\n\n:where(.eyebrow) + :where(h1, h2, h3, h4, h5, h6) {\n  margin-block-start: var(--space-xs);\n}\n\n\/* Unclassed text links only. A bare `a` \/ `a:hover` colour rule is 0,1,1 on\n   hover and paints `.btn` labels the same colour as the fill. *\/\na:not([class]) {\n  color: var(--color-ink);\n}\n\na:not([class]):hover {\n  color: var(--color-ink-muted);\n}\n\n.section__inner {\n  \/* Running text. A shorter line: calc(var(--layout-content) * 0.7) \u2014 never a raw ch. *\/\n  max-width: var(--layout-content);\n  font-size: var(--text-md-size);\n  line-height: var(--text-md-leading);\n  letter-spacing: var(--text-md-tracking);\n  color: var(--color-ink);\n}\n\n.section__inner h2,\n.section__inner h3 {\n  font-family: var(--font-title);\n  font-weight: var(--weight-medium);\n}\n\n.section__inner h2 {\n  font-size: var(--title-lg-size);\n  line-height: var(--title-lg-leading);\n  letter-spacing: var(--title-lg-tracking);\n}\n\n.section__inner h3 {\n  font-size: var(--title-md-size);\n  line-height: var(--title-md-leading);\n  letter-spacing: var(--title-md-tracking);\n}\n\n.section__inner p {\n  color: var(--color-ink-muted);\n}\n\n\/* Links inside body text only. Never a bare `.x a { color }` (0,1,1): it outranks\n   a component's own color (.btn is 0,1,0) and paints button labels invisible.\n   The link_color_scope write invariant enforces this; the seed obeys it too.\n   Hover must be restated: this selector ties a:not([class]):hover at 0,2,1. *\/\n.section__inner a:not([class]) {\n  color: var(--color-ink);\n}\n\n.section__inner a:not([class]):hover {\n  color: var(--color-ink-muted);\n}\n\n\/**\n * Surface rows.\n *\n * The light row lives in tokens.css (:root). The two rows below set the same\n * job names with other values. A component never knows which row it is in.\n *\/\n\n\/* Site-wide dark mode: data-theme=\"dark\" on <html>. Inert until something\n   sets it (the light-and-dark recipe adds a header script and a toggle).\n   Declared on :root, never on body: a value on body would override the\n   dark value body inherits from <html>. *\/\n:root[data-theme=\"dark\"] {\n  --color-surface-body: #18181B;\n  --color-surface-subtle: #1F1F22;\n  --color-surface-raised: #27272A;\n  --color-ink: #FAFAFA;\n  --color-ink-muted: #A1A1AA;\n  --color-border: #3F3F46;\n  --color-action: #FAFAFA;\n  --color-action-hover: #E4E4E7;\n  --color-action-subtle: #27272A;\n  --color-focus: #FAFAFA;\n  --color-on-action: #18181B;\n  --color-danger: #F87171;\n  --color-danger-bg: #452A2C;\n  --color-success: #4ADE80;\n  --color-success-bg: #224030;\n  --color-warning: #FBBF24;\n  --color-warning-bg: #45391D;\n  \/* Shadows need their own dark values: a light shadow on a dark ground is invisible. *\/\n  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 \/ 0.4);\n  --shadow-md: 0 4px 6px -1px rgb(0 0 0 \/ 0.5), 0 2px 4px -2px rgb(0 0 0 \/ 0.5);\n  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 \/ 0.6), 0 4px 6px -4px rgb(0 0 0 \/ 0.6);\n}\n\n\/* The inverted band: dark on a light page, one per page. Same values as the\n   dark row. Put the class (or the attribute) on the section wrapper and\n   nothing inside it needs to change. *\/\n.surface-contrast,\n[data-surface=\"contrast\"] {\n  --color-surface-body: #18181B;\n  --color-surface-subtle: #1F1F22;\n  --color-surface-raised: #27272A;\n  --color-ink: #FAFAFA;\n  --color-ink-muted: #A1A1AA;\n  --color-border: #3F3F46;\n  --color-action: #FAFAFA;\n  --color-action-hover: #E4E4E7;\n  --color-action-subtle: #27272A;\n  --color-focus: #FAFAFA;\n  --color-on-action: #18181B;\n  --color-danger: #F87171;\n  --color-danger-bg: #452A2C;\n  --color-success: #4ADE80;\n  --color-success-bg: #224030;\n  --color-warning: #FBBF24;\n  --color-warning-bg: #45391D;\n  \/* Shadows need their own dark values: a light shadow on a dark ground is invisible. *\/\n  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 \/ 0.4);\n  --shadow-md: 0 4px 6px -1px rgb(0 0 0 \/ 0.5), 0 2px 4px -2px rgb(0 0 0 \/ 0.5);\n  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 \/ 0.6), 0 4px 6px -4px rgb(0 0 0 \/ 0.6);\n}\n\n\/* The inverted band on a dark page is light: the light row again. *\/\n:root[data-theme=\"dark\"] .surface-contrast,\n:root[data-theme=\"dark\"] [data-surface=\"contrast\"] {\n  --color-surface-body: #FFFFFF;\n  --color-surface-subtle: #F4F4F5;\n  --color-surface-raised: #FFFFFF;\n  --color-ink: #09090B;\n  --color-ink-muted: #6E6E77;\n  --color-border: #E4E4E7;\n  --color-action: #18181B;\n  --color-action-hover: #27272A;\n  --color-action-subtle: #F4F4F5;\n  --color-focus: #18181B;\n  --color-on-action: #FAFAFA;\n  --color-danger: #DC2626;\n  --color-danger-bg: #FEF2F2;\n  --color-success: #16A34A;\n  --color-success-bg: #F0FDF4;\n  --color-warning: #D97706;\n  --color-warning-bg: #FFFBEB;\n  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 \/ 0.05);\n  --shadow-md: 0 4px 6px -1px rgb(0 0 0 \/ 0.10), 0 2px 4px -2px rgb(0 0 0 \/ 0.10);\n  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 \/ 0.10), 0 4px 6px -4px rgb(0 0 0 \/ 0.10);\n}\n\n\/* Every surface paints its own row. `color` must be set here: it inherits as\n   an already computed value, so a rebinding alone would leave the old ink. *\/\nbody,\n.surface-contrast,\n[data-surface=\"contrast\"] {\n  background: var(--color-surface-body);\n  color: var(--color-ink);\n}\n\n\/* Quiet band between sections. Same row, one step off the page. *\/\n.surface-subtle {\n  background: var(--color-surface-subtle);\n}\n\n\/* A lifted card or panel. On light the border and shadow lift it; on dark\n   the tone does. The agent writes the class and never chooses between them. *\/\n.surface-raised {\n  background: var(--color-surface-raised);\n  border: var(--border-width) solid var(--color-border);\n  box-shadow: var(--shadow-sm);\n}\n\n\/* The contrast band in this site's own colours, carried over from the names the earlier seed gave them. *\/\n.surface-contrast,\n[data-surface=\"contrast\"] {\n  --color-surface-body: var(--color-surface-contrast);\n  --color-on-action: var(--color-surface-contrast);\n  --color-ink: var(--color-ink-on-contrast);\n  --color-action: var(--color-ink-on-contrast);\n  --color-focus: var(--color-ink-on-contrast);\n  --color-ink-muted: var(--color-ink-muted-on-contrast);\n  --color-action-hover: var(--color-ink-muted-on-contrast);\n  --color-border: var(--color-border-on-contrast);\n}\n\n\/**\n * Kept from this site at the seed upgrade: its own rules, its changes to seed\n * rules, and rules of the earlier seed that this seed has no version of.\n * They come after the seed's rules, so where both speak these win.\n *\/\n\n\/**\n * Site CSS \u2014 element defaults, composed properties, context classes.\n *\/\n\n\/* ---- Composed properties -------------------------------------------\n   Site-level decisions the token file does not carry. Bare names: the\n   --color-* \/ --space-* namespace belongs to tokens.json. *\/\n\/* Declared on every element, not on :root. A custom property that references\n   another is resolved on the element that declares it, and descendants inherit\n   the finished value. On :root these two froze to the light colours, so\n   .inverted and dark mode, which rebind --color-border and --color-ink, could\n   not reach them. On * each element resolves them from its own colour tokens. *\/\n* {\n  --rule: var(--border-width) solid var(--color-border);\n  \/* A control's edge is not a layout hairline. --color-border is 1.19:1 on the\n     page ground \u2014 fine for a rule that separates blocks, and a failure on\n     anything a person operates, where WCAG 1.4.11 asks for 3:1. Form controls\n     take this token; the secondary and ghost buttons take --color-ink-muted,\n     which clears the same floor without a token of its own.\n     Named here so the intent is on the record and the two can move apart. *\/\n  --color-field-border: var(--color-ink);\n}\n\n:root {\n  --pad: var(--layout-section-inline);\n  --mono-sm: var(--text-xs-size);\n  \/* Vertical rhythm. Named for the job, not the size \u2014 --gap-md would only be a\n     second word for --space-md and would not tell anyone where to use it.\n     These five say where they belong, so a block picks the one that matches its\n     relationship and the size follows. Change the mapping here and the rhythm\n     moves everywhere at once, which is the point of naming them at all.\n\n     Vertical space is set with `gap` on the parent, not margin on the child.\n     Where a block needs two rhythms \u2014 a label hugging its heading inside a\n     looser stack \u2014 nest a container rather than reaching back for margins.\n     Two exceptions that gap cannot express: `margin-top: auto` pinning a link\n     to the bottom of a card, and the space below the last child of a block,\n     which is that block's padding. *\/\n  --gap-tight: var(--space-2xs);   \/* a label and the thing it labels *\/\n  --gap-stack: var(--space-md);    \/* siblings inside one text block *\/\n  --gap-inline: var(--space-sm);   \/* items sitting in a row *\/\n  --gap-block: var(--space-lg);    \/* distinct blocks inside a component *\/\n  --gap-group: var(--space-2xl);   \/* major groups inside a section *\/\n\n  \/* Line length. Every max-width on running text derives from --layout-content,\n     so the whole family moves when that one token moves. There is no bare ch\n     value left on the site: the twelve that outlived the first pass now sit on\n     these six steps, each within a character or two of what it replaced.\n     --line-length-title caps a section h2; --line-length-title-page caps the h1\n     in a section head, which is set one size up and needs the wider cap.\n     Resolved values at the current 65ch content measure are in the comments. *\/\n  --line-length-title: calc(var(--layout-content) * 0.28);       \/* ~18ch \u2014 section titles *\/\n  --line-length-title-page: calc(var(--layout-content) * 0.37);  \/* ~24ch \u2014 page titles *\/\n  --line-length-xs: calc(var(--layout-content) * 0.5);           \/* ~33ch \u2014 cell captions *\/\n  --line-length-sm: calc(var(--layout-content) * 0.65);          \/* ~42ch \u2014 leads, cells *\/\n  --line-length-md: calc(var(--layout-content) * 0.71);          \/* ~46ch \u2014 body in a column *\/\n  --line-length-lg: calc(var(--layout-content) * 1.05);          \/* ~68ch \u2014 long-form *\/\n\n  \/* Breakpoints are literals by necessity: a custom property cannot be read in\n     a media query condition. Every query on this site is written against the\n     token values \u2014 40rem is --breakpoint-sm, 64rem is --breakpoint-md, and\n     63.99rem is the max-width side of md. Change a breakpoint token and these\n     literals must be changed with it. --breakpoint-lg (80rem) is unused: no\n     layout on the site changes at that width. *\/\n}\n\n\/* ---- Element defaults ------------------------------------------------ *\/\n\n\/* border-box for everything. The site was written without it, so every box was\n   content-box: .site-header and .site-footer both set inline-size:100% and then\n   add padding and a side rule on top, which put them 2x--pad wider than .shell\n   at every width and overflowed the viewport below ~1498px. .field__in did the\n   same inside its column. The templates already say they are \"contained to the\n   same measure as .shell\" \u2014 this is what makes that true. *\/\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  font-family: var(--font-text);\n  font-size: var(--text-md-size);\n  line-height: var(--text-md-leading);\n  letter-spacing: var(--text-md-tracking);\n  color: var(--color-ink);\n  background: var(--color-surface-body);\n  -webkit-font-smoothing: antialiased;\n}\n\na {\n  color: var(--color-action);\n}\n\n\/* :where() keeps this at 0,0,1. A bare a:hover is 0,1,1 and outranks a\n   component's own color (.btn--primary is 0,1,0) \u2014 which paints a button label\n   in the same value the hover state paints its background. *\/\na:where(:hover) {\n  color: var(--color-action-hover);\n}\n\n:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {\n  outline: var(--space-3xs) solid var(--color-focus);\n  outline-offset: var(--space-3xs);\n}\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n}\n\nhr {\n  border: 0;\n  border-top: var(--rule);\n  margin: var(--space-2xl) 0;\n}\n\nimg {\n  max-width: 100%;\n  height: auto;\n}\n\n\/* ---- Layout context -------------------------------------------------\n   Full-bleed section, constrained inner column. Every page inherits this\n   skeleton, so two pages built months apart still reconcile.\n\n   The page column is the theme's own main.delta-main, not a wrapper div in\n   each page. Every page and template used to open with <div class=\"shell\">,\n   which made the whole page one block: the Front panel lists the direct\n   children of the page as its Sections, so it showed one entry and could\n   reorder nothing. Pages and templates now start with their sections.\n   inline-size is needed because .delta-site is a flex column: with\n   margin-inline:auto and no width, the column shrinks to its content and the\n   widest child pushes it past the viewport. *\/\n.delta-main {\n  inline-size: 100%;\n  max-width: var(--layout-max);\n  margin-inline: auto;\n  background: var(--color-surface-body);\n  border-inline: var(--rule);\n}\n\n.delta-main > * {\n  min-width: 0;\n}\n\n.section {\n  border-bottom: var(--rule);\n}\n\n\/* The footer draws its own top rule, so the last block in the page column must not\n   draw a bottom one or the hairline doubles above the footer on every page.\n   This was written as `.shell > :has(+ .site-footer)`, which never matched: the\n   footer is a sibling of main.delta-main, not of .shell, so it is not the\n   shell's next element. Closing on :last-child needs no knowledge of what\n   follows the shell. *\/\n.delta-main > :last-child {\n  border-bottom: 0;\n}\n\n.section__inner {\n  padding: var(--layout-section-block) var(--pad);\n}\n\n.section__inner--measure {\n  max-width: var(--layout-content);\n}\n\n\/* Links inside body text only. Never a bare `.x a { color }` (0,1,1): it\n   outranks a component's own color (.btn is 0,1,0) and paints button labels\n   invisible. *\/\n.section__inner a:not([class]) {\n  color: var(--color-action);\n}\n\n\/* The one eyebrow. Every short label that sits above a heading and names what\n   follows uses this and nothing else \u2014 section heads, hero, service bands. It\n   carries its own colour and its own space below, so it works on its own; a\n   block that needs a different layout (an icon beside it, say) adds that and\n   changes nothing about the type. Do not write a second mono variant: the\n   role is the same, so the style is the same. *\/\n.eyebrow {\n  display: block;\n  margin: 0;\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n  line-height: var(--title-2xs-leading);\n  letter-spacing: var(--tracking-wide);\n  font-weight: var(--weight-regular);\n  text-transform: uppercase;\n  color: var(--color-action);\n}\n\n.cluster {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: var(--space-sm);\n}\n\n\/* A row of buttons stacks and goes full width on a narrow screen: side by side\n   they either wrap into a ragged pair or squeeze their labels. Scoped with\n   :has(> .btn) so a cluster of badges or meta keeps flowing as a row. *\/\n@media (max-width: 39.99rem) {\n  .cluster:has(> .btn) {\n    flex-direction: column;\n    align-items: stretch;\n  }\n}\n\n\/* ---- Terminal caption -----------------------------------------------\n   A command line used as a label. It began inside the intake form, then the\n   method grid needed the same idiom, so it moved here rather than being copied\n   \u2014 the same mistake .pgrid made. The host segment carries the accent; the\n   command after it takes the surrounding ink. *\/\n.prompt {\n  margin: 0 0 var(--space-xl);\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n  color: var(--color-ink-muted);\n}\n\n.prompt__host {\n  color: var(--color-action);\n}\n\n\/* The action colour is 3.4:1 on the contrast ground, under the floor. Lifted\n   towards the light ink rather than replaced, so the segment still reads as an\n   accent, and derived from the tokens so it follows a palette change. *\/\n.inverted .prompt__host {\n  color: color-mix(in srgb, var(--color-action), var(--color-ink-on-contrast) 45%);\n}\n\n\/* ---- Ruled cell grid -------------------------------------------------\n   A shared layout utility, not a component: the grid owns every hairline and\n   the cells inside it draw none. Modifier picks the column count at the md\n   breakpoint. The nth-child maths is tied to that count, so changing the\n   number of columns means revisiting the border rules. *\/\n.cells {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n  display: grid;\n  border-top: var(--rule);\n}\n\n.cells > * {\n  border-bottom: var(--rule);\n}\n\n.cells > :last-child {\n  border-bottom: 0;\n}\n\n.secfoot {\n  padding: var(--space-xl) var(--pad);\n  border-top: var(--rule);\n}\n\n.secfoot__link {\n  display: inline-flex;\n  align-items: center;\n  gap: var(--space-2xs);\n  padding-bottom: var(--space-3xs);\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n  color: var(--color-ink);\n  text-decoration: none;\n  border-bottom: var(--border-width) solid var(--color-action);\n}\n\n.secfoot__link:hover {\n  color: var(--color-action);\n}\n\n@media (min-width: 40rem) {\n  .cells--2,\n  .cells--3,\n  .cells--4 {\n    grid-template-columns: repeat(2, 1fr);\n  }\n\n  .cells--2 > * {\n    border-right: var(--rule);\n  }\n\n  .cells--2 > :nth-child(2n) {\n    border-right: 0;\n  }\n\n  .cells--2 > :nth-last-child(-n+2) {\n    border-bottom: 0;\n  }\n\n  .cells--3 > *,\n  .cells--4 > * {\n    border-right: var(--rule);\n  }\n\n  .cells--3 > :nth-child(2n),\n  .cells--4 > :nth-child(2n) {\n    border-right: 0;\n  }\n\n  .cells--3 > :last-child,\n  .cells--4 > :last-child {\n    border-bottom: var(--rule);\n  }\n}\n\n@media (min-width: 64rem) {\n  .cells--3 {\n    grid-template-columns: repeat(3, 1fr);\n  }\n\n  .cells--3 > :nth-child(2n) {\n    border-right: var(--rule);\n  }\n\n  .cells--3 > :nth-child(3n) {\n    border-right: 0;\n  }\n\n  .cells--3 > :nth-last-child(-n+3) {\n    border-bottom: 0;\n  }\n\n  .cells--4 {\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .cells--4 > :nth-child(2n) {\n    border-right: var(--rule);\n  }\n\n  .cells--4 > :nth-child(4n) {\n    border-right: 0;\n  }\n\n  \/* Matches the .cells--3 form above, and it has to: `.cells--4 > *` is 0,1,0\n     and loses to the `:last-child` rule at the sm breakpoint, which left the\n     fourth cell drawing a bottom rule against whatever followed the grid. *\/\n  .cells--4 > :nth-last-child(-n+4) {\n    border-bottom: 0;\n  }\n}\n\n\/* ---- Inverted context ------------------------------------------------\n   color must be declared here: it inherits from body as an already computed\n   value, so rebinding --color-ink alone leaves descendants on the light ink. *\/\n.inverted {\n  color: var(--color-ink);\n  background: var(--color-surface-contrast);\n  --color-ink: var(--color-ink-on-contrast);\n  --color-ink-muted: var(--color-ink-muted-on-contrast);\n  --color-border: var(--color-border-on-contrast);\n  --color-surface-subtle: color-mix(in srgb, var(--color-surface-contrast), white 7%);\n  \/* action, action-hover and on-action are deliberately NOT rebound: a filled\n     button carries its own ground, so it reads the same here as on a light\n     section. Only bare text links need help \u2014 the brand colour is 3.4:1 on this\n     ground, so they take the light ink instead (see the rule below). *\/\n  --color-focus: var(--color-ink-on-contrast);\n}\n\n\/* The eyebrow is action-coloured on a light ground, which is 3.4:1 on this one\n   \u2014 under the 4.5 floor. It takes the light ink here for the same reason bare\n   links below do. The icon inside it follows, because it inherits currentColor. *\/\n.inverted .eyebrow {\n  color: var(--color-ink-on-contrast);\n}\n\n\/* Unclassed links only. A classed element \u2014 a button \u2014 keeps its own colours,\n   which is what makes the filled button identical on light and inverted grounds. *\/\n.inverted a:not([class]) {\n  color: var(--color-ink-on-contrast);\n}\n\n.inverted a:not([class]):where(:hover) {\n  color: var(--color-ink-muted-on-contrast);\n}\n\n\/* ---- Ruled post grid -------------------------------------------------\n   Shared utility, not a component: used by the blog archive and by the related\n   block on a single post. It lived in the archive template CSS, which does not\n   load on a single, so the related grid rendered unstyled. The grid owns every\n   hairline and the cards inside draw none. *\/\n.pgrid {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n  display: grid;\n  border-top: var(--rule);\n}\n\n.pgrid > * {\n  border-bottom: var(--rule);\n}\n\n.pgrid > :last-child {\n  border-bottom: 0;\n}\n\n\/* The final row draws no bottom rule: the section around the grid closes it,\n   the same arrangement .cells uses. Re-adding a rule on the last cell alone\n   doubled the hairline against the section's own. The nth-last-child count is\n   tied to the column count, so changing one means changing the other. *\/\n@media (min-width: 40rem) {\n  .pgrid {\n    grid-template-columns: repeat(2, 1fr);\n  }\n\n  .pgrid > * {\n    border-right: var(--rule);\n  }\n\n  .pgrid > :nth-child(2n) {\n    border-right: 0;\n  }\n\n  .pgrid > :nth-last-child(-n+2) {\n    border-bottom: 0;\n  }\n}\n\n@media (min-width: 64rem) {\n  .pgrid {\n    grid-template-columns: repeat(3, 1fr);\n  }\n\n  .pgrid > :nth-child(2n) {\n    border-right: var(--rule);\n  }\n\n  .pgrid > :nth-child(3n) {\n    border-right: 0;\n  }\n\n  .pgrid > :nth-last-child(-n+3) {\n    border-bottom: 0;\n  }\n}\n\n\/* ---- Pager -----------------------------------------------------------\n   Shared utility, not a component. It was written three times \u2014 in the blog\n   archive, the term archive and the search results template \u2014 and the copies\n   had already drifted apart (two on --space-sm, one on --gap-inline) before\n   anyone noticed, which is the same way .pgrid went wrong. It sits here beside\n   .pgrid because every template that lists posts also pages them.\n   --gap-inline is the right name for it: these are items sitting in a row. *\/\n.pager {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: var(--gap-inline);\n  padding: var(--space-xl) var(--pad);\n  border-top: var(--rule);\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n}\n\n\/* :empty does not match here \u2014 the pagination loop leaves whitespace behind\n   even when it renders no links, which is enough to defeat it. Test for the\n   links themselves, or an empty band with a rule above it sits under the grid. *\/\n.pager:not(:has(a)) {\n  display: none;\n}\n\n.pager__n {\n  display: inline-grid;\n  place-items: center;\n  min-inline-size: var(--space-xl);\n  padding: var(--space-2xs) var(--space-xs);\n  border: var(--rule);\n  color: var(--color-ink-muted);\n  text-decoration: none;\n}\n\n.pager__n:hover {\n  color: var(--color-action);\n  border-color: var(--color-action);\n}\n\n.pager__n[aria-current] {\n  background: var(--color-action);\n  border-color: var(--color-action);\n  color: var(--color-on-action);\n}\n\n\/* ---- Form controls ---------------------------------------------------\n   The field primitives \u2014 .field, .field__lbl, .field__in and the rest \u2014 live\n   on the `field` component, not here. They were written in both files, and\n   this copy loaded last and won, so editing the component recipe changed\n   nothing on the page and only its custom select arrow ever reached the\n   screen. Component CSS applies by class across the whole site, with no\n   data-delta-component marker needed, so the search bar below takes the same\n   controls from the component. Only what is not the control stays here. *\/\n\n\/* A single control beside its submit. Stacks below sm, where a button sitting\n   next to a full-width input leaves neither enough room. *\/\n.searchbar {\n  display: grid;\n  gap: var(--space-sm);\n  max-width: var(--line-length-lg);\n}\n\n@media (min-width: 40rem) {\n  .searchbar {\n    grid-template-columns: 1fr auto;\n    align-items: end;\n  }\n\n  .searchbar .field {\n    grid-column: 1;\n  }\n}\n\n\/* ---- Page figure -----------------------------------------------------\n   A full-bleed band under a page title. Shared: the services page and the blog\n   archive both use it, so it lives here rather than in either one.\n\n   Full-bleed means the inner edge of the page column (.delta-main), not the\n   viewport \u2014 its side rules are the edge of the design. The figure takes\n   no --pad, so it runs rule to rule.\n\n   A fixed ratio with object-fit: cover, because the source images are 16:9 and\n   the band is wider than that; an auto ratio would let the band's height follow\n   whatever image is dropped in. Shorter ratio on narrow screens, where a 16:5\n   crop leaves nothing readable in the frame. *\/\n.pagefig {\n  margin: 0;\n  aspect-ratio: 16 \/ 9;\n  overflow: hidden;\n  background: var(--color-surface-subtle);\n  border-bottom: var(--rule);\n}\n\n.pagefig img {\n  display: block;\n  inline-size: 100%;\n  block-size: 100%;\n  object-fit: cover;\n  object-position: center;\n}\n\n\/* Below md the band leads the page: the image comes first, then the title and\n   lead below it. order:-1 needs a flex context, and the section is a plain\n   block, so :has() gives one only to the sections that carry a page figure.\n   The rule moves to the block end for the same reason \u2014 the figure is now the\n   first thing under the header, not the last thing under the copy. *\/\n@media (max-width: 39.99rem) {\n  .section:has(> .pagefig) {\n    display: flex;\n    flex-direction: column;\n  }\n\n  .pagefig {\n    order: -1;\n    border-bottom: 0;\n    border-top: var(--rule);\n  }\n}\n\n@media (min-width: 40rem) {\n  .pagefig {\n    aspect-ratio: 16 \/ 5;\n  }\n}\n\n\/* ---- Closing call to action -----------------------------------------\n   Shared utility. It began in the Services page CSS; the Case study page\n   needed the same block, so it moved here rather than being copied \u2014 the\n   same mistake .pgrid and .pager made. The title cap moved from a bare 20ch\n   to --line-length-title, the lead cap from 46ch to --line-length-md. *\/\n.cta {\n  display: grid;\n  gap: var(--space-lg);\n  padding: var(--space-3xl) var(--pad);\n  align-items: center;\n}\n\n.cta__title {\n  margin: 0;\n  font-family: var(--font-title);\n  font-size: var(--title-lg-size);\n  line-height: var(--title-lg-leading);\n  letter-spacing: var(--title-lg-tracking);\n  font-weight: var(--weight-bold);\n  max-width: var(--line-length-title);\n  text-wrap: balance;\n}\n\n.cta__lead {\n  margin: var(--space-md) 0 0;\n  max-width: var(--line-length-md);\n  color: var(--color-ink-muted);\n}\n\n\/* Stacked, and both buttons the same width: min-inline-size sets the floor\n   and the wider label sets the rest, so the pair reads as one block. *\/\n.cta__actions {\n  display: flex;\n  flex-direction: column;\n  align-items: stretch;\n  gap: var(--space-sm);\n  min-inline-size: 16rem;\n}\n\n@media (min-width: 64rem) {\n  .cta {\n    grid-template-columns: 1fr auto;\n    gap: var(--space-2xl);\n  }\n}\n\n\/* Dot grid behind the call to action, on a pseudo-element so the mask fades\n   only the grid and not the section ground or its text. isolation keeps the\n   negative z-index inside this section. Dot colour is mixed from the section's\n   own ink, so a token change moves it. *\/\n.section:has(> .cta) {\n  position: relative;\n  isolation: isolate;\n}\n\n.section:has(> .cta)::before {\n  content: \"\";\n  position: absolute;\n  inset: 0;\n  z-index: -1;\n  pointer-events: none;\n  background-image: radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--color-ink-on-contrast) 16%, transparent) 1px, transparent 0);\n  background-size: var(--space-xl) var(--space-xl);\n  -webkit-mask-image: radial-gradient(120% 120% at 100% 0%, black 20%, transparent 72%);\n  mask-image: radial-gradient(120% 120% at 100% 0%, black 20%, transparent 72%);\n}\n\n\/* Contained to the same measure as the page column (.delta-main), with the same side rules, so the\n   bar reads as the top of the page column rather than a band behind it. The\n   footer does the same at the other end. *\/\n.site-header {\n  position: sticky;\n  top: 0;\n  z-index: 20;\n  display: flex;\n  align-items: center;\n  gap: var(--space-md);\n  inline-size: 100%;\n  max-width: var(--layout-max);\n  margin-inline: auto;\n  padding: var(--space-sm) var(--pad);\n  border-inline: var(--rule);\n  border-bottom: var(--rule);\n  background: var(--color-surface-body);\n}\n\n\/* Mixed in srgb, not oklch. Mixing a warm near-white with transparent in oklch\n   leaves the hue channel powerless \u2014 the computed value came out as\n   `oklch(0.9855 0.0057 none \/ 0.92)`, and a residual chroma on an undefined hue\n   renders pink, so the bar read visibly cooler and pinker than the page it sits\n   on. srgb has no hue channel to lose and holds the cream. *\/\n@supports (backdrop-filter: blur(2px)) {\n  .site-header {\n    background: color-mix(in srgb, var(--color-surface-body), transparent 8%);\n    backdrop-filter: blur(8px);\n  }\n}\n\n\/* The bar keeps the tighter button. The component's block padding is sized for\n   a button sitting in a page, which would make the header noticeably taller. *\/\n.site-header .btn {\n  padding-block: var(--space-sm);\n}\n\n.site-header__brand {\n  display: flex;\n  align-items: center;\n  gap: var(--space-xs);\n  margin-right: auto;\n  text-decoration: none;\n  color: var(--color-ink);\n}\n\n.site-header__mark {\n  display: grid;\n  place-items: center;\n  inline-size: var(--space-xl);\n  block-size: var(--space-xl);\n  background: var(--color-action);\n  color: var(--color-on-action);\n  font-family: var(--font-title);\n  font-size: var(--text-sm-size);\n  font-weight: var(--weight-bold);\n}\n\n.site-header__word {\n  font-family: var(--font-title);\n  font-size: var(--title-xs-size);\n  font-weight: var(--weight-bold);\n  letter-spacing: var(--tracking-tight);\n}\n\n\/* Below the md breakpoint the links become a disclosure panel dropped from the\n   bar. The panel is absolute against the sticky bar, which already establishes\n   the containing block \u2014 making the bar static drops it to the top of the page. *\/\n.site-header__nav {\n  display: none;\n  position: absolute;\n  inset-inline: 0;\n  top: 100%;\n  background: var(--color-surface-body);\n  border-bottom: var(--rule);\n}\n\n\/* The panel can outrun a short viewport once the links are set this large, so\n   it caps at the space under the bar and scrolls inside itself. *\/\n.site-header__nav.is-open {\n  display: block;\n  max-block-size: calc(100dvh - var(--space-4xl));\n  overflow-y: auto;\n}\n\n\/* primary_nav emits its own ul\/li\/a, so style by descent, never by adding\n   classes inside the placeholder. The :not([class]) guard keeps this off any\n   classed link \u2014 a bare `.x a { color }` is 0,1,1 and outranks .btn at 0,1,0. *\/\n.site-header__nav ul {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n  display: flex;\n  flex-direction: column;\n}\n\n\/* On the panel the links are the page, not a strip of labels, so they take the\n   heading face at the h3 step. Above md they drop back to reading size in the\n   bar. Navigation is reading text either way \u2014 the mono face is reserved for\n   metadata: dates, counts, field labels, the terminal caption. *\/\n.site-header__nav li a:not([class]) {\n  display: block;\n  padding: var(--space-md) var(--pad);\n  border-top: var(--rule);\n  font-family: var(--font-title);\n  font-size: var(--title-md-size);\n  line-height: var(--title-md-leading);\n  letter-spacing: var(--title-md-tracking);\n  font-weight: var(--weight-semibold);\n  color: var(--color-ink);\n  text-decoration: none;\n}\n\n\/* The call to action lives at the foot of the panel on a small screen, where\n   the bar has no room for it, and full width so it reads as the end of the\n   list rather than a stray control. *\/\n.site-header__navcta {\n  padding: var(--space-lg) var(--pad) var(--space-xl);\n  border-top: var(--rule);\n}\n\n.site-header__navcta .btn {\n  inline-size: 100%;\n}\n\n\/* The bar's own copy of the button is for md and up; below that the panel\n   carries it and two would be one too many. *\/\n.site-header__cta {\n  display: none;\n}\n\n.site-header__nav li:first-child a:not([class]) {\n  border-top: 0;\n}\n\n.site-header__nav li a:not([class]):hover,\n.site-header__nav li a:not([class])[aria-current] {\n  color: var(--color-action);\n}\n\n.site-header__toggle {\n  appearance: none;\n  background: none;\n  border: 0;\n  padding: var(--space-2xs);\n  display: grid;\n  place-items: center;\n  cursor: pointer;\n  color: var(--color-ink);\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n}\n\n.site-header__toggle:hover {\n  color: var(--color-action);\n}\n\n.site-header__toggle .is-close { display: none; }\n.site-header__toggle[aria-expanded=\"true\"] .is-open { display: none; }\n.site-header__toggle[aria-expanded=\"true\"] .is-close { display: inline; }\n\n@media (min-width: 64rem) {\n  .site-header__toggle {\n    display: none;\n  }\n\n  .site-header__cta {\n    display: inline-flex;\n  }\n\n  .site-header__navcta {\n    display: none;\n  }\n\n  .site-header__nav {\n    display: block;\n    position: static;\n    border-bottom: 0;\n    background: none;\n  }\n\n  .site-header__nav ul {\n    flex-direction: row;\n    gap: var(--space-lg);\n  }\n\n  .site-header__nav li a:not([class]) {\n    padding: 0;\n    border-top: 0;\n    font-family: var(--font-text);\n    font-size: var(--text-sm-size);\n    line-height: var(--text-md-leading);\n    letter-spacing: var(--text-sm-tracking);\n    font-weight: var(--weight-regular);\n  }\n}\n\n\/* Contained to the same measure as the page column (.delta-main), with the same side rules, so the\n   page column runs unbroken from the header to the bottom of the footer. *\/\n.site-footer {\n  display: grid;\n  gap: var(--space-xl);\n  inline-size: 100%;\n  max-width: var(--layout-max);\n  margin-inline: auto;\n  padding: var(--space-2xl) var(--pad);\n  border-inline: var(--rule);\n  border-top: var(--rule);\n}\n\n.site-footer__brand {\n  display: grid;\n  gap: var(--space-xs);\n  align-content: start;\n}\n\n.site-footer__word {\n  font-family: var(--font-title);\n  font-size: var(--title-xs-size);\n  font-weight: var(--weight-bold);\n  letter-spacing: var(--tracking-tight);\n  color: var(--color-ink);\n}\n\n.site-footer__line {\n  margin: 0;\n  max-width: var(--line-length-xs);\n  font-size: var(--text-sm-size);\n  line-height: var(--text-sm-leading);\n  color: var(--color-ink-muted);\n}\n\n.site-footer__col {\n  display: grid;\n  gap: var(--space-2xs);\n  align-content: start;\n}\n\n.site-footer__h {\n  margin: 0 0 var(--space-2xs);\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n  text-transform: uppercase;\n  letter-spacing: var(--tracking-wide);\n  color: var(--color-ink);\n}\n\n\/* footer_nav emits its own list markup, so the column styles by descent. The\n   :not([class]) guard keeps this rule off any classed link. *\/\n.site-footer__col ul {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n  display: grid;\n  gap: var(--space-2xs);\n}\n\n\/* Matches the header: navigation is reading text and takes the text face. The\n   mono face stays on the column headings and the fine print, which are labels. *\/\n.site-footer__col li a:not([class]) {\n  font-family: var(--font-text);\n  font-size: var(--text-sm-size);\n  color: var(--color-ink-muted);\n  text-decoration: none;\n}\n\n.site-footer__col li a:not([class]):hover {\n  color: var(--color-action);\n}\n\n.site-footer__fine {\n  margin: 0;\n  padding-top: var(--space-lg);\n  border-top: var(--rule);\n  font-family: var(--font-mono);\n  font-size: var(--mono-sm);\n  color: var(--color-ink-muted);\n}\n\n@media (min-width: 40rem) {\n  .site-footer {\n    grid-template-columns: 2fr 1fr 1fr;\n  }\n\n  .site-footer__fine {\n    grid-column: 1 \/ -1;\n  }\n}"}],"mode":"seed"},"_links":{"self":[{"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/pages\/25","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/comments?post=25"}],"version-history":[{"count":8,"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/pages\/25\/revisions"}],"predecessor-version":[{"id":145,"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/pages\/25\/revisions\/145"}],"wp:attachment":[{"href":"https:\/\/preview.deltatheme.com\/kiln\/wp-json\/wp\/v2\/media?parent=25"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}