/* ===================================================================
   KaoTech — standalone site styles
   Brand: black base, blue #3a50c0, orange #e8891d (from the logo).
   Dark by default, light theme via toggle.
   =================================================================== */

:root {
    --kao-blue: #3a50c0;
    --kao-blue-bright: #8fa1f5;
    --kao-orange: #e8891d;

    --bg: #0a0a0d;
    --bg-elevated: #101017;
    --bg-card: #14141d;
    --text: #f2f2f6;
    --text-muted: #a2a7bd;
    --border: #262633;
    --accent: var(--kao-orange);
    --heading-accent: var(--kao-blue-bright);
    --nav-bg: rgba(10, 10, 13, 0.88);
    --shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
}

body.light-mode {
    --bg: #f4f4f6;
    --bg-elevated: #ffffff;
    --bg-card: #ffffff;
    --text: #17181f;
    --text-muted: #575d75;
    --border: #dcdde6;
    --accent: #c86e0a;
    --heading-accent: var(--kao-blue);
    --nav-bg: rgba(255, 255, 255, 0.88);
    --shadow: 0 8px 24px rgba(23, 24, 31, 0.12);
}

* { box-sizing: border-box; }

/* The hidden attribute must win over component display rules like
   .btn { display: inline-block } (author CSS otherwise beats the UA
   [hidden] rule, leaving "hidden" buttons visible). */
[hidden] { display: none !important; }

html {
    scroll-behavior: smooth;
    /* Keep #anchors clear of the sticky header. Without this a nav click puts
       the section heading UNDER the bar -- survivable at the old height because
       .container's 3rem top padding covered it, not at the new one. */
    scroll-padding-top: 5.5rem;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    /* .anim is not set under reduced motion -- but it IS already on <html> if
       the visitor flips the setting with the page open, so undo it here too. */
    .anim .reveal,
    .anim .reveal .card,
    .anim .reveal .work-item,
    .anim .reveal .care-tier,
    .anim .reveal .steps > li,
    .anim .reveal .web-steps > li {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
    /* The landing ring is deliberately NOT silenced here: it is a shadow
       fading in and out, with nothing moving, scaling or spinning. */
}

body {
    margin: 0;
    font-family: "Fredoka", "Segoe UI", system-ui, sans-serif;
    background-color: var(--bg);
    /* Honeycomb tile across the whole page — a nod to the logo's infill */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z' fill='%23e8891d' fill-opacity='0.045'/%3E%3C/svg%3E");
    color: var(--text);
    line-height: 1.6;
    transition: background-color 0.3s ease, color 0.3s ease;
}

body.light-mode {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z' fill='%23c86e0a' fill-opacity='0.10'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------------
   Navigation
   ------------------------------------------------------------------ */
/* Header sized up 25% on 2026-09-24 (Nathan). Everything that sets the bar's
   HEIGHT is scaled together -- vertical padding, the badge, the wordmark, the
   nav pills and the theme toggle -- so it reads as the same design at 125%
   rather than a taller bar with small type in it. The 1.2rem side padding is
   the page gutter, not header size, so it stays put and the brand keeps its
   alignment with the content below. The badge's width/height attributes in
   index.html were bumped to match (32 -> 40): they exist to reserve the space
   before the image loads, so a CSS-only change would reintroduce layout shift. */
.site-nav {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 0.95rem 1.2rem;
    background: var(--nav-bg);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.69rem;
    font-weight: 700;
    font-size: 1.44rem;
    letter-spacing: 0.5px;
    color: var(--text);
    text-decoration: none;
    white-space: nowrap;
}

.brand-kao { color: var(--heading-accent); }
.brand-tech { color: var(--kao-orange); }

.site-nav nav {
    margin-left: auto;
    display: flex;
    gap: 0.3rem;
    flex-wrap: wrap;
}

.site-nav nav a {
    color: var(--text-muted);
    text-decoration: none;
    /* Deliberately NOT scaled. The pills are the tallest thing in the bar after
       the badge. MEASURED, not assumed: the pills -- not the badge -- were
       already the tallest thing in the old bar (58.6px total, not the 51.2 the
       padding-plus-badge arithmetic suggests). Scaling them to 1.25rem took the
       bar to 73px BUT wrapped the nav to two rows under 1230px; leaving them at
       1rem and putting the growth into the bar's own padding reaches the same
       73px (58.6 -> 73 = +25%) at every width, with no wrapping. */
    padding: 0.5rem 1rem;
    border-radius: 999px;
    font-weight: 500;
    transition: color 0.2s, background 0.2s;
}

.site-nav nav a:hover {
    color: var(--text);
    background: var(--bg-card);
}

#theme-toggle {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 1.31rem;
    padding: 0.44rem 0.75rem;
    cursor: pointer;
    line-height: 1;
    transition: transform 0.2s;
}

#theme-toggle:hover { transform: scale(1.12); }

/* The phone menu button. Hidden above 640px, where the links fit on the bar.
   The glyph lives in ::before so opening and closing is pure CSS off one
   class -- nothing has to rewrite the button's text, which would fight the
   aria-label a screen reader is already using to announce it. */
.nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    font-family: inherit;
    font-size: 1.31rem;
    line-height: 1;
    padding: 0.44rem 0.75rem;
    color: var(--text);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
}

.nav-toggle::before { content: "\2630"; }                 /* hamburger */
.site-nav.menu-open .nav-toggle::before { content: "\2715"; }  /* close */

/* ------------------------------------------------------------------
   Hero — honeycomb over black, blue + orange glows
   ------------------------------------------------------------------ */
.hero {
    text-align: center;
    padding: 4.5rem 1.5rem;
    background-image:
        radial-gradient(ellipse 70% 60% at 50% 0%, rgba(58, 80, 192, 0.30), transparent),
        radial-gradient(ellipse 50% 45% at 85% 35%, rgba(232, 137, 29, 0.14), transparent);
}

body.light-mode .hero {
    background-image:
        radial-gradient(ellipse 70% 60% at 50% 0%, rgba(58, 80, 192, 0.12), transparent),
        radial-gradient(ellipse 50% 45% at 85% 35%, rgba(232, 137, 29, 0.08), transparent);
}

/* The frame carries the padding, border and glow. Its background is #0f0f0f
   because that is exactly the banner PNG's own baked-in background — matching
   them removes the visible seam between the artwork and its surround. */
.banner-frame {
    display: inline-block;
    width: min(620px, 90vw);
    background: #0f0f0f;
    border: 1px solid rgba(232, 137, 29, 0.35);
    border-radius: 16px;
    padding: 1rem 1.5rem;
    box-shadow: 0 0 35px rgba(232, 137, 29, 0.25);
    margin-bottom: 1.5rem;
}

/* Tight, padding-free box so the hotspot's percentages map to the artwork
   itself rather than to the padded frame around it. */
.banner-wrap {
    position: relative;
    display: block;
    line-height: 0;
}

.hero-banner {
    display: block;
    width: 100%;
    height: auto;
}

/* Staff shortcut to /admin/, sitting over the arrowhead in the artwork's
   top-right corner. This is convenience, NOT security: /admin/ is a public
   URL protected by the login gate either way — this just keeps a visible
   "Admin" link off the storefront. */
.banner-hotspot {
    position: absolute;
    top: 7%;
    right: 1.5%;
    width: 9%;
    height: 19%;
    cursor: pointer;
}

/* At full width the target is ~109x57px; on a phone the same percentages
   shrink it to ~30x16px, so give it more room to be tappable. */
@media (max-width: 700px) {
    .banner-hotspot {
        top: 4%;
        right: 1%;
        width: 16%;
        height: 30%;
    }
}

.tagline {
    font-size: clamp(1.05rem, 2.5vw, 1.3rem);
    color: var(--text-muted);
    max-width: 36em;
    margin: 0 auto 2rem;
}

.hero-actions {
    display: flex;
    gap: 0.8rem;
    justify-content: center;
    flex-wrap: wrap;
}

/* ------------------------------------------------------------------
   Buttons
   ------------------------------------------------------------------ */
.btn {
    display: inline-block;
    padding: 0.65rem 1.5rem;
    border-radius: 999px;
    font-weight: 600;
    font-family: inherit;
    font-size: 1rem;
    text-decoration: none;
    transition: transform 0.15s, box-shadow 0.15s, background 0.2s;
    cursor: pointer;
}

.btn-primary {
    background: var(--kao-orange);
    color: #2b1600;
    box-shadow: 0 4px 16px rgba(232, 137, 29, 0.4);
}

.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(232, 137, 29, 0.55);
}

.btn-ghost {
    background: transparent;
    color: var(--text);
    border: 1.5px solid var(--kao-blue);
}

.btn-ghost:hover {
    border-color: var(--kao-orange);
    transform: translateY(-2px);
}

/* ------------------------------------------------------------------
   Sections
   ------------------------------------------------------------------ */
.container {
    max-width: 1000px;
    margin: 0 auto;
    padding: 3rem 1.5rem;
}

h2 {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: clamp(1.5rem, 3.5vw, 2rem);
    font-weight: 600;
    margin: 0 0 0.5rem;
}

/* Hexagon section markers — a nod to the logo's infill */
.hex {
    display: inline-block;
    width: 16px;
    height: 14px;
    clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
    flex-shrink: 0;
}

.hex-orange { background: var(--kao-orange); filter: drop-shadow(0 0 6px var(--kao-orange)); }
.hex-blue   { background: var(--kao-blue-bright); filter: drop-shadow(0 0 6px var(--kao-blue)); }

/* ------------------------------------------------------------------
   Cards
   ------------------------------------------------------------------ */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1.2rem;
    margin-top: 1.5rem;
}

.card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 1.5rem;
    box-shadow: var(--shadow);
    transition: transform 0.2s, border-color 0.2s;
}

.card:hover {
    transform: translateY(-4px);
    border-color: var(--kao-orange);
}

.card-icon { font-size: 2rem; margin-bottom: 0.4rem; }

.card h3 {
    margin: 0 0 0.4rem;
    font-weight: 600;
    color: var(--heading-accent);
}

.card p { margin: 0; color: var(--text-muted); }

/* ------------------------------------------------------------------
   Steps
   ------------------------------------------------------------------ */
.steps {
    list-style: none;
    margin: 1.5rem 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1.2rem;
}

.steps li {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 1.4rem;
    box-shadow: var(--shadow);
    transition: transform 0.2s, border-color 0.2s;
}

.steps li:hover {
    transform: translateY(-4px);
    border-color: var(--kao-blue);
}

.steps h3 {
    margin: 0 0 0.4rem;
    font-weight: 600;
    color: var(--heading-accent);
}

.steps p { margin: 0; color: var(--text-muted); }

/* ------------------------------------------------------------------
   Shop — product cards
   ------------------------------------------------------------------ */
.product-card {
    display: flex;
    flex-direction: column;
}

.product-card p {
    /* Teaser only — clamp to 4 lines on the card; full text shows in the modal. */
    margin: 0 0 1rem;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
}

.product-img {
    width: 100%;
    height: 150px;
    object-fit: cover;
    border-radius: 10px;
    margin-bottom: 0.6rem;
    background: #0d0d0d;
}

/* Clickable thumbnail strip under the primary photo — signals "more angles". */
.card-thumbs {
    display: flex;
    gap: 0.4rem;
    margin: 0 0 0.7rem;
    flex-wrap: wrap;
}

.card-thumb {
    width: 44px;
    height: 44px;
    border-radius: 8px;
    border: 1.5px solid var(--border);
    background-size: cover;
    background-position: center;
    background-color: #0d0d0d;
    cursor: pointer;
    padding: 0;
    flex: 0 0 auto;
    transition: border-color 0.15s, transform 0.1s;
}

.card-thumb:hover { border-color: var(--kao-orange); transform: translateY(-1px); }

.card-thumb-more {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--kao-orange);
    background: var(--bg-elevated);
}

.product-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: auto;   /* pin to the bottom so footers align even with a clamped description */
}

/* Keeps the price pill and its "+ tax" note together as ONE flex item, so the
   product footer stays a two-child row and nothing reflows. */
.price-wrap {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
}

.price-tax {
    font-size: 0.78rem;
    color: var(--text-muted);
    white-space: nowrap;
}

.price {
    font-weight: 600;
    color: var(--kao-orange);
    border: 1.5px solid var(--kao-orange);
    border-radius: 999px;
    padding: 0.2rem 0.8rem;
    font-size: 0.9rem;
    white-space: nowrap;
}

.product-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.btn-sm {
    padding: 0.4rem 1rem;
    font-size: 0.9rem;
}

/* ------------------------------------------------------------------
   Order form
   ------------------------------------------------------------------ */
.order-form {
    max-width: 720px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 1.8rem;
    box-shadow: var(--shadow);
}

.order-form label {
    display: block;
    font-weight: 500;
    margin-bottom: 1.1rem;
}

.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

@media (max-width: 560px) {
    .form-row { grid-template-columns: 1fr; }
}

.order-form input,
.order-form textarea,
.order-form select {
    display: block;
    width: 100%;
    margin-top: 0.35rem;
    padding: 0.65rem 0.8rem;
    font: inherit;
    color: var(--text);
    background: var(--bg);
    border: 1.5px solid var(--border);
    border-radius: 10px;
    transition: border-color 0.2s;
}

.order-form input:focus,
.order-form textarea:focus,
.order-form select:focus {
    outline: none;
    border-color: var(--kao-orange);
}

.order-form textarea { resize: vertical; }

/* Short "why choose this" blurb under the Material dropdown. */
.material-hint {
    display: block;
    margin-top: 0.4rem;
    font-size: 0.82rem;
    line-height: 1.4;
    color: var(--text-muted);
}
.material-hint:empty { display: none; }

/* Colour-variation note under a Color dropdown in the product modal. */
.opt-note {
    display: block;
    margin-top: 0.3rem;
    font-size: 0.78rem;
    line-height: 1.4;
    font-weight: 400;
    color: var(--text-muted);
}

/* Cloudflare Turnstile bot-check widget (renders into the order form when configured) */
.cf-turnstile-mount { margin: 0.75rem 0 0.25rem; }
.cf-turnstile-mount:empty { margin: 0; }

.req { color: var(--kao-orange); }

.opt {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.85em;
}

/* fulfillment + address */
.fulfillment {
    border: 1.5px solid var(--border);
    border-radius: 10px;
    padding: 0.8rem 1rem 0.9rem;
    margin: 0 0 1.1rem;
}

.fulfillment legend {
    font-weight: 500;
    padding: 0 0.4rem;
}

.fulfillment .radio {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 400;
    margin: 0.35rem 0 0;
    cursor: pointer;
}

.fulfillment .radio input {
    width: auto;
    margin: 0;
    accent-color: var(--kao-orange);
}

.ship-note {
    margin: 0.6rem 0 0;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.form-row-3 { grid-template-columns: 2fr 1fr 1fr; }

@media (max-width: 560px) {
    .form-row-3 { grid-template-columns: 1fr; }
}

.order-form input[type="file"] {
    padding: 0.45rem 0.6rem;
    cursor: pointer;
}

.order-form input[type="file"]::file-selector-button {
    font: inherit;
    background: var(--kao-blue);
    color: #fff;
    border: none;
    border-radius: 999px;
    padding: 0.35rem 1rem;
    margin-right: 0.8rem;
    cursor: pointer;
}

.shop-empty { color: var(--text-muted); }

.shop-divider {
    grid-column: 1 / -1;
    margin: 1.2rem 0 0;
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--text);
    border-top: 1px solid var(--border);
    padding-top: 1.4rem;
}

.shop-divider span {
    font-size: 0.85rem;
    font-weight: 400;
    color: var(--text-muted);
}

.dig-badge {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    background: #1c3a52;
    color: #8fc6f5;
    padding: 0.14rem 0.55rem;
    border-radius: 999px;
    vertical-align: middle;
}

.closed-note {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
    background: var(--bg-card);
    border: 1.5px dashed var(--kao-orange);
    border-radius: 16px;
    padding: 1.4rem 1.6rem;
    grid-column: 1 / -1;
}

.closed-note span { font-size: 2rem; line-height: 1; }

.closed-note strong { color: var(--heading-accent); }

.closed-note p { margin: 0.2rem 0 0; color: var(--text-muted); }

/* ------------------------------------------------------------------
   Product modal
   ------------------------------------------------------------------ */
.modal { position: fixed; inset: 0; z-index: 200; }

.modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(3px);
}

.modal-card {
    position: relative;
    max-width: 460px;
    margin: 8vh auto 0;
    max-height: 84vh;
    overflow-y: auto;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 18px;
    padding: 1.6rem;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7);
}

.modal-close {
    position: absolute;
    top: 0.7rem;
    right: 0.9rem;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
}

.modal-close:hover { color: var(--kao-orange); }

.modal-media { text-align: center; }

.modal-icon { font-size: 4.5rem; }

.modal-img {
    width: 100%;
    max-height: 300px;
    object-fit: cover;
    border-radius: 12px;
    background: #0d0d0d;
}

.modal-thumbs {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.6rem;
    flex-wrap: wrap;
    justify-content: center;
}

.modal-thumb {
    width: 56px;
    height: 56px;
    object-fit: cover;
    border-radius: 8px;
    border: 2px solid transparent;
    cursor: pointer;
    background: #0d0d0d;
    transition: border-color 0.15s;
}

.modal-thumb:hover { border-color: var(--kao-blue-bright); }
.modal-thumb.active { border-color: var(--kao-orange); }

.modal-options {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin: 0 0 1rem;
}

.modal-opt {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.9rem;
    color: var(--text-muted);
    text-align: left;
}

.modal-opt select {
    font: inherit;
    color: var(--text);
    background: var(--bg);
    border: 1.5px solid var(--border);
    border-radius: 8px;
    padding: 0.45rem 0.6rem;
}

.modal-opt select:focus { outline: none; border-color: var(--kao-orange); }

.modal-card h3 {
    margin: 0.8rem 0 0.4rem;
    color: var(--heading-accent);
    font-size: 1.3rem;
}

.modal-card p {
    color: var(--text-muted);
    margin: 0 0 1rem;
    /* Full description — keep the author's line breaks, scroll if it's very long. */
    white-space: pre-wrap;
    overflow-wrap: break-word;
    max-height: 45vh;
    overflow-y: auto;
}

.modal-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    flex-wrap: wrap;
}

/* honeypot — hidden from humans, visible to naive bots */
.hp-field {
    position: absolute !important;
    left: -9999px !important;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.form-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

#form-status { margin: 0; font-weight: 500; }

.status-ok { color: #4caf70; }

.status-err { color: #e05a4e; }

/* ------------------------------------------------------------------
   Footer
   ------------------------------------------------------------------ */
footer {
    text-align: center;
    padding: 2.5rem 1.5rem;
    border-top: 1px solid var(--border);
    background: var(--bg-elevated);
    margin-top: 2rem;
}

footer p { margin: 0.3rem 0; }

.footer-note { color: var(--text-muted); font-size: 0.92rem; }

.footer-note a {
    color: var(--accent);
    text-decoration: none;
}

.footer-note a:hover { text-decoration: underline; }

/* ------------------------------------------------------------------
   Small screens
   ------------------------------------------------------------------ */
/* Eight links show once every section has content (Gallery hides itself while
   it has no images), and the bigger brand and badge eat ~25px of the row. Below
   1230px the pills tighten to 0.7rem side padding to buy that back, so a laptop
   keeps the single row it had before instead of wrapping to two. Height is
   unaffected either way -- the badge governs it at both sizes. */
@media (max-width: 1230px) {
    .site-nav { gap: 1rem; }
    .site-nav nav { gap: 0.25rem; }
    .site-nav nav a { padding: 0.4rem 0.7rem; }
}

@media (max-width: 1100px) {
    /* The phone header's whole history in one place. Five links beside the
       brand stacked one per line: a 210px sticky bar. Letting the nav take its
       own full-width row fixed that at 129px -- until the extra sections
       appeared and eight links wrapped to three rows, 166px again, a fifth of
       the screen before a word is read.
       The links now live behind a menu button, so the bar is a single row and
       can carry the same 25% the desktop got: ~65px, closed. MEASURED: the nav
       needs ~1002px to hold its eight links on one row, so the button appears
       below 1100px, not below 640 -- at 641px it was still wrapping to three
       rows and a 154px bar, which is the very thing it exists to prevent. Opened, the menu
       is a COLUMN -- full-width rows are easier to hit with a thumb than a
       cloud of wrapped pills, and they read as a menu rather than as a header
       that grew. Nothing here overrides the [hidden] links, so a section with
       no content still keeps itself out of the menu. */
    .site-nav { padding: 0.75rem 1.2rem; gap: 0.6rem; flex-wrap: wrap; row-gap: 0.3rem; }
    .nav-toggle { display: inline-flex; order: 3; }
    #theme-toggle { order: 2; margin-left: auto; }
    .site-nav nav {
        display: none;
        order: 4;
        flex-basis: 100%;
        margin-left: 0;
        flex-direction: column;
        gap: 0.15rem;
        /* A tall menu on a short phone must scroll itself rather than push the
           page out of reach -- the bar is sticky, so it would take the viewport
           with it. */
        max-height: calc(100vh - 8rem);
        overflow-y: auto;
    }
    .site-nav.menu-open nav { display: flex; }
    .site-nav nav a { padding: 0.65rem 0.8rem; font-size: 1rem; text-align: center; }
}

@media (max-width: 640px) {
    .hero { padding: 3rem 1rem; }
}

/* ------------------------------------------------------------------
   Section sub-heading
   ------------------------------------------------------------------ */
.section-sub { color: var(--text-muted); max-width: 46em; margin: 0.2rem 0 0; }

/* ------------------------------------------------------------------
   Motion. Everything here is gated on .anim, which only exists when JS
   set it in <head> AND the visitor has not asked for reduced motion.
   ------------------------------------------------------------------ */

/* Sections FADE, they do not move. An anchor scrolls you to a section's
   box; sliding that same box while you arrive undoes the landing offset
   the sticky header needs. The movement lives on the cards inside. */
.anim .reveal { opacity: 0; }

.anim .reveal.in-view {
    opacity: 1;
    transition: opacity 0.55s ease-out;
}

/* Set for a few frames while an anchor jump reveals everything at once. The
   sections still become visible -- they just do it instantly instead of each
   fading in as the scroll flies past, which is what made a jump flicker. */
.anim.kao-no-fade .reveal,
.anim.kao-no-fade .reveal .card,
.anim.kao-no-fade .reveal .work-item,
.anim.kao-no-fade .reveal .care-tier,
.anim.kao-no-fade .reveal .steps > li,
.anim.kao-no-fade .reveal .web-steps > li {
    transition: none !important;
}

/* Cards, tiles and tiers lift as their section arrives, one after another. */
.anim .reveal .card,
.anim .reveal .work-item,
.anim .reveal .care-tier,
.anim .reveal .steps > li,
.anim .reveal .web-steps > li {
    opacity: 0;
    transform: translateY(14px);
}

.anim .reveal.in-view .card,
.anim .reveal.in-view .work-item,
.anim .reveal.in-view .care-tier,
.anim .reveal.in-view .steps > li,
.anim .reveal.in-view .web-steps > li {
    opacity: 1;
    transform: none;
    transition: opacity 0.5s ease-out var(--kao-d, 0s),
                transform 0.5s cubic-bezier(0.2, 0.75, 0.3, 1) var(--kao-d, 0s);
}

.anim .reveal.in-view :is(.card, .work-item, .care-tier, li):nth-child(2) { --kao-d: 0.08s; }
.anim .reveal.in-view :is(.card, .work-item, .care-tier, li):nth-child(3) { --kao-d: 0.16s; }
.anim .reveal.in-view :is(.card, .work-item, .care-tier, li):nth-child(4) { --kao-d: 0.24s; }
.anim .reveal.in-view :is(.card, .work-item, .care-tier, li):nth-child(5) { --kao-d: 0.32s; }

/* Landing. Click a link and the section you arrive at says so: an accent
   outline draws itself inside the section, holds, then clears. Nathan tried
   seven treatments on 24 Sept and chose this one; the other six are gone.

   ⭐ It moves NOTHING, and that is why it survived where the rest did not.
   Every earlier attempt animated position or opacity on something already on
   screen -- a heading glow, a sweeping bar, a card ripple -- and each one read
   as a blip, a flicker, or a dip before the effect proper. A shadow fading in
   and out cannot do that. It also needs no pseudo-element, no stagger and no
   fill-mode, which is where the last three bugs all came from. */
@keyframes kao-land-ring {
    0%   { box-shadow: inset 0 0 0 0 rgba(232, 137, 29, 0); }
    28%  { box-shadow: inset 0 0 0 3px rgba(232, 137, 29, 0.6); }
    100% { box-shadow: inset 0 0 0 3px rgba(232, 137, 29, 0); }
}

/* Both levels get it. With no movement at all there is nothing here a
   reduced-motion visitor needs protecting from, so `anim-lite` is not a
   lesser version -- it is the same effect without the scroll reveals. */
:is(.anim, .anim-lite) .just-landed {
    animation: kao-land-ring 0.85s ease-out;
}

/* Line bands. Full-bleed on purpose: they are dividers between the two halves
   of the business, not headings inside one. Deliberately NOT <h2> -- every
   section below still carries its own, and demoting twelve of them to <h3> to
   nest under a band would rearrange the document outline for a purely visual
   grouping. Screen readers still get the section headings in order; this is
   for the person scrolling past. */
.line-band {
    margin-top: 3rem;
    padding: 1.5rem 1.5rem 1.3rem;
    text-align: center;
    background: var(--bg-card);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
}

.line-band-label {
    display: block;
    font-weight: 700;
    letter-spacing: 0.5px;
    /* clamp() rather than another breakpoint -- there are already four. */
    font-size: clamp(1.3rem, 4vw, 1.7rem);
}

.line-band-sub {
    color: var(--text-muted);
    max-width: 52em;
    margin: 0.4rem auto 0;
    font-size: 0.98rem;
}

.line-band-print .line-band-label { color: var(--kao-orange); }
.line-band-web .line-band-label { color: var(--heading-accent); }
.line-band-both .line-band-label { color: var(--text); }

/* Centred sections — "Start a Print" and the FAQ.
   These two are the only sections whose content is narrower than the 1000px
   container (form 720px, FAQ list 780px), so left-aligning them left a wide
   gap on the right: the form ended 404px short of the edge, the FAQ 344px.
   Centring the block AND its heading makes the whole section read as centred.
   The fields inside the form and the text inside each answer stay LEFT
   aligned — centred body copy and centred form labels are hard to read. */
#order > h2,
#faq > h2 { justify-content: center; }

#order > .section-sub,
#faq > .section-sub { text-align: center; margin-left: auto; margin-right: auto; }

.order-form,
.faq-list { margin-left: auto; margin-right: auto; }

/* ------------------------------------------------------------------
   Gallery + lightbox
   ------------------------------------------------------------------ */
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
    margin-top: 1.5rem;
}

.gallery-item {
    margin: 0;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--bg-card);
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: transform 0.2s, border-color 0.2s;
}

.gallery-item:hover,
.gallery-item:focus-visible {
    transform: translateY(-4px);
    border-color: var(--kao-orange);
    outline: none;
}

.gallery-item img {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    background: #0d0d0d;
}

.gallery-item figcaption {
    padding: 0.6rem 0.8rem;
    font-size: 0.88rem;
    color: var(--text-muted);
}

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: grid;
    place-items: center;
    padding: 2rem 1rem;
}

.lightbox-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.82);
    backdrop-filter: blur(3px);
}

.lightbox-figure {
    position: relative;
    margin: 0;
    max-width: 900px;
    text-align: center;
}

.lightbox-figure img {
    max-width: 100%;
    max-height: 78vh;
    border-radius: 12px;
    border: 1px solid var(--border);
}

.lightbox-figure figcaption { margin-top: 0.8rem; color: #f2f2f6; }

/* ------------------------------------------------------------------
   FAQ accordion
   ------------------------------------------------------------------ */
.faq-list { margin-top: 1.5rem; max-width: 780px; }

.faq-item {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    margin-bottom: 0.7rem;
    overflow: hidden;
}

.faq-item summary {
    cursor: pointer;
    padding: 1rem 1.2rem;
    font-weight: 600;
    color: var(--heading-accent);
    list-style: none;
    display: flex;
    justify-content: space-between;
    gap: 0.8rem;
    align-items: center;
}

.faq-item summary::-webkit-details-marker { display: none; }

.faq-item summary::after {
    content: '+';
    color: var(--kao-orange);
    font-size: 1.3rem;
    line-height: 1;
    flex-shrink: 0;
}

.faq-item[open] summary::after { content: '\2013'; }

.faq-item p {
    margin: 0;
    padding: 0 1.2rem 1.1rem;
    color: var(--text-muted);
    white-space: pre-wrap;
}

/* ------------------------------------------------------------------
   Footer socials
   ------------------------------------------------------------------ */
.footer-social {
    display: flex;
    gap: 1.2rem;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 1rem;
}

.footer-social a {
    color: var(--text-muted);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.92rem;
    transition: color 0.2s;
}

.footer-social a:hover { color: var(--kao-orange); }

/* ------------------------------------------------------------------
   Back-to-top button — appears after scrolling past the hero
   ------------------------------------------------------------------ */
.back-to-top {
    position: fixed;
    left: 1.2rem;
    bottom: 1.2rem;
    z-index: 150;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: none;
    background: var(--kao-orange);
    color: #2b1600;
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 4px 16px rgba(232, 137, 29, 0.45);
    display: grid;
    place-items: center;
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s, filter 0.2s, box-shadow 0.2s;
}

.back-to-top.visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.back-to-top:hover {
    filter: brightness(1.1);
    box-shadow: 0 6px 20px rgba(232, 137, 29, 0.6);
}

.back-to-top:focus-visible {
    outline: 2px solid var(--kao-orange);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .back-to-top {
        transform: none;
        transition: opacity 0.25s, visibility 0.25s, background 0.2s, color 0.2s;
    }
}

/* ------------------------------------------------------------------
   Two doors + the web-project section (2026-09-17)
   The homepage now leads with "What We Do": two cards that are LINKS to
   the print and web sections. An <a> with the .card look needs its own
   display/colour reset, or it inherits link blue and underlines everything.
   ------------------------------------------------------------------ */
.doors { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.card-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

.card-link .card-more {
    display: inline-block;
    margin-top: 0.9rem;
    font-weight: 600;
    color: var(--accent);
}

.card-link:hover .card-more { text-decoration: underline; }

.card-link:focus-visible {
    outline: 2px solid var(--kao-orange);
    outline-offset: 3px;
}

/* Four steps for a web build; the print steps stay three. A narrower minimum
   keeps all four on one row inside the 1000px container. */
.web-steps { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.steps p a {
    color: var(--accent);
    text-decoration: none;
}

.steps p a:hover { text-decoration: underline; }

/* The web section is full width (cards + steps) with the form centred below —
   so the FORM gets its own centred heading rather than the section's. */
.form-heading {
    margin: 2.4rem 0 0;
    text-align: center;
    font-size: 1.45rem;
    font-weight: 600;
    color: var(--heading-accent);
}

.form-sub { text-align: center; margin: 0.3rem auto 0; }

#start-web .order-form { margin-top: 1.3rem; }
#start-web { padding-top: 0; }

/* Our Work — the web portfolio (admin Content page, work.php). A tile is the
   site's screenshot, cropped from the top so the header and hero show, with
   the name, one line on what we did, and a link out. Hidden until an entry
   is visible, like the Gallery. */
.work-grid {
    display: grid;
    /* Flexible tracks (the column COUNT comes from the 280px minimum — a
       definite max like 640px would be used for the count instead and give
       one column), items capped at 640px and centred in their track: one
       site is a card in the middle, two share the row, three fill it. */
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    justify-items: center;
    gap: 1.2rem;
    margin-top: 1.5rem;
}

.work-item {
    width: 100%;
    max-width: 640px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
    box-shadow: var(--shadow);
    display: flex;
    flex-direction: column;
    transition: transform 0.2s, border-color 0.2s;
}

.work-item:hover { transform: translateY(-4px); border-color: var(--kao-orange); }

.work-shot {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    object-position: top;
    background: #0f0f0f;
    border-bottom: 1px solid var(--border);
}

.work-shot-empty {
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 10;
    font-size: 3rem;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}

.work-body { padding: 1.1rem 1.3rem 1.3rem; display: flex; flex-direction: column; gap: 0.4rem; flex: 1; }

.work-body h3 { margin: 0; font-weight: 600; color: var(--heading-accent); }

.work-body p { margin: 0; color: var(--text-muted); flex: 1; }

.work-link {
    align-self: flex-start;
    margin-top: 0.5rem;
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
}

.work-link:hover { text-decoration: underline; }

/* ------------------------------------------------------------------
   Care plans — "Keeping it running" (2026-09-24). Priced from the admin
   Plans page via care.php; the section hides itself until published.
   ------------------------------------------------------------------ */
.care-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.care-tier {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.care-price {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin: 0.2rem 0 0.1rem;
}

.care-price .amount {
    font-size: 1.9rem;
    font-weight: 700;
    color: var(--accent);
    line-height: 1.1;
}

.care-price .per { color: var(--text-muted); font-size: 0.92rem; }

.care-alt { font-size: 0.85rem; color: var(--text-muted); margin: 0; }

.care-list { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.4rem; }

.care-list li {
    position: relative;
    padding-left: 1.4rem;
    color: var(--text-muted);
    font-size: 0.94rem;
}

.care-list li::before {
    content: "✓";
    position: absolute;
    left: 0;
    color: var(--accent);
    font-weight: 700;
}

.care-hourly {
    text-align: center;
    color: var(--text-muted);
    margin: 1.4rem auto 0;
    max-width: 46em;
}

.care-hourly strong { color: var(--text); }

/* The disclaimer is meant to be read, not buried: bordered, full width,
   quieter than the cards but not grey-on-grey. */
.care-smallprint {
    max-width: 46em;
    margin: 1.6rem auto 0;
    padding: 0.9rem 1.2rem;
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: 12px;
    background: var(--bg-card);
    color: var(--text-muted);
    font-size: 0.89rem;
    line-height: 1.6;
}

.care-smallprint strong { color: var(--text); }

/* ------------------------------------------------------------------
   Watch — the YouTube channel (2026-09-24, watch.php).

   Every tile is the same 16:9 frame, which is the whole problem: five of
   the seven videos are Shorts, and a 9:16 thumbnail in a 16:9 hole has to
   go somewhere. Cropping it keeps a third of the picture; letting it float
   on black bars looks like a mistake. So the image sits full-height and
   centred over a blurred, darkened copy of itself. A landscape thumbnail
   fills the frame exactly and the wash never shows, so one rule covers
   both shapes with no per-video branching.
   ------------------------------------------------------------------ */
.watch-grid {
    display: grid;
    /* 280px against the 940px of content inside .container means exactly
       three across on desktop, two on a tablet, one on a phone. */
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.2rem;
    margin-top: 1.5rem;
}

.watch-item {
    display: flex;
    flex-direction: column;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
    box-shadow: var(--shadow);
    text-decoration: none;
    color: inherit;
    transition: transform 0.2s, border-color 0.2s;
}

.watch-item:hover,
.watch-item:focus-visible {
    transform: translateY(-4px);
    border-color: var(--kao-orange);
}

.watch-shot {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: #0f0f0f;
    border-bottom: 1px solid var(--border);
}

/* The wash behind a vertical thumbnail. --shot is set from JS, built from
   the 11-character video id and never from anything the feed sent as text.
   inset:-8% pushes the blur's own soft edge outside the tile, which would
   otherwise read as a pale rim around the picture. */
.watch-shot::before {
    content: '';
    position: absolute;
    inset: -8%;
    background-image: var(--shot);
    background-size: cover;
    background-position: center;
    filter: blur(18px) brightness(0.45) saturate(1.1);
}

.watch-thumb {
    position: relative;   /* above the wash */
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;  /* 16:9 fills it; 9:16 sits full height, centred */
}

.watch-play {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 54px;
    height: 54px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: rgba(12, 12, 16, 0.7);
    border: 2px solid rgba(255, 255, 255, 0.85);
    color: #fff;
    font-size: 1.05rem;
    padding-left: 3px;    /* a triangle centres left of where its box does */
    transition: background 0.2s, border-color 0.2s, transform 0.2s;
}

.watch-item:hover .watch-play,
.watch-item:focus-visible .watch-play {
    background: var(--kao-orange);
    border-color: var(--kao-orange);
    transform: translate(-50%, -50%) scale(1.08);
}

.watch-badge {
    position: absolute;
    left: 0.6rem;
    top: 0.6rem;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    background: rgba(12, 12, 16, 0.78);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.3);
}

.watch-body {
    padding: 0.9rem 1.1rem 1.1rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    flex: 1;
}

/* Two lines, then an ellipsis: the titles run long and a tile that grows to
   fit one drags the whole row with it. */
.watch-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--heading-accent);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.watch-date {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.85rem;
}

.watch-more {
    text-align: center;
    margin: 1.5rem 0 0;
}

/* ------------------------------------------------------------------
   The questionnaire offer in the web form's thank-you state (2026-10-01).
   The short request form stays short on purpose — a long first form loses
   customers — so the deeper questions are offered here instead, once they
   have already said yes to something.
   ------------------------------------------------------------------ */
.brief-offer {
    margin: 1rem 0 0;
    padding: 1.1rem 1.2rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: 12px;
}

.brief-offer-h {
    margin: 0 0 0.3rem;
    font-weight: 600;
    color: var(--heading-accent);
}

.brief-offer p {
    margin: 0 0 0.9rem;
    color: var(--text-muted);
    font-size: 0.92rem;
}

.brief-offer .btn { text-decoration: none; }
