/* ==========================================================================
   Dileep Dilraj - Portfolio
   1.  Design tokens
   2.  Reset & base
   3.  Layout shell
   4.  Theme toggle
   5.  Buttons, pills & badges
   6.  Sidebar / profile
   7.  Section headings
   8.  Cards
   9.  Feature card (AI agent)
   10. Videos
   11. Skills
   12. Timeline
   13. Contact & footer
   14. Motion & accessibility
   15. Responsive
   ========================================================================== */

/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */
:root {
    color-scheme: light;

    --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

    /* Surfaces & text */
    --bg: #ffffff;
    --bg-soft: #f6f7f9;
    --surface: #ffffff;
    --surface-2: #fafafb;
    --surface-3: #f2f3f5;
    --border: #e8e9ec;
    --border-strong: #d7d9df;
    --text: #0e0f12;
    --text-2: #3f434c;
    --muted: #74787f;

    /* Accent - #4fcaff, the brand light blue.
       It is bright enough to be a surface rather than an ink: on white it only
       reaches 1.87:1, so it fills shapes and dark type sits on top of it. Where
       the accent has to BE the text on a white page, --accent-ink carries the
       same hue taken down to 4.5:1 instead. */
    --accent: #4fcaff;
    --accent-hover: #2fb9f5;
    --accent-soft: rgba(79, 202, 255, 0.14);
    --accent-border: rgba(79, 202, 255, 0.55);
    /* Near-black on the light blue: 8.9:1, where white would be 1.87:1. */
    --on-accent: #04212e;
    --accent-ink: #0a7fae;
    --accent-ink-hover: #075f83;
    --positive: #16a34a;

    /* Shape */
    --radius-xs: 8px;
    --radius-sm: 12px;
    --radius: 16px;
    --radius-lg: 20px;
    --radius-pill: 999px;

    /* Depth */
    --shadow-sm: 0 1px 2px rgba(14, 15, 18, .04), 0 2px 6px rgba(14, 15, 18, .04);
    --shadow-md: 0 4px 12px rgba(14, 15, 18, .06), 0 12px 28px rgba(14, 15, 18, .07);
    --ring: 0 0 0 3px rgba(79, 202, 255, .45);

    /* Scrollbar */
    --scroll-thumb: rgba(14, 15, 18, .22);
    --scroll-thumb-hover: rgba(14, 15, 18, .38);

    /* Metrics */
    --shell: 1200px;
    --gap: 20px;

    /* Hover.
       Everything that answers to the pointer answers the same way: it swells a
       little where it stands. It used to lift instead, and a couple of pixels
       up the page is a movement rather than a response - on a grid of cards it
       read as the row twitching as the cursor crossed it, and it nudged the
       thing you were aiming at out from under you.

       Two sizes, because the same percentage is not the same gesture on a chip
       and on a 600px card: a large surface needs a much smaller number to read
       as the same amount of swell. */
    --hover-scale: 1.01;
    --hover-scale-sm: 1.04;

    /* Liquid glass.
       The border and the top highlight used to be white, which read as a lit
       edge while a colour wash sat behind the panes. Over a flat white page a
       white edge is simply not there, and the cards lost their outline
       altogether - so on light the edge is now a real hairline. */
    --glass-bg: rgba(255, 255, 255, .58);
    --glass-bg-strong: rgba(255, 255, 255, .74);
    --glass-border: rgba(14, 15, 18, .10);
    --glass-highlight: rgba(255, 255, 255, .9);
    --glass-edge: rgba(14, 15, 18, .07);
    --glass-blur: 20px;
    --glass-shadow: 0 1px 2px rgba(14, 15, 18, .04), 0 10px 30px rgba(14, 15, 18, .08);
    --glass-shadow-lg: 0 2px 6px rgba(14, 15, 18, .05), 0 18px 44px rgba(14, 15, 18, .12);
}

[data-theme="dark"] {
    --glass-bg: rgba(22, 25, 30, .55);
    --glass-bg-strong: rgba(24, 28, 34, .72);
    --glass-border: rgba(255, 255, 255, .10);
    --glass-highlight: rgba(255, 255, 255, .16);
    --glass-edge: rgba(0, 0, 0, .5);
    --glass-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 30px rgba(0, 0, 0, .45);
    --glass-shadow-lg: 0 2px 8px rgba(0, 0, 0, .5), 0 20px 48px rgba(0, 0, 0, .6);
}

[data-theme="dark"] {
    color-scheme: dark;

    --bg: #08090b;
    --bg-soft: #0e1013;
    --surface: #101215;
    --surface-2: #14171b;
    --surface-3: #1b1f24;
    --border: #23272e;
    --border-strong: #333944;
    --text: #f3f4f6;
    --text-2: #c3c7ce;
    --muted: #8b929d;

    /* On the dark ground the brand blue needs no help: 10.6:1 against --bg,
       so ink and fill are the same colour here. */
    --accent: #4fcaff;
    --accent-hover: #7fd9ff;
    --accent-soft: rgba(79, 202, 255, 0.12);
    --accent-border: rgba(79, 202, 255, 0.32);
    --on-accent: #04212e;
    --accent-ink: #4fcaff;
    --accent-ink-hover: #7fd9ff;
    --positive: #3ddc84;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
    --shadow-md: 0 8px 30px rgba(0, 0, 0, .55);
    --ring: 0 0 0 3px rgba(79, 202, 255, .38);

    --scroll-thumb: rgba(255, 255, 255, .20);
    --scroll-thumb-hover: rgba(255, 255, 255, .34);
}

/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    /* The gutter is reserved whether or not a scrollbar is showing. Without it
       the preloader - which locks scrolling - has no scrollbar, and handing over
       to the site puts one back and shoves the whole layout sideways. */
    scrollbar-gutter: stable;
    scrollbar-width: thin;
    scrollbar-color: var(--scroll-thumb) transparent;
}

/* Custom scrollbar. The thumb is drawn inside a transparent border so it reads
   as a slim pill floating in the gutter rather than filling it. */
::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background-color: var(--scroll-thumb);
    border: 3px solid transparent;
    background-clip: content-box;
    border-radius: 999px;
}

::-webkit-scrollbar-thumb:hover {
    background-color: var(--scroll-thumb-hover);
}

::-webkit-scrollbar-corner {
    background: transparent;
}

/* The page colour lives on <html> so body can stay transparent - that lets the
   ambient wash sit behind the content but in front of the page background. */
html {
    background: var(--bg);
}

body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 16px;
    line-height: 1.6;
    color: var(--text);
    background: transparent;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
    transition: color .25s ease;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    margin: 0;
    font-weight: 650;
    line-height: 1.25;
    letter-spacing: -0.02em;
    color: var(--text);
}

p {
    margin: 0;
}

img,
video {
    max-width: 100%;
    display: block;
}

a {
    color: inherit;
    text-decoration: none;
}

ul,
ol,
dl,
dd {
    margin: 0;
    padding: 0;
    list-style: none;
}

button {
    font: inherit;
    color: inherit;
    border: 0;
    background: none;
    cursor: pointer;
}

/* A disabled control is still a button, but it is not offering anything. */
button:disabled {
    cursor: default;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: var(--radius-xs);
}

::selection {
    background: var(--accent);
    color: var(--on-accent);
}

.dd-skip {
    position: absolute;
    left: 16px;
    top: -100px;
    z-index: 200;
    padding: 10px 18px;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--on-accent);
    font-weight: 600;
    transition: top .2s ease;
}

.dd-skip:focus {
    top: 12px;
}

.dd-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   3. LAYOUT SHELL
   ========================================================================== */
.dd-shell {
    width: 100%;
    max-width: var(--shell);
    margin: 0 auto;
    padding: 0 24px;
}

.dd-layout {
    display: grid;
    grid-template-columns: 296px minmax(0, 1fr);
    gap: 56px;
    /* No align-items here: the sidebar must stretch to the row height,
       otherwise its sticky child has no room to travel. */
    padding: 44px 0 0;
}

.dd-main {
    min-width: 0;
    padding-bottom: 40px;
}

.dd-section {
    scroll-margin-top: 28px;
    margin-bottom: 64px;
}

.dd-section:last-child {
    margin-bottom: 0;
}

/* ==========================================================================
   4. THEME TOGGLE - lives in the top-right of the profile card
   ========================================================================== */
/* Just the icon - no plate, no ring, no fill. The hit area stays a comfortable
   38px square; only the chrome is gone. */
.dd-theme-toggle {
    position: absolute;
    top: 20px;
    right: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--muted);
    transition: color .2s ease, transform .3s cubic-bezier(.2, 1.4, .4, 1);
}

.dd-theme-toggle:hover {
    color: var(--text);
    background: none;
    transform: scale(1.12);
}

.dd-theme-toggle:active {
    transform: scale(.9);
    transition-duration: .1s;
}

/* --------------------------------------------------------------------------
   Tabler's sun and moon, stacked on the same spot. The script spins one out as
   the other spins in - no shadows, just the two glyphs and the colour.
   -------------------------------------------------------------------------- */
.dd-theme-icon {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 21px;
    height: 21px;
}


/* ==========================================================================
   5. BUTTONS, PILLS & BADGES
   ========================================================================== */
.dd-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 18px;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--text);
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    transition: background-color .18s ease, border-color .18s ease, color .18s ease, transform .18s ease, box-shadow .18s ease;
}

.dd-btn:hover {
    border-color: var(--border-strong);
    background: var(--surface-3);
    transform: scale(var(--hover-scale-sm));
}

.dd-btn svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
}

.dd-btn--primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.dd-btn--primary:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: var(--on-accent);
}

.dd-btn--sm {
    padding: 7px 14px;
    font-size: 13px;
}

.dd-btn--block {
    width: 100%;
}

/* A label, not a control. Nothing here can be pressed - these name a skill or
   tag a card - so the chip is a flat fill and nothing else: no rim, no shadow,
   no answer to the pointer. Dressed as glass with a raised edge they read as a
   row of buttons that do not work when you click them. */
.dd-pill {
    display: inline-flex;
    align-items: center;
    padding: 5px 13px;
    border-radius: var(--radius-pill);
    border: 0;
    background: var(--surface-3);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-2);
    cursor: default;
}

.dd-pill--accent {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.dd-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 12px 5px 10px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--accent-border);
    background: var(--accent-soft);
    color: var(--accent-ink);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .01em;
}

.dd-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.dd-dot--live {
    background: var(--positive);
    box-shadow: 0 0 0 3px rgba(22, 163, 74, .22);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--positive) 22%, transparent);
    animation: dd-pulse 2.4s ease-out infinite;
}

@keyframes dd-pulse {

    0%,
    70%,
    100% {
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--positive) 22%, transparent);
    }

    35% {
        box-shadow: 0 0 0 5px color-mix(in srgb, var(--positive) 10%, transparent);
    }
}

.dd-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* ==========================================================================
   6. SIDEBAR / PROFILE
   ========================================================================== */
/* Sticky rail on desktop only. max-height keeps a tall card reachable
   on short screens; the scrollbar only appears if it actually overflows. */
@media (min-width: 961px) {
    .dd-sidebar-inner {
        position: sticky;
        top: 28px;
        max-height: calc(100vh - 56px);
        overflow-y: auto;
        overscroll-behavior: contain;
        /* A scroll container clips to its padding box, and the card's shadow was
           being sliced off flat along the bottom. The padding gives the shadow
           room to fall inside the box; the negative margin puts the card back
           where it was. */
        padding: 8px 10px 26px;
        margin: -8px -10px -26px;
    }
}

.dd-profile {
    position: relative;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);

    background: linear-gradient(
        180deg,
        var(--surface-2) 0,
        var(--surface) 150px
    );

    padding: 28px 24px 24px;
    box-shadow: var(--shadow-sm);

    /* Don't clip the shadow */
    overflow: visible;
}

.dd-avatar {
    width: 88px;
    height: 88px;
    border-radius: 50%;
    border: 0;
    background: var(--surface-3);
    margin-bottom: 16px;
    /* Hairline ring + a soft lift, instead of a flat 1px border. */
    box-shadow: 0 0 0 1px var(--border), 0 6px 18px rgba(14, 15, 18, .10);
}

[data-theme="dark"] .dd-avatar {
    box-shadow: 0 0 0 1px var(--border-strong), 0 6px 20px rgba(0, 0, 0, .55);
}

.dd-name {
    font-size: 25px;
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1.15;
}

.dd-role {
    color: var(--muted);
    font-size: 14px;
    font-weight: 500;
    margin-top: 5px;
}

/* Availability chip - tinted with the positive colour so it reads as a signal,
   not just another grey pill. */
.dd-status {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 16px;
    padding: 5px 13px 5px 11px;
    border-radius: var(--radius-pill);
    border: 1px solid rgba(22, 163, 74, .26);
    border-color: color-mix(in srgb, var(--positive) 26%, transparent);
    background: rgba(22, 163, 74, .08);
    background: color-mix(in srgb, var(--positive) 8%, transparent);
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .005em;
    color: var(--positive);
    color: color-mix(in srgb, var(--positive) 72%, var(--text));
}

.dd-bio {
    margin-top: 16px;
    font-size: 14.5px;
    line-height: 1.62;
    color: var(--text-2);
    text-wrap: pretty;
}

.dd-meta {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    font-size: 13.5px;
    color: var(--muted);
}

.dd-meta li {
    display: flex;
    align-items: center;
    gap: 9px;
}

.dd-meta svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    color: var(--muted);
    opacity: .85;
}

.dd-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 20px;
}

/* Two equal actions rather than one stray pill. */
.dd-profile .dd-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.dd-profile .dd-actions .dd-btn {
    padding-inline: 12px;
}

.dd-social-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}

.dd-social-row a {
    display: inline-flex;
    border-radius: var(--radius-xs);
    transition: transform .18s ease, opacity .18s ease;
}

.dd-social-row a:hover {
    transform: scale(var(--hover-scale-sm));
}

.dd-brand-icon {
    width: 34px;
    height: 34px;
    border-radius: var(--radius-xs);
}

[data-theme="dark"] .dd-brand-icon {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
}

.dd-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}

/* Hairlines between the cells keep the three numbers from reading as one
   run-on line, and let the labels wrap without looking cramped. */
.dd-stat {
    min-width: 0;
    padding-left: 12px;
    border-left: 1px solid var(--border);
}

.dd-stat:first-child {
    padding-left: 0;
    border-left: 0;
}

.dd-stat dt {
    font-size: 21px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.dd-stat dd {
    font-size: 11.5px;
    line-height: 1.3;
    color: var(--muted);
    margin-top: 5px;
}

/* ==========================================================================
   7. SECTION HEADINGS
   ========================================================================== */
.dd-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
}

.dd-section-title {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
}

.dd-section-count {
    font-size: 13px;
    color: var(--muted);
}

/* ==========================================================================
   8. CARDS
   ========================================================================== */
.dd-grid {
    display: grid;
    gap: var(--gap);
}

.dd-grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.dd-grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.dd-grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* The card's surface is a layer of its own, sitting behind the content rather
   than around it. That is the whole reason it is built this way: the hover
   swells the surface, and scaling the card itself would take everything inside
   with it - type re-rasterised a percent larger, so letter-spacing and every
   inner element visibly resettle. Nothing in here moves; only the pane behind
   it grows.

   The 1px that used to be the border now lives in the padding, so the content
   box is exactly where it always was. */
.dd-card {
    position: relative;
    /* Keeps ::before's negative z-index inside the card rather than letting it
       fall behind the section it sits on. */
    isolation: isolate;
    display: flex;
    flex-direction: column;
    border-radius: var(--radius-lg);
    padding: 21px;
    height: 100%;
}

.dd-card::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border: 1px solid var(--border);
    border-radius: inherit;
    background: var(--surface);
    transition: transform .24s cubic-bezier(.2, .9, .3, 1), border-color .2s ease, box-shadow .2s ease, background-color .2s ease;
}

a.dd-card:hover::before,
.dd-card-link:hover .dd-card::before {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
    transform: scale(var(--hover-scale));
}

.dd-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.dd-card-id {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 650;
    font-size: 15px;
}

/* Intro card */
.dd-intro {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    padding: 28px;
    box-shadow: var(--shadow-sm);
}

.dd-intro h2 {
    font-size: 24px;
    letter-spacing: -0.03em;
}

.dd-intro p {
    margin-top: 12px;
    color: var(--text-2);
    font-size: 16px;
}

.dd-intro .dd-tags {
    margin-top: 20px;
}

/* Behance-style thumb grid */
.dd-thumb-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-top: 16px;
}

.dd-thumb-grid img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: var(--radius-xs);
    background: var(--surface-3);
}

.dd-graph {
    margin-top: 16px;
    width: 100%;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    border: 1px solid var(--border);
    padding: 12px;
}

.dd-graph-img {
    width: 100%;
    border-radius: 6px;
}

/* Only the fallback picture needs a light plate under it - it is a light-
   background PNG. The live chart draws in the page's own colours. */
[data-theme="dark"] .dd-graph:not(.is-live) {
    background: #ffffff;
    border-color: transparent;
}

/* --------------------------------------------------------------------------
   Live contribution chart
   -------------------------------------------------------------------------- */
.dd-gh-svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

/* Sized in viewBox units - the narrower the window, the larger these render,
   so they are set for the four-month view rather than a full year. */
.dd-gh-month {
    font-size: 4.6px;
    font-weight: 500;
    fill: var(--muted);
}

.dd-gh-total {
    margin-top: 10px;
    font-size: 12.5px;
    color: var(--muted);
}

.dd-gh-total b {
    font-weight: 600;
    color: var(--text-2);
}

/* GitHub's own five steps, so the chart reads as a contribution graph rather
   than a generic heatmap. */
.dd-graph {
    --gh-0: #ebedf0;
    --gh-1: #9be9a8;
    --gh-2: #40c463;
    --gh-3: #30a14e;
    --gh-4: #216e39;
}

[data-theme="dark"] .dd-graph {
    --gh-0: #1b1f24;
    --gh-1: #0e4429;
    --gh-2: #006d32;
    --gh-3: #26a641;
    --gh-4: #39d353;
}

.dd-gh-day[data-level="0"] { fill: var(--gh-0); }
.dd-gh-day[data-level="1"] { fill: var(--gh-1); }
.dd-gh-day[data-level="2"] { fill: var(--gh-2); }
.dd-gh-day[data-level="3"] { fill: var(--gh-3); }
.dd-gh-day[data-level="4"] { fill: var(--gh-4); }

/* Compact social card */
.dd-social-card {
    align-items: flex-start;
    gap: 4px;
}

.dd-social-card h3 {
    font-size: 15px;
    margin-top: 12px;
}

.dd-social-card span {
    font-size: 13px;
    color: var(--muted);
}

.dd-social-card .dd-pill {
    margin-top: 14px;
}

/* ---- Case study card ----------------------------------------------------
   Image-led: the cover carries the card, the discipline tag rides on top of
   it, and the read affordance is pinned to the bottom so both cards finish on
   the same line however far their titles wrap. */
.dd-case {
    padding: 0;
}

.dd-case-cover {
    position: relative;
    margin: 10px 10px 0;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--surface-3);
    /* A pale cover would otherwise dissolve into the card on light. */
    box-shadow: inset 0 0 0 1px var(--border);
}

.dd-case-cover img {
    display: block;
    width: 100%;
    /* The width/height attributes reserve the space before the file lands, but
       they also arrive as presentational hints - without height:auto the
       intrinsic height wins and aspect-ratio is ignored. */
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    transition: transform .5s cubic-bezier(.2, .7, .3, 1);
}

.dd-card-link:hover .dd-case-cover img {
    transform: scale(1.035);
}

.dd-case-tag {
    position: absolute;
    top: 10px;
    left: 10px;
    padding: 5px 11px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--glass-border);
    background: var(--glass-bg-strong);
    -webkit-backdrop-filter: blur(12px) saturate(160%);
    backdrop-filter: blur(12px) saturate(160%);
    font-size: 11.5px;
    font-weight: 650;
    letter-spacing: .03em;
    color: var(--text);
}

.dd-case-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
    padding: 16px 18px 18px;
}

.dd-case-title {
    font-size: 17px;
    font-weight: 700;
    line-height: 1.35;
    letter-spacing: -.015em;
    color: var(--text);
}

.dd-case-desc {
    margin: 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--muted);
}

.dd-case-cta {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin-top: auto;
    padding-top: 14px;
    font-size: 13.5px;
    font-weight: 650;
    color: var(--accent-ink);
}

.dd-case-cta svg {
    width: 15px;
    height: 15px;
    transition: transform .2s ease;
}

.dd-card-link:hover .dd-case-cta svg {
    transform: translateX(4px);
}

/* Project card */
.dd-project {
    flex-direction: row;
    align-items: center;
    gap: 18px;
    justify-content: space-between;
}

.dd-project-body {
    min-width: 0;
}

.dd-project-title {
    font-size: 15px;
    font-weight: 600;
    margin-top: 12px;
    line-height: 1.35;
}

.dd-project-url {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    font-size: 13.5px;
    color: var(--muted);
}

.dd-project-url svg {
    width: 12px;
    height: 12px;
    opacity: 0;
    transform: translate(-3px, 3px);
    transition: opacity .2s ease, transform .2s ease;
}

.dd-card-link:hover .dd-project-url {
    color: var(--accent-ink);
}

.dd-card-link:hover .dd-project-url svg {
    opacity: 1;
    transform: translate(0, 0);
}

.dd-project-thumb {
    width: 168px;
    min-width: 168px;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--surface-3);
    border: 1px solid var(--border);
}

/* Collapsed project list */
.js .dd-collapsible[data-collapsed="true"]>*:nth-child(n+7) {
    display: none;
}

.dd-more {
    display: flex;
    justify-content: center;
    margin-top: 22px;
}

.js .dd-more {
    display: flex;
}

.dd-more:not(.is-ready) {
    display: none;
}

/* ==========================================================================
   9. FEATURE CARD (AI AGENT)
   ========================================================================== */
.dd-feature {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    gap: 32px;
    align-items: center;
    padding: 30px;
    border: 1px solid var(--accent-border);
    border-radius: var(--radius-lg);
    background: var(--accent-soft);
    transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
}

.dd-feature:hover {
    box-shadow: var(--shadow-md);
    transform: scale(var(--hover-scale));
}

.dd-feature h2 {
    font-size: 26px;
    margin-top: 14px;
    letter-spacing: -0.03em;
}

.dd-feature p {
    margin-top: 10px;
    color: var(--text-2);
    font-size: 15.5px;
}

.dd-feature-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 18px;
    font-weight: 650;
    font-size: 14.5px;
    color: var(--accent-ink);
}

.dd-feature-cta svg {
    width: 14px;
    height: 14px;
    transition: transform .2s ease;
}

.dd-feature:hover .dd-feature-cta svg {
    transform: translateX(4px);
}

/* Faux chat preview */
.dd-chat {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    box-shadow: var(--shadow-sm);
}

.dd-chat-row {
    display: flex;
    align-items: flex-end;
    gap: 8px;
}

.dd-chat-row--me {
    justify-content: flex-end;
}

.dd-chat-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--border);
    flex-shrink: 0;
}

.dd-bubble {
    max-width: 82%;
    padding: 9px 14px;
    border-radius: 16px;
    font-size: 13.5px;
    line-height: 1.5;
    background: var(--surface-3);
    color: var(--text-2);
}

.dd-bubble--me {
    background: var(--accent);
    color: var(--on-accent);
    border-bottom-right-radius: 5px;
}

.dd-bubble--ai {
    border-bottom-left-radius: 5px;
}

.dd-typing {
    display: inline-flex;
    gap: 4px;
    align-items: center;
    padding: 12px 14px;
}

.dd-typing span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--muted);
    animation: dd-blink 1.4s infinite ease-in-out both;
}

.dd-typing span:nth-child(2) {
    animation-delay: .18s;
}

.dd-typing span:nth-child(3) {
    animation-delay: .36s;
}

@keyframes dd-blink {

    0%,
    80%,
    100% {
        opacity: .25;
    }

    40% {
        opacity: 1;
    }
}

/* ==========================================================================
   10. VIDEOS
   ========================================================================== */
.dd-video {
    position: relative;
    border-radius: var(--radius-lg);
    aspect-ratio: 16 / 9;
    cursor: pointer;
    transition: transform .35s cubic-bezier(.2, .9, .3, 1);
}

.dd-video:hover {
    transform: scale(var(--hover-scale));
}

/* The frame is the piece that flies: it holds the picture and nothing else, so
   it can be lifted into the lightbox and put back without disturbing the tile's
   chip or its play button. */
.dd-video-frame {
    position: absolute;
    inset: 0;
    border: 1px solid var(--border);
    border-radius: inherit;
    background: var(--surface-3);
    overflow: hidden;
}

.dd-video-frame video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.dd-video-open {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: inherit;
}

/* Solid white, and nothing behind it. A translucent disc lets the footage show
   through and reads as a smudge on the picture rather than a control. */
.dd-video-disc {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: #fff;
    color: #101215;
    box-shadow: 0 4px 18px rgba(0, 0, 0, .18);
}

.dd-video-disc svg {
    width: 21px;
    height: 21px;
    margin-left: 2px;
}

/* While a tile's frame is away in the lightbox, the gap it leaves keeps the
   grid's shape instead of collapsing. */
.dd-video.is-open .dd-video-open {
    opacity: 0;
    pointer-events: none;
}

/* --------------------------------------------------------------------------
   LIGHTBOX
   -------------------------------------------------------------------------- */
.dd-lightbox {
    position: fixed;
    inset: 0;
    z-index: 400;
    display: none;
}

.dd-lightbox.is-open {
    display: block;
}

/* Still painted while the picture flies home, but no longer in the way: a click
   aimed at the next video used to land on the fading scrim and do nothing. */
.dd-lightbox.is-closing {
    pointer-events: none;
}

.dd-lightbox-scrim {
    position: absolute;
    inset: 0;
    /* Clicking the dim area closes the player, the same as the × does. */
    cursor: pointer;
    background: rgba(6, 7, 9, .82);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    opacity: 0;
}

/* The frame lands here. Grid centring means the flown element needs no
   transform of its own, which keeps Flip's arithmetic honest. */
.dd-lightbox-stage {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 4vmin 4vmin 96px;
    pointer-events: none;
}

.dd-lightbox-stage .dd-video-frame {
    position: relative;
    inset: auto;
    width: min(1180px, 100%);
    aspect-ratio: 16 / 9;
    height: auto;
    border: 0;
    border-radius: 16px;
    box-shadow: 0 40px 110px rgba(0, 0, 0, .6);
    pointer-events: auto;
}

.dd-lightbox-stage .dd-video-frame video {
    object-fit: contain;
    background: #000;
}

.dd-lightbox-foot {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 24px;
    display: flex;
    justify-content: center;
    padding: 0 16px;
    pointer-events: none;
}

.dd-lightbox-bar {
    pointer-events: auto;
    display: flex;
    align-items: center;
    gap: 2px;
    /* Extra room on the right: the pill's corner curves in around the close
       button and without it the × looks like it is falling off the end. */
    padding: 6px 12px 6px 6px;
    border-radius: var(--radius-pill);
    background: rgba(20, 22, 26, .82);
    border: 1px solid rgba(255, 255, 255, .12);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    color: #fff;
    opacity: 0;
}

.dd-lb-sep {
    width: 1px;
    align-self: stretch;
    margin: 4px 2px;
    background: rgba(255, 255, 255, .14);
}

.dd-lb-meta {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 0 10px;
}

.dd-lb-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    color: #fff;
    transition: background-color .18s ease;
}

.dd-lb-btn:hover {
    background: rgba(255, 255, 255, .14);
}

.dd-lb-btn--close {
    margin-left: 2px;
}

.dd-lb-btn--close:hover {
    background: rgba(255, 255, 255, .2);
}

/* Centring the glyph needs the pull-back as well as the offset. The scripted
   icons get theirs from GSAP; the close button has no script behind it, so
   without this it hangs down and to the right of its circle. */
.dd-lb-btn svg {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 18px;
    height: 18px;
}

/* The picture is a play/pause target too. */
.dd-lightbox-stage .dd-video-frame {
    cursor: pointer;
}

.dd-lb-time {
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.dd-lb-name {
    max-width: 30vw;
    font-size: 13px;
    color: rgba(255, 255, 255, .62);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (max-width: 640px) {
    .dd-lb-name {
        display: none;
    }

    .dd-lightbox-stage {
        padding: 4vmin 4vmin 88px;
    }
}

/* ==========================================================================
   11. SKILLS
   ========================================================================== */
.dd-skill-group h3 {
    font-size: 15px;
    margin-bottom: 14px;
}

.dd-skill-group .dd-tags .dd-pill {
    background: var(--surface-2);
}

/* ==========================================================================
   12. TIMELINE
   ========================================================================== */
.dd-panel-title {
    font-size: 15px;
    margin-bottom: 18px;
}

.dd-timeline {
    position: relative;
    padding-left: 26px;
}

.dd-timeline::before {
    content: "";
    position: absolute;
    left: 4px;
    top: 6px;
    bottom: 6px;
    width: 1px;
    background: var(--border-strong);
}

.dd-timeline li {
    position: relative;
    padding-bottom: 24px;
}

.dd-timeline li:last-child {
    padding-bottom: 0;
}

.dd-timeline li::before {
    content: "";
    position: absolute;
    left: -26px;
    top: 6px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--surface);
    border: 2px solid var(--border-strong);
}

.dd-timeline li:first-child::before {
    background: var(--accent);
    border-color: var(--accent);
}

.dd-timeline h4 {
    font-size: 15px;
    font-weight: 600;
}

.dd-timeline .dd-org {
    font-size: 13.5px;
    color: var(--text-2);
    margin-top: 1px;
}

.dd-timeline .dd-when {
    font-size: 13px;
    color: var(--muted);
    margin-top: 3px;
}

/* ==========================================================================
   12b. ABOUT ME - long-form prose block
   ========================================================================== */
.dd-about {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    padding: 40px 36px 34px;
    box-shadow: var(--shadow-sm);
}

.dd-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--text-2);
}

.dd-eyebrow svg {
    width: 17px;
    height: 17px;
    color: var(--accent-ink);
    flex-shrink: 0;
}

.dd-about-title {
    margin-top: 20px;
    font-size: clamp(34px, 5vw, 52px);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.045em;
    text-wrap: balance;
}

.dd-about-body {
    margin-top: 28px;
    max-width: 62ch;
}

.dd-about-body p {
    font-size: 16.5px;
    line-height: 1.72;
    color: var(--text-2);
    text-wrap: pretty;
}

.dd-about-body p+p {
    margin-top: 20px;
}

.dd-about-body a {
    color: var(--accent-ink);
    font-weight: 600;
    text-underline-offset: 3px;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--accent-border);
    transition: text-decoration-color .18s ease, color .18s ease;
}

.dd-about-body a:hover {
    color: var(--accent-ink-hover);
    text-decoration-color: currentColor;
}

/* The name is signed, not set. This is the same artwork the intro writes
   itself with, so the flourish that opens the page is the one that closes it -
   where a script webfont was only ever an impression of a signature, and cost
   a second font request to be one.

   Painted as a mask rather than dropped in as an <img>: the file is flat black,
   and a mask lets it be re-inked per theme instead of shipping two of it.

   One number sizes the whole lockup. */
.dd-signature {
    --sig: clamp(52px, 7vw, 78px);
    display: flex;
    align-items: flex-end;
    gap: calc(var(--sig) * .07);
    /* Pulled 15px up and 15px out on every other edge, so the hand overhangs
       the measure of the writing the way a signature on paper does rather than
       lining up with it. The top is the old 34px less the same 15. */
    margin: 19px -15px -15px;
    /* The glow lives here, on the lockup, and not on the mark itself: a filter
       is applied before the mask is, so a drop-shadow declared on the masked
       element gets cut away by the very mask that gives it its shape. On the
       parent it acts on the finished letterforms, so the light follows the ink
       and the stop rather than boxing the whole block.

       Declared at zero strength at rest so the two shadows interpolate; from
       `none` it would simply snap on. */
    width: fit-content;
    filter: drop-shadow(0 0 0 transparent);
    transition: filter .34s ease;
}

.dd-signature:hover {
    filter: drop-shadow(0 0 9px color-mix(in srgb, var(--text) 38%, transparent));
}

.dd-signature-mark {
    display: block;
    /* 392 x 129 in the file, so the width follows the height and the artwork
       is never stretched. */
    width: calc(var(--sig) * 392 / 129);
    height: var(--sig);
    /* Written in ink, not in the accent: white on the dark theme, near-black on
       the light one. The accent is saved for the full stop, which is the one
       mark here that is the brand rather than the hand. */
    background-color: var(--text);
    -webkit-mask: url("assets/imgs/DileepDilraj-name.svg") no-repeat center / contain;
    mask: url("assets/imgs/DileepDilraj-name.svg") no-repeat center / contain;
}

/* The full stop after it. The writing line sits at 97 of the file's 129 units
   - the rest is the tail of the j - so the stop is lifted by the difference
   and lands on the line rather than under the descender. */
.dd-signature-dot {
    width: calc(var(--sig) * .085);
    height: calc(var(--sig) * .085);
    margin-bottom: calc(var(--sig) * 32 / 129);
    border-radius: 50%;
    background: var(--accent-ink);
}

/* ==========================================================================
   13. CONTACT & FOOTER
   ========================================================================== */
.dd-contact {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface-2);
    padding: 40px 32px;
    text-align: center;
}

.dd-contact h2 {
    font-size: 28px;
    letter-spacing: -0.03em;
}

.dd-contact p {
    margin: 12px auto 0;
    max-width: 52ch;
    color: var(--text-2);
}

.dd-contact .dd-actions {
    justify-content: center;
    margin-top: 24px;
}

.dd-footer {
    border-top: 1px solid var(--border);
    margin-top: 72px;
    /* Bottom padding clears the floating dock menu. */
    padding: 28px 0 108px;
}

.dd-footer-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    flex-wrap: wrap;
    font-size: 13.5px;
    color: var(--muted);
    text-align: center;
}

/* ==========================================================================
   13b. DOCK MENU - floating pill nav, bottom centre
   ========================================================================== */
.dd-dock {
    position: fixed;
    left: 50%;
    bottom: 20px;
    z-index: 130;
    display: flex;
    align-items: center;
    /* The mark sits hard against one end and the links against the other, with
       the bar's own width opening the space between them. min-width is what
       makes space-between mean anything - the pill is shrink-to-fit otherwise,
       so there is no free space to push the two groups apart with. The gap is
       only a floor, for the case where the labels ever outgrow that width. */
    justify-content: space-between;
    min-width: 400px;
    gap: 24px;
    padding: 7px 10px 7px 7px;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, .82);
    background: color-mix(in srgb, var(--surface) 84%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(1.7);
    backdrop-filter: blur(16px) saturate(1.7);
    box-shadow: 0 12px 34px rgba(14, 15, 18, .16), 0 2px 8px rgba(14, 15, 18, .06);
    transform: translateX(-50%) translateY(18px);
    opacity: 0;
}

/* Waits for the preloader to get out of the way before sliding up. */
html:not(.dd-loading) .dd-dock {
    animation: dd-dock-in .5s cubic-bezier(.16, .84, .44, 1) .15s forwards;
}

[data-theme="dark"] .dd-dock {
    box-shadow: 0 12px 34px rgba(0, 0, 0, .6), 0 0 0 1px rgba(255, 255, 255, .04);
}

@keyframes dd-dock-in {
    to {
        opacity: 1;
        transform: translateX(-50%) translateY(0);
    }
}

/* The avatar alone. The name used to sit beside it, which said nothing the
   page has not already said twice over and cost the dock a third of its width
   on a phone - width the links needed. */
.dd-dock-id {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
}

/* The D mark on a round white plate. Clipping the artwork straight to a circle
   is what bit into the stem of the D and left a crescent, because the letter
   runs to the edges of its own square. So the file is contained inside the
   circle rather than cropped by it, and the plate carries the same white the
   artwork's ground already is - the seam between the two never shows. */
.dd-dock-id img {
    width: 36px;
    height: 36px;
    padding: 5px;
    border-radius: 50%;
    background: #fff;
    object-fit: contain;
    box-shadow: 0 0 0 1px var(--border);
    transition: transform .22s ease;
}

.dd-dock-id:hover img {
    transform: scale(1.06);
}

.dd-dock-links {
    display: flex;
    align-items: center;
    /* No gap: each label's own padding is the whole of the separation, which
       keeps the three of them reading as one group at the right-hand end
       rather than as three loose controls. */
    gap: 0;
}

.dd-dock-links a {
    display: inline-block;
    padding: 8px 14px;
    border-radius: var(--radius-pill);
    font-size: 14.5px;
    font-weight: 600;
    color: var(--text-2);
    transition: color .18s ease, background-color .18s ease;
}

.dd-dock-links a:hover {
    color: var(--text);
    background: var(--surface-3);
}

.dd-dock-links a.is-current {
    color: var(--accent-ink);
    background: var(--accent-soft);
}

/* ==========================================================================
   13c. CHAT FAB - floats in once the hero is behind you
   ========================================================================== */
.dd-fab {
    position: fixed;
    right: 20px;
    bottom: 18px;
    z-index: 120;
    display: block;
    width: 118px;
    /* Hidden until the script says otherwise; visibility keeps it out of the
       tab order while it is off screen. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(20px) scale(.9);
    transition: opacity .45s cubic-bezier(.16, .84, .44, 1),
        transform .45s cubic-bezier(.16, .84, .44, 1),
        visibility .45s;
}

.dd-fab img {
    width: 100%;
    height: auto;
    /* Pivot at the top, so the idle wobble reads like a bell swinging. */
    transform-origin: 50% 8%;
    filter: drop-shadow(0 10px 18px rgba(14, 15, 18, .18));
}

/* No plate behind it on dark - just the artwork. */
[data-theme="dark"] .dd-fab img {
    filter: none;
}

.dd-fab.is-visible {
    opacity: 1;
    visibility: visible;
    transform: none;
}

.dd-fab.is-visible img {
    animation: dd-fab-ring 6s ease-in-out 1.4s infinite;
}

/* The lift goes on the anchor, not the artwork. The bell swing is a running
   animation writing transform on the image, and a running animation outranks
   any plain rule underneath it - a scale set on the image here never showed at
   all. Scaling the wrapper composes with the swing instead of losing to it. */
.dd-fab.is-visible:hover,
.dd-fab.is-visible:focus-visible {
    transform: scale(1.06);
    transition: transform .2s ease;
}

.dd-fab.is-visible:hover img,
.dd-fab.is-visible:focus-visible img {
    animation-play-state: paused;
}

.dd-fab.is-visible:active {
    transform: scale(.97);
    transition: transform .1s ease;
}

@keyframes dd-fab-ring {

    0%,
    58%,
    100% {
        transform: rotate(0deg);
    }

    62% {
        transform: rotate(-14deg);
    }

    68% {
        transform: rotate(11deg);
    }

    74% {
        transform: rotate(-7deg);
    }

    80% {
        transform: rotate(4deg);
    }

    86% {
        transform: rotate(-2deg);
    }
}

.dd-fab-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.2;
}

.dd-fab-title {
    font-size: 14.5px;
    font-weight: 650;
    letter-spacing: -0.01em;
    color: var(--text);
}

.dd-fab-sub {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 11.5px;
    font-weight: 500;
    color: var(--muted);
}

.dd-fab-sub .dd-dot {
    width: 6px;
    height: 6px;
}

/* ==========================================================================
   13d. THEME TRANSITION - the new theme wipes in as a growing circle
   ========================================================================== */
/* The old theme is held still underneath while the new one is revealed by a
   circle that grows out of the toggle. The animation lives in CSS - driven by
   custom properties the script sets - so the new snapshot is already clipped
   on its very first frame, with no flash of the finished theme. */
/* Scoped to the theme switch on purpose. The same pseudo-elements are used by
   the cross-document page transition further down, and that one does want an
   animation of its own - an unscoped `animation: none` here used to strip it. */
.dd-switching::view-transition-old(root),
.dd-switching::view-transition-new(root) {
    mix-blend-mode: normal;
    /* Both snapshots are driven by the rules below; neither may keep the UA's
       default cross-fade, which is what made the swap read as a second change
       landing after the circle had already finished. */
    animation: none;
}

/* Going dark: the night pours in. The new theme grows out of the toggle over
   the old one, which is held still underneath. */
.dd-vt-fill::view-transition-old(root) {
    z-index: 1;
}

.dd-vt-fill::view-transition-new(root) {
    z-index: 2;
    animation: dd-theme-fill .95s cubic-bezier(.65, 0, .35, 1) forwards;
}

/* Going light: the night is drawn back out. The old theme shrinks into the
   toggle and the new one is simply sitting behind it, already there. */
.dd-vt-suck::view-transition-old(root) {
    z-index: 2;
    animation: dd-theme-suck .95s cubic-bezier(.65, 0, .35, 1) forwards;
}

.dd-vt-suck::view-transition-new(root) {
    z-index: 1;
}

@keyframes dd-theme-fill {
    from {
        clip-path: circle(0 at var(--dd-vt-x, 50%) var(--dd-vt-y, 50%));
    }

    to {
        clip-path: circle(var(--dd-vt-r, 150%) at var(--dd-vt-x, 50%) var(--dd-vt-y, 50%));
    }
}

@keyframes dd-theme-suck {
    from {
        clip-path: circle(var(--dd-vt-r, 150%) at var(--dd-vt-x, 50%) var(--dd-vt-y, 50%));
    }

    to {
        clip-path: circle(0 at var(--dd-vt-x, 50%) var(--dd-vt-y, 50%));
    }
}

/* Nothing else may animate while the snapshots are being taken, or the new
   snapshot captures a half-finished colour. */
.dd-switching *,
.dd-switching *::before,
.dd-switching *::after {
    transition: none !important;
    /* Snapshotting a page full of blurred panes is the expensive half of the
       swap, and it is what leaves the circle stuttering part-way across before
       the rest of the change lands. The panes sit over flat colour, so going
       without the blur for half a second costs next to nothing. */
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
}

/* ==========================================================================
   13e. LIQUID GLASS
   Every raised surface becomes a pane: translucent fill, blurred backdrop,
   a bright top edge for the specular highlight and a soft inner shade at the
   bottom. Applied last so it wins over the flat backgrounds above.
   ========================================================================== */
.dd-profile,
.dd-intro,
.dd-about,
.dd-feature,
.dd-contact,
.dd-video,
.dd-dock,
.dd-btn,
.dd-status,
.dd-card::before {
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.8);
    backdrop-filter: blur(var(--glass-blur)) saturate(1.8);
    border-color: var(--glass-border);
}

.dd-profile,
.dd-intro,
.dd-about,
.dd-feature,
.dd-contact {
    background: var(--glass-bg-strong);
    /* One edge only. The 1px spread ring that used to sit here doubled up with
       the element's own border in a slightly different tone, and on the rounded
       corners the two drifted apart into a visible mismatch. */
    box-shadow: var(--glass-shadow);
}

/* On light the hairline is enough to seat the panel; a drop shadow on white
   only ever reads as a smudge. Dark keeps its shadow, further down. */
:root .dd-profile {
    box-shadow: none;
}

/* On dark the pane catches a little light along its top edge. On white the same
   wash is invisible, so light keeps the flat fill. */
[data-theme="dark"] .dd-profile {
    background:
        linear-gradient(180deg, var(--glass-highlight), transparent 130px),
        var(--glass-bg-strong);
    box-shadow: var(--glass-shadow), inset 0 1px 0 var(--glass-highlight);
}

/* Cards are the most repeated surface, so they take a lighter blur. */
.dd-card,
.dd-video {
    --glass-blur: 12px;
}

.dd-video,
.dd-card::before {
    background: var(--glass-bg);
    box-shadow: none;
}

a.dd-card:hover::before,
.dd-card-link:hover .dd-card::before {
    background: var(--glass-bg-strong);
    box-shadow: var(--glass-shadow-lg);
}

.dd-btn {
    --glass-blur: 14px;
    background: var(--glass-bg);
    box-shadow: none;
}

.dd-btn:hover {
    background: var(--glass-bg-strong);
}

/* The accent surfaces stay solid - glass over a saturated fill just muddies it. */
.dd-btn--primary,
.dd-btn--primary:hover,
.dd-pill--accent {
    background: var(--accent);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-color: var(--accent);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22);
}

.dd-btn--primary:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
}

.dd-dock {
    background: var(--glass-bg-strong);
    box-shadow: 0 0 0 1px var(--glass-edge), var(--glass-shadow-lg), inset 0 1px 0 var(--glass-highlight);
}

/* --------------------------------------------------------------------------
   REFRACTION - the pane bends its backdrop instead of only blurring it.

   The warp goes on a pseudo-element rather than the pane itself: an SVG filter
   drags pixels past the element's own edges, so applying it directly would eat
   the border and leave the corners chewed. The pseudo sits behind the content,
   inherits the radius, and is clipped to it.

   Restricted to the panes that actually float over other content, and only in
   engines that composite it correctly (see .dd-glass-refract in the script).
   Displacing a backdrop is expensive - putting it on all fourteen project
   cards costs far more than it shows.
   -------------------------------------------------------------------------- */
.dd-glass-refract .dd-dock {
    /* No position or isolation reset here. The dock is fixed and the toggle is
       absolute, so declaring position would tear them out of place - and
       isolation would open a backdrop root, which is the one thing that stops
       the warped child from seeing any backdrop at all. */
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.dd-glass-refract .dd-dock::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    pointer-events: none;
    -webkit-backdrop-filter: blur(6px) saturate(1.8);
    backdrop-filter: blur(6px) saturate(1.8);
    filter: url(#dd-glass-warp);
}

/* The specular pass: a bright rim catching light along the top-left edge and a
   softer one returning along the bottom-right, which is what reads as a solid
   piece of glass rather than a translucent rectangle. */
.dd-glass-refract .dd-dock {
    box-shadow:
        inset 1px 1px 1px -.5px var(--glass-highlight),
        inset -1px -1px 1px -.5px var(--glass-highlight),
        inset 0 0 8px -2px var(--glass-highlight),
        0 0 0 1px var(--glass-edge),
        var(--glass-shadow);
}

/* --------------------------------------------------------------------------
   The glass answers to the pointer: it swells a little under the cursor and
   gives under a press, on a spring rather than a linear ramp.
   -------------------------------------------------------------------------- */
.dd-glass-refract .dd-dock {
    transition:
        transform .42s cubic-bezier(.2, 1.5, .4, 1),
        box-shadow .32s cubic-bezier(.2, .9, .3, 1),
        background-color .2s ease,
        border-color .2s ease;
}

/* The dock is centred by a translate, so its own scale has to carry that too. */
.dd-glass-refract .dd-dock:hover {
    transform: translateX(-50%) scale(1.03);
    box-shadow:
        inset 1px 1px 2px -.5px var(--glass-highlight),
        inset -1px -1px 2px -.5px var(--glass-highlight),
        inset 0 0 16px -3px var(--glass-highlight),
        0 0 0 1px var(--glass-edge),
        var(--glass-shadow-lg);
}

@media (prefers-reduced-motion: reduce) {

    .dd-glass-refract .dd-dock {
        transition: none;
    }

    .dd-glass-refract .dd-dock:hover {
        transform: translateX(-50%);
    }
}

.dd-glass-defs {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* Browsers without backdrop-filter get the opaque surfaces back, otherwise the
   translucent fills would leave text sitting on the ambient wash. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {

    .dd-profile,
    .dd-intro,
    .dd-about,
    .dd-feature,
    .dd-contact,
    .dd-video,
    .dd-dock,
    .dd-btn,
    .dd-card::before {
        background: var(--surface);
        border-color: var(--border);
    }
}

/* ==========================================================================
   13f. PRELOADER - the name is written out, then the camera flies into the dot
   ========================================================================== */
.dd-preloader {
    position: fixed;
    inset: 0;
    /* inset alone stops at the reserved scrollbar gutter and leaves a bare
       strip down the edge; 100vw takes in the gutter too. */
    width: 100vw;
    z-index: 999;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: var(--bg);
    /* A hole gets masked into this whole layer - backdrop and lettering alike -
       so the site is revealed through it rather than under it. No will-change:
       promoting this to a fixed layer rasterises it at 1x and the rim of the
       hole goes stair-steppy on high-DPI screens. */
}

.dd-preloader.is-done,
/* Second and later loads in the same visit: the intro has already played, so
   the overlay never gets a frame on screen. */
.dd-intro-seen .dd-preloader,
/* The signature is written by script, so without one there is nothing to watch
   and nothing to end the animation - the overlay would just sit there covering
   the site. .js is set in the head, before first paint. */
html:not(.js) .dd-preloader {
    display: none;
}

/* Nothing scrolls while it plays. */
.dd-loading body,
.dd-lightbox-open body {
    overflow: hidden;
}

.dd-preloader-stage {
    position: relative;
    z-index: 1;
    /* em here is the unit the whole lockup is measured in: the full stop, the
       gap before it, and nothing else - the signature carries its own scale. */
    font-size: clamp(46px, 11vw, 108px);
    line-height: 1;
    /* Deliberately no will-change/backface hint here: promoting the lockup to a
       static layer makes the browser scale one raster, and the lettering turns
       to mush by the time it fills the screen. Re-drawing each frame keeps the
       handwriting crisp all the way out. */
}

/* Holds the artwork and the full stop together. The padding is the room the
   dot sits in, so the pair is centred as one lockup rather than the signature
   being centred and the dot hanging off the end of it. */
.dd-preloader-sign {
    position: relative;
    display: block;
    padding-right: .3em;
}

.dd-preloader-art {
    display: block;
    width: min(78vw, 620px);
    height: auto;
    overflow: visible;
}

/* Nothing is ever filled. Every visible mark is one of these strokes, clipped
   to a letter - the clip is what gives the ink its shape. */
.dd-preloader-art .dd-sign-stroke {
    fill: none;
    stroke: var(--text);
    stroke-linecap: round;
    stroke-linejoin: round;
    /* Off the page until the pen reaches it: a round cap on a zero-length dash
       is still a round cap, and would sit there as a spot of ink waiting. */
    display: none;
}

.dd-preloader-dot {
    position: absolute;
    /* 48.18% is where the artwork's own writing line falls: the signature is
       129 units tall and the letters without descenders sit on 66.85, so the
       rest is the room the j's tail needs. Measured off the file rather than
       eyeballed, so the full stop lands on the line the name is written on. */
    bottom: 48.18%;
    right: .07em;
    width: .16em;
    height: .16em;
    border-radius: 50%;
    /* The ink, not the fill: on the white ground the brand blue is only 1.87:1,
       and this dot is the full stop the whole camera move flies into - it has
       to read as a mark on the page, not a tint. */
    background: var(--accent-ink);
    transform: scale(0);
    /* No will-change. Promoting the dot freezes one small raster and stretches
       it, so by the time it is a few hundred pixels across its edge has become
       a wide blue haze bleeding over the opening. Re-drawn each frame it stays
       a clean circle. */
}

/* On a phone the card is already narrow, so the peek is trimmed to a sliver -
   a quarter of it there would cost real reading width. */
@media (max-width: 620px) {
    .dd-slider {
        --slider-gap: 12px;
        --slider-per: 1.12;
    }
}


/* ==========================================================================
   14. MOTION & ACCESSIBILITY
   ========================================================================== */
.js .dd-reveal {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .5s ease, transform .5s ease;
}

.js .dd-reveal.is-visible {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {

    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }

    .js .dd-reveal {
        opacity: 1;
        transform: none;
    }

    .dd-journey {
        scroll-behavior: auto;
    }

    /* No writing animation, no ambient drift - go straight to the site. */
    .dd-preloader {
        display: none;
    }

    .dd-dock {
        opacity: 1;
        transform: translateX(-50%);
    }
}

/* ==========================================================================
   15. RESPONSIVE
   ========================================================================== */
@media (max-width: 1080px) {
    .dd-layout {
        grid-template-columns: 268px minmax(0, 1fr);
        gap: 36px;
    }
}

@media (max-width: 960px) {
    .dd-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 32px;
        padding-top: 28px;
    }

    .dd-profile {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        column-gap: 22px;
        align-items: start;
        /* Room for the theme toggle sitting in the corner. */
        padding-right: 74px;
    }

    .dd-avatar {
        grid-row: span 2;
        margin-bottom: 0;
    }

    .dd-profile>*:not(.dd-avatar):not(.dd-theme-toggle) {
        grid-column: 2;
    }

    /* Grid items stretch by default; the chip must stay content-width. */
    .dd-status {
        justify-self: start;
    }

    .dd-stats {
        grid-column: 1 / -1;
    }

    .dd-social-row {
        grid-column: 1 / -1;
    }

    .dd-feature {
        grid-template-columns: minmax(0, 1fr);
        gap: 24px;
    }
}

@media (max-width: 760px) {
    .dd-shell {
        padding: 0 16px;
    }

    .dd-grid--2,
    .dd-grid--3 {
        grid-template-columns: minmax(0, 1fr);
    }

    .dd-grid--4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .dd-section {
        margin-bottom: 52px;
    }

    .dd-profile {
        display: block;
        padding: 22px 20px;
    }

    .dd-avatar {
        width: 76px;
        height: 76px;
        margin-bottom: 14px;
    }

    .dd-name {
        font-size: 23px;
    }

    .dd-intro {
        padding: 22px 20px;
    }

    .dd-about {
        padding: 28px 20px 24px;
    }

    .dd-about-body {
        margin-top: 22px;
    }

    .dd-about-body p {
        font-size: 15.5px;
        line-height: 1.68;
    }

    .dd-signature {
        margin-top: 26px;
        font-size: 38px;
    }

    .dd-intro h2 {
        font-size: 21px;
    }

    .dd-feature {
        padding: 22px 20px;
    }

    .dd-feature h2 {
        font-size: 22px;
    }

    .dd-project {
        flex-direction: column;
        align-items: stretch;
        gap: 16px;
    }

    .dd-project-thumb {
        order: -1;
        width: 100%;
        min-width: 0;
        aspect-ratio: 16 / 9;
    }

    .dd-project-title {
        margin-top: 10px;
    }

    .dd-contact {
        padding: 32px 20px;
    }

    .dd-contact h2 {
        font-size: 23px;
    }

    .dd-footer-inner {
        gap: 10px;
    }
}

/* Narrow screens: the dock collapses behind the dots, and the FAB stacks
   above it instead of fighting it for the bottom edge. */
/* Narrow screens. Three links are not a menu - they fit on the bar as they
   are, and hiding them behind a button meant every visit to Work or Contact
   from a phone cost a tap to open the thing first. */
@media (max-width: 700px) {
    .dd-dock {
        min-width: 300px;
        gap: 16px;
        bottom: 16px;
    }

    .dd-dock-links a {
        padding: 8px 12px;
        font-size: 14px;
    }
}

/* Only here does the bar run out of room, so this is the one width that gives
   any of it back. */
@media (max-width: 360px) {
    .dd-dock {
        min-width: 270px;
        gap: 10px;
        padding: 7px 8px 7px 7px;
    }

    .dd-dock-links a {
        padding: 8px 10px;
        font-size: 13.5px;
    }
}

@media (max-width: 560px) {
    .dd-fab {
        width: 94px;
        right: 14px;
        bottom: 84px;
    }
}

@media (max-width: 420px) {
    .dd-actions .dd-btn {
        flex: 1 1 100%;
    }

    .dd-video-disc {
        width: 48px;
        height: 48px;
    }
}


/* ==========================================================================
   16. CASE STUDY PAGES  (work/jetlog.html, work/grep.html)
   Long-form reading layout: a sticky contents rail on the left, a measured
   prose column on the right, and figures that are allowed to break out of
   that column when the artwork needs the room.
   ========================================================================== */
.dd-cs-shell {
    width: 100%;
    max-width: 1120px;
    margin: 0 auto;
    padding: 0 24px;
}

/* --- Back link ----------------------------------------------------------- */
.dd-cs-back {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 34px 0 30px;
    padding: 8px 14px 8px 11px;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: var(--surface);
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text-2);
    text-decoration: none;
    transition: color .2s ease, border-color .2s ease, transform .2s ease;
}

.dd-cs-back svg {
    width: 16px;
    height: 16px;
    transition: transform .2s ease;
}

.dd-cs-back:hover {
    color: var(--text);
    border-color: var(--border-strong);
}

.dd-cs-back:hover svg {
    transform: translateX(-3px);
}

/* --- Hero ---------------------------------------------------------------- */
/* The hero fills the same container as the cover image and the fact strip
   below it, so the page opens on one edge rather than two. */
.dd-cs-hero {
    max-width: 100%;
    margin-bottom: 34px;
}

.dd-cs-kicker {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--accent-ink);
}

.dd-cs-title {
    margin: 14px 0 0;
    /* Scaled up with the extra room, so the title still reads as a display
       line rather than a small heading adrift in a wide column. */
    font-size: clamp(30px, 4.6vw, 54px);
    line-height: 1.1;
    letter-spacing: -.025em;
    font-weight: 800;
    color: var(--text);
}

/* The one thing that does not fill the width: a lede set across the whole
   container would run past 120 characters a line and stop being readable. */
.dd-cs-lede {
    max-width: 880px;
    margin: 18px 0 0;
    font-size: clamp(16.5px, 1.7vw, 19.5px);
    line-height: 1.6;
    color: var(--text-2);
}

.dd-cs-byline {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 22px;
    font-size: 13.5px;
    color: var(--muted);
}

.dd-cs-byline img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    object-fit: cover;
}

.dd-cs-byline b {
    font-weight: 600;
    color: var(--text-2);
}

.dd-cs-byline .sep {
    opacity: .5;
}

/* --- Live showcase link -------------------------------------------------- */
/* For a case study that has something real to visit. Accent-filled, because it
   is the one thing in the hero worth leaving the page for. */
.dd-cs-live {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    margin-top: 22px;
    padding: 11px 20px;
    border: 1px solid var(--accent-border);
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    font-size: 14px;
    font-weight: 600;
    color: var(--accent-ink);
    text-decoration: none;
    transition: background .2s ease, color .2s ease, border-color .2s ease, transform .2s ease;
}

.dd-cs-live:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    transform: scale(var(--hover-scale-sm));
}

.dd-cs-live:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

.dd-cs-live svg {
    width: 16px;
    height: 16px;
    transition: transform .2s ease;
}

.dd-cs-live:hover svg {
    transform: translate(2px, -2px);
}

/* --- Fact strip ---------------------------------------------------------- */
.dd-cs-facts {
    display: grid;
    /* auto-fit rather than a fixed four, so a page can carry a fifth fact
       (context, research, whatever it needs) without the row breaking. */
    grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
    gap: 1px;
    margin: 0 0 40px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--border);
    overflow: hidden;
}

.dd-cs-fact {
    padding: 18px 20px;
    background: var(--surface-2);
}

.dd-cs-fact dt {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--muted);
}

.dd-cs-fact dd {
    margin: 7px 0 0;
    font-size: 14.5px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--text);
}

/* --- Two column body ----------------------------------------------------- */
.dd-cs-layout {
    display: grid;
    grid-template-columns: 212px minmax(0, 1fr);
    gap: 56px;
    align-items: start;
}

.dd-cs-toc {
    position: sticky;
    top: 28px;
    /* Own scroller so a long list can never outgrow the viewport. */
    max-height: calc(100vh - 56px);
    overflow-y: auto;
    padding-bottom: 8px;
}

/* The rail is a <details> so the same markup can be a permanent list beside the
   article on a desktop and a folded-away summary above it on a phone, where a
   fifteen-item list would otherwise push the article most of a screen down. */
.dd-cs-toc summary {
    margin: 0 0 14px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
    list-style: none;
    /* Not a control at this width - the list beside it is always open. */
    cursor: default;
}

.dd-cs-toc summary::-webkit-details-marker {
    display: none;
}

.dd-cs-toc summary .chev {
    display: none;
}

.dd-cs-toc ol {
    margin: 0;
    padding: 0;
    list-style: none;
    border-left: 1px solid var(--border);
}

/* Sub-steps of a section: indented, quieter, and no rail of their own. */
.dd-cs-toc ol ol {
    margin: 2px 0 4px;
    padding-left: 14px;
    border-left: 0;
}

.dd-cs-toc a {
    display: block;
    padding: 7px 0 7px 14px;
    margin-left: -1px;
    border-left: 2px solid transparent;
    font-size: 13.5px;
    line-height: 1.4;
    color: var(--muted);
    text-decoration: none;
    transition: color .2s ease, border-color .2s ease;
}

.dd-cs-toc ol ol a {
    padding-top: 5px;
    padding-bottom: 5px;
    font-size: 12.5px;
    opacity: .82;
}

.dd-cs-toc a:hover {
    color: var(--text);
}

.dd-cs-toc a.is-current {
    color: var(--accent-ink);
    border-left-color: var(--accent);
    font-weight: 600;
    opacity: 1;
}

/* --- Prose --------------------------------------------------------------- */
/* The column is as wide as the artwork needs; the running text inside it is
   held to a comfortable measure. That way a figure can break out to the full
   column simply by lifting its own cap, with no negative-margin trickery. */
.dd-prose {
    max-width: 980px;
    font-size: 16.5px;
    line-height: 1.75;
    color: var(--text-2);
}

.dd-prose p,
.dd-prose h2,
.dd-prose h3,
.dd-prose ul,
.dd-prose ol {
    max-width: 720px;
}

/* Panels are containers, not running text. They line up with the figures, the
   stat rows and the comparison table at the full column width — held to the
   reading measure they read as a narrower, unrelated column. */
.dd-prose .dd-legend,
.dd-prose .dd-pull,
.dd-prose .dd-note {
    max-width: 100%;
}

/* Jumping from the contents rail should land the heading a comfortable way
   down the viewport, not flush against the top edge under the progress bar. */
.dd-prose>section {
    scroll-margin-top: 80px;
}

.dd-prose h2 {
    margin: 64px 0 18px;
    font-size: clamp(22px, 2.6vw, 27px);
    line-height: 1.25;
    letter-spacing: -.02em;
    font-weight: 700;
    color: var(--text);
}

.dd-prose>section:first-child>h2:first-child {
    margin-top: 0;
}

.dd-prose h3 {
    margin: 38px 0 12px;
    font-size: 17.5px;
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--text);
}

.dd-prose p {
    margin: 0 0 18px;
}

.dd-prose strong {
    font-weight: 600;
    color: var(--text);
}

/* Inline links in running text only. The next-case-study card is an anchor too,
   but it is a card - it must not pick up the underline or the accent colour. */
.dd-prose a:not(.dd-cs-next) {
    color: var(--accent-ink);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
}

.dd-prose ul,
.dd-prose ol {
    margin: 0 0 20px;
    /* The global reset drops list-style for the nav/card lists; running prose
       needs its markers back. */
    padding-left: 24px;
}

.dd-prose ul {
    list-style: disc;
}

.dd-prose ol {
    list-style: decimal;
}

.dd-prose .dd-legend {
    list-style: none;
    padding-left: 0;
}

.dd-prose li {
    margin-bottom: 9px;
    padding-left: 4px;
}

.dd-prose li::marker {
    color: var(--muted);
}

/* --- Pull quote ---------------------------------------------------------- */
.dd-pull {
    margin: 32px 0;
    padding: 22px 26px;
    border: 0;
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius) var(--radius) 0;
    background: var(--accent-soft);
    font-size: 17.5px;
    line-height: 1.6;
    font-weight: 500;
    color: var(--text);
}

.dd-pull p {
    margin: 0 0 12px;
}

.dd-pull p:last-child {
    margin-bottom: 0;
}

.dd-pull cite {
    display: block;
    margin-top: 12px;
    font-size: 13.5px;
    font-style: normal;
    color: var(--muted);
}

/* --- Callout ------------------------------------------------------------- */
.dd-note {
    display: flex;
    gap: 14px;
    margin: 30px 0;
    padding: 18px 20px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
    font-size: 15px;
    line-height: 1.65;
    color: var(--text-2);
}

.dd-note svg {
    flex: none;
    width: 20px;
    height: 20px;
    margin-top: 2px;
    color: var(--muted);
}

.dd-note p {
    margin: 0 0 10px;
}

.dd-note p:last-child {
    margin-bottom: 0;
}

/* --- Stat row ------------------------------------------------------------ */
.dd-cs-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px;
    margin: 30px 0;
}

.dd-cs-stat {
    padding: 18px 18px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}

.dd-cs-stat b {
    display: block;
    font-size: 26px;
    font-weight: 800;
    letter-spacing: -.02em;
    line-height: 1.1;
    color: var(--text);
}

.dd-cs-stat span {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--muted);
}

/* --- Figures ------------------------------------------------------------- */
.dd-fig {
    margin: 30px 0;
    max-width: 720px;
}

.dd-fig-media {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-3);
    line-height: 0;
}

.dd-fig img,
.dd-fig video {
    display: block;
    width: 100%;
    height: auto;
}

.dd-fig figcaption {
    margin-top: 11px;
    font-size: 13px;
    line-height: 1.55;
    color: var(--muted);
    text-align: center;
}

/* A caption that points at something real to visit. Sits on the same line as
   the caption text and wraps with it, so it never orphans its own arrow.
   Selector is weighted past `.dd-prose a:not(.dd-cs-next)` on purpose —
   inheriting that rule's underline would double up with the border below. */
.dd-fig-link,
.dd-prose figcaption a.dd-fig-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 4px;
    white-space: nowrap;
    font-weight: 600;
    color: var(--accent-ink);
    text-decoration: none;
    border-bottom: 1px solid var(--accent-border);
    transition: border-color .2s ease, opacity .2s ease;
}

.dd-fig-link:hover {
    border-bottom-color: var(--accent);
}

.dd-fig-link svg {
    width: 13px;
    height: 13px;
    transition: transform .2s ease;
}

.dd-fig-link:hover svg {
    transform: translate(1.5px, -1.5px);
}

/* Artwork that wants more than the reading measure: it takes the full column. */
.dd-fig--wide {
    max-width: 100%;
}

/* --- Artboards ------------------------------------------------------------
   Some of the exports are drawn on transparency, so they inherit whatever is
   behind them - and their own ink then disappears in one of the two themes.
   These two give such artwork the ground it was drawn against, in both themes,
   plus room to breathe instead of running edge to edge. */
.dd-fig--plate .dd-fig-media,
.dd-fig--plate-dark .dd-fig-media {
    padding: clamp(16px, 2.6vw, 34px);
}

.dd-fig--plate .dd-fig-media {
    background: #f3f4f6;
    border-color: #e2e4e9;
}

.dd-fig--plate-dark .dd-fig-media {
    background: #16181c;
    border-color: #262a31;
}

/* Zoomable stills get a cursor and a gentle lift so it reads as clickable. */
.dd-fig--zoom .dd-fig-media {
    cursor: zoom-in;
    transition: transform .25s ease, box-shadow .25s ease;
}

.dd-fig--zoom:hover .dd-fig-media {
    transform: scale(var(--hover-scale));
    box-shadow: var(--shadow-md);
}

/* --- Gallery ------------------------------------------------------------- */
.dd-cs-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 14px;
    margin: 30px 0;
    align-items: start;
}

.dd-cs-gallery .dd-fig {
    margin: 0;
    max-width: none;
}

/* --- Journey strip ------------------------------------------------------- */
/* --- The journey strip, as a slider --------------------------------------
   Seven beats of one story. A grid asks you to read them as a wall; a track
   asks you to move through them, which is what they are. Built on scroll
   snapping rather than a carousel library: a touch screen and a trackpad then
   get their own momentum for free, and with the script gone it degrades to a
   strip you can still scroll.
   ------------------------------------------------------------------------- */
.dd-slider {
    --slider-gap: 18px;
    /* One step at a time. The storyboard frames are the argument being made
       here, so they get the whole column rather than a quarter of it - and the
       fraction is deliberate: the quarter of the next card showing past the
       edge is what says "this moves" without a word of copy. */
    --slider-per: 1.25;
    margin: 30px 0;
}

.dd-journey {
    display: flex;
    gap: var(--slider-gap, 16px);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    /* The track is its own scroller; a bar under it would cut the strip in two. */
    scrollbar-width: none;
    -ms-overflow-style: none;
    cursor: grab;
}

.dd-journey::-webkit-scrollbar {
    display: none;
}

.dd-journey:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 5px;
    border-radius: var(--radius);
}

/* Mid-drag the snap points have to let go, or every pixel of movement fights
   to land on one; releasing puts them back and the track settles. */
.dd-journey.is-dragging {
    scroll-snap-type: none;
    scroll-behavior: auto;
    cursor: grabbing;
}

.dd-journey.is-dragging img {
    /* Otherwise the browser's own image drag starts and steals the pointer. */
    pointer-events: none;
}

.dd-journey-step {
    display: flex;
    flex-direction: column;
    flex: 0 0 calc((100% - (var(--slider-per) - 1) * var(--slider-gap)) / var(--slider-per));
    scroll-snap-align: start;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
    overflow: hidden;
}

.dd-slider-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin-top: 18px;
}

/* Nothing to page through means nothing to press. */
.dd-slider.is-static .dd-slider-controls {
    display: none;
}

.dd-slider-btn {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--surface-2);
    color: var(--text-2);
    cursor: pointer;
    transition: border-color .18s ease, color .18s ease, background-color .18s ease, opacity .18s ease;
}

.dd-slider-btn:hover:not(:disabled) {
    border-color: var(--accent);
    color: var(--accent-ink);
    background: var(--accent-soft);
}

.dd-slider-btn:disabled {
    opacity: .3;
    cursor: default;
}

.dd-slider-btn svg {
    width: 17px;
    height: 17px;
}

.dd-slider-dots {
    display: flex;
    align-items: center;
    gap: 7px;
}

.dd-slider-dot {
    width: 7px;
    height: 7px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
    cursor: pointer;
    transition: width .22s ease, background-color .22s ease;
}

.dd-slider-dot:hover {
    background: var(--muted);
}

.dd-slider-dot.is-active {
    width: 22px;
    background: var(--accent);
}

/* The storyboard frames arrive at slightly different ratios. A fixed box with
   `contain` evens the strip out without cropping anyone out of their own
   panel. */
.dd-journey-step img {
    display: block;
    width: 100%;
    /* The frames arrive at slightly different ratios; 16/10 is the one most of
       them are already at, so the fewest of them get bars down the side. */
    aspect-ratio: 16 / 10;
    object-fit: contain;
    background: var(--surface-3);
    cursor: zoom-in;
}

.dd-journey-step p {
    margin: 0;
    /* The card is now as wide as the column, but a line of text is not allowed
       to be - past about 65 characters the eye loses the return sweep. */
    max-width: 62ch;
    padding: 15px 18px 18px;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--text-2);
}

.dd-journey-step b {
    display: block;
    margin-bottom: 4px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
}

/* --- Feature / takeaway cards -------------------------------------------- */
.dd-cs-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 14px;
    margin: 28px 0;
}

.dd-cs-mini {
    padding: 18px 20px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
}

.dd-cs-mini h4 {
    margin: 0 0 7px;
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
}

.dd-cs-mini p {
    margin: 0;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-2);
}

.dd-cs-mini .num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin-bottom: 10px;
    border-radius: 50%;
    background: var(--accent-soft);
    border: 1px solid var(--accent-border);
    font-size: 12px;
    font-weight: 700;
    color: var(--accent-ink);
}

/* --- Status legend (Jetlog sync states) ----------------------------------
   Three of the five states are green in the product, so a plain colour dot
   told the reader nothing - the rows read as duplicates. Each row carries the
   actual glyph instead, tinted with that state's colour via --state. */
.dd-legend {
    margin: 26px 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.dd-legend li {
    display: flex;
    align-items: center;
    gap: 15px;
    margin: 0;
    padding: 15px 20px;
    background: var(--surface-2);
    border-top: 1px solid var(--border);
    font-size: 14.5px;
    line-height: 1.55;
}

.dd-legend li:first-child {
    border-top: 0;
}

.dd-legend .state {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 11px;
    color: var(--state, var(--accent));
    background: color-mix(in srgb, var(--state, var(--accent)) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--state, var(--accent)) 34%, transparent);
}

.dd-legend .state svg {
    width: 21px;
    height: 21px;
}

.dd-legend b {
    display: block;
    color: var(--text);
    font-weight: 600;
}

.dd-legend .state-note {
    display: block;
    color: var(--text-2);
}

/* --- Section divider ----------------------------------------------------- */
.dd-cs-rule {
    height: 1px;
    margin: 56px 0;
    border: 0;
    background: var(--border);
}

/* --- Next case study ----------------------------------------------------- */
/* Same construction as .dd-card, and for the same reason - the swell belongs
   to the pane, not to the two lines of type sitting on it. */
.dd-cs-next {
    position: relative;
    isolation: isolate;
    display: block;
    margin: 64px 0 0;
    padding: 27px 29px;
    border-radius: var(--radius-lg);
    text-decoration: none;
}

.dd-cs-next::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border: 1px solid var(--border);
    border-radius: inherit;
    background: var(--surface-2);
    transition: transform .24s cubic-bezier(.2, .9, .3, 1), border-color .2s ease, box-shadow .2s ease;
}

.dd-cs-next:hover::before {
    border-color: var(--border-strong);
    transform: scale(var(--hover-scale));
    box-shadow: var(--shadow-md);
}

.dd-cs-next span {
    display: block;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
}

.dd-cs-next strong {
    display: block;
    margin-top: 9px;
    font-size: 19px;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -.015em;
    color: var(--text);
}

/* --- Floating theme toggle (no sidebar on these pages) ------------------- */
.dd-cs-toggle {
    position: fixed;
    top: 18px;
    right: 18px;
    z-index: 60;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    /* A visible edge and a real surface. The glass fill alone all but vanished
       against a dark page - a control you cannot find is not a control. */
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--glass-bg-strong);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(150%);
    backdrop-filter: blur(var(--glass-blur)) saturate(150%);
    box-shadow: var(--shadow-sm);
    color: var(--text-2);
    cursor: pointer;
    transition: color .2s ease, border-color .2s ease, transform .3s cubic-bezier(.2, 1.4, .4, 1);
}

.dd-cs-toggle:hover {
    color: var(--text);
    border-color: var(--border-strong);
    transform: scale(1.08);
}

.dd-cs-toggle:active {
    transform: scale(.92);
    transition-duration: .1s;
}

.dd-cs-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* The shared .dd-theme-icon is absolutely positioned and expects the home
   page's script to pull it back by half its size. These pages do not load that
   script, so the glyph used to hang down and to the right of its own button.
   Here the flexbox centres it and no script is involved. */
.dd-cs-toggle .dd-theme-icon {
    position: static;
    width: 20px;
    height: 20px;
    transform: none;
    opacity: 1;
    visibility: visible;
}

/* One icon at a time - matches the sidebar toggle on the home page. */
.dd-cs-toggle .dd-icon-moon {
    display: none;
}

[data-theme="dark"] .dd-cs-toggle .dd-icon-sun {
    display: none;
}

[data-theme="dark"] .dd-cs-toggle .dd-icon-moon {
    display: inline;
}

/* --- Reading progress bar ------------------------------------------------ */
.dd-cs-progress {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 70;
    height: 2px;
    width: 100%;
    transform: scaleX(0);
    transform-origin: 0 50%;
    background: var(--accent);
    pointer-events: none;
}

/* --- Image lightbox ------------------------------------------------------ */
.dd-imgbox {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 32px;
    background: rgba(6, 7, 9, .88);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    cursor: zoom-out;
    opacity: 0;
    transition: opacity .22s ease;
}

.dd-imgbox.is-open {
    display: flex;
    opacity: 1;
}

/* A percentage max-height would resolve against the figure's auto height and be
   dropped, which let tall artwork run off the top and bottom of the screen. The
   viewport is the thing that is actually known, so it is what the picture is
   measured against - the subtracted strip is the padding plus the caption. */
.dd-imgbox img {
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: calc(100vh - 150px);
    border-radius: var(--radius-sm);
    object-fit: contain;
}

/* Artwork drawn on transparency keeps the ground it was drawn against when it
   is enlarged too - otherwise the backdrop swallows exactly the picture the
   reader just asked for a closer look at. The class is copied off the figure. */
.dd-imgbox figure.is-plate img {
    padding: clamp(14px, 2vw, 28px);
    background: #f3f4f6;
}

.dd-imgbox figure.is-plate-dark img {
    padding: clamp(14px, 2vw, 28px);
    background: #16181c;
}

/* --- Responsive ---------------------------------------------------------- */
@media (max-width: 1080px) {
    .dd-cs-layout {
        gap: 40px;
    }
}

@media (max-width: 960px) {
    .dd-cs-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
    }

    /* The rail becomes a fold-away summary above the article, closed by default
       so the reader starts on the writing rather than on a table of contents. */
    .dd-cs-toc {
        position: static;
        max-height: none;
        overflow: visible;
        margin-bottom: 34px;
        padding: 4px 18px;
        border: 1px solid var(--border);
        border-radius: var(--radius);
        background: var(--surface-2);
    }

    .dd-cs-toc summary {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        margin: 0;
        padding: 15px 0;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }

    .dd-cs-toc summary .chev {
        display: block;
        width: 16px;
        height: 16px;
        color: var(--muted);
        transition: transform .2s ease;
    }

    .dd-cs-toc details[open] summary .chev {
        transform: rotate(180deg);
    }

    .dd-cs-toc details[open] summary {
        border-bottom: 1px solid var(--border);
    }

    .dd-cs-toc ol {
        padding: 6px 0 12px;
        border-left: 0;
    }

    .dd-cs-toc a {
        padding-left: 0;
        border-left: 0;
    }

    .dd-cs-toc ol ol {
        padding-left: 16px;
    }

    .dd-cs-toc a.is-current {
        border-left: 0;
    }

    .dd-prose,
    .dd-prose p,
    .dd-prose h2,
    .dd-prose h3,
    .dd-prose ul,
    .dd-prose ol,
    .dd-prose .dd-pull,
    .dd-prose .dd-note,
    .dd-prose .dd-legend,
    .dd-fig {
        max-width: none;
    }

    .dd-cs-facts {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 760px) {
    .dd-cs-shell {
        padding: 0 16px;
    }

    .dd-prose {
        font-size: 16px;
    }

    .dd-imgbox {
        padding: 16px;
    }
}

@media (max-width: 480px) {
    .dd-cs-facts {
        grid-template-columns: minmax(0, 1fr);
    }

    .dd-cs-gallery {
        grid-template-columns: minmax(0, 1fr);
    }
}


/* ==========================================================================
   17. CASE STUDY - COMPARISON TABLE
   A before/after read of the same job, side by side. Wide content scrolls
   inside its own box so the page body never scrolls sideways.
   ========================================================================== */
.dd-table-wrap {
    margin: 28px 0;
    overflow-x: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-2);
    -webkit-overflow-scrolling: touch;
}

.dd-table {
    width: 100%;
    min-width: 620px;
    border-collapse: collapse;
    font-size: 14.5px;
    line-height: 1.55;
}

.dd-table th,
.dd-table td {
    padding: 13px 18px;
    text-align: left;
    vertical-align: top;
    border-top: 1px solid var(--border);
}

.dd-table thead th {
    border-top: 0;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--muted);
    white-space: nowrap;
}

.dd-table tbody th {
    font-weight: 600;
    color: var(--text);
    width: 28%;
}

.dd-table td {
    color: var(--text-2);
}

/* The "after" column is the point of the table, so it is the one that is lit. */
.dd-table .is-after {
    color: var(--text);
    background: var(--accent-soft);
}

.dd-table thead .is-after {
    color: var(--accent-ink);
}


/* ==========================================================================
   18. CASE STUDY - FIGURE, LIGHTBOX & VIDEO AFFORDANCES
   ========================================================================== */
/* Zoomable stills are reachable from the keyboard, so they need a focus ring
   and a hint that says what the click does. */
.dd-fig--zoom .dd-fig-media:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

.dd-fig--zoom .dd-fig-media::after {
    content: "";
    position: absolute;
    inset: auto 10px 10px auto;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: rgba(12, 14, 18, .62) center / 15px 15px no-repeat
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0'/%3E%3Cpath d='M21 21l-6 -6'/%3E%3Cpath d='M7 10h6'/%3E%3Cpath d='M10 7v6'/%3E%3C/svg%3E");
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    opacity: 0;
    transform: scale(.85);
    transition: opacity .2s ease, transform .2s ease;
    pointer-events: none;
}

.dd-fig--zoom:hover .dd-fig-media::after,
.dd-fig--zoom .dd-fig-media:focus-visible::after {
    opacity: 1;
    transform: none;
}

@media (hover: none) {

    /* No hover to reveal it on a touch screen - leave it showing. */
    .dd-fig--zoom .dd-fig-media::after {
        opacity: .9;
        transform: none;
    }
}

/* A clip that could not autoplay (low power mode, a blocked play promise) gets
   its native controls back rather than sitting there as a dead poster frame. */
.dd-fig video[controls] {
    background: #000;
}

/* --- Lightbox: figure, caption and an explicit way out ------------------- */
.dd-imgbox figure {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    max-width: 100%;
    max-height: 100%;
    margin: 0;
    cursor: default;
}

.dd-imgbox figcaption {
    max-width: 62ch;
    font-size: 13px;
    line-height: 1.55;
    text-align: center;
    color: rgba(255, 255, 255, .74);
}

.dd-imgbox figcaption:empty {
    display: none;
}

.dd-imgbox-close {
    position: fixed;
    top: 18px;
    right: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 50%;
    background: rgba(255, 255, 255, .1);
    color: #fff;
    cursor: pointer;
    transition: background .2s ease, transform .2s ease;
}

.dd-imgbox-close:hover {
    background: rgba(255, 255, 255, .2);
    transform: scale(1.06);
}

.dd-imgbox-close:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 3px;
}

.dd-imgbox-close svg {
    width: 20px;
    height: 20px;
}


/* ==========================================================================
   19. PAGE-TO-PAGE TRANSITION
   Same-origin navigations cross-fade and lift instead of blinking. Only the
   browsers that support cross-document view transitions take part; everyone
   else simply navigates. Held behind a motion query - this is decoration.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
    @view-transition {
        navigation: auto;
    }
}

/* :not(.dd-switching) keeps this clear of the theme toggle, which drives the
   very same pseudo-elements with a circular wipe of its own. */
html:not(.dd-switching)::view-transition-old(root) {
    animation: dd-page-out .19s cubic-bezier(.4, 0, 1, 1) both;
}

html:not(.dd-switching)::view-transition-new(root) {
    animation: dd-page-in .34s cubic-bezier(.16, .84, .44, 1) both;
}

@keyframes dd-page-out {
    to {
        opacity: 0;
    }
}

@keyframes dd-page-in {
    from {
        opacity: 0;
        transform: translateY(12px);
    }
}


/* ==========================================================================
   20. THE CURTAIN - single-URL page transitions

   The site is browsed from one address, so a navigation has no address bar
   change to announce it. This does the announcing: the site's own lockup with
   the destination's name - works. about. jetlog. - drawn on, held while the
   next page is put in place, then opened through the full stop.
   ========================================================================== */
@property --dd-hole-r {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
}

.dd-curtain {
    position: fixed;
    inset: 0;
    /* 100vw takes in the reserved scrollbar gutter; inset alone stops short of
       it and leaves a bare strip down the edge. */
    width: 100vw;
    /* Over the dock, the lightbox and the intro alike - nothing may show
       through the curtain except the hole it opens itself. */
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .26s ease, visibility .26s;
}

.dd-curtain.is-shown {
    opacity: 1;
    visibility: visible;
    /* Nothing underneath is clickable while it is up. */
    pointer-events: auto;
}

/* On the way home the curtain carries no word: the page behind it signs itself
   in, and the curtain is only the flat cover that starts up in front of it. */
.dd-curtain.is-blank .dd-curtain-stage {
    display: none;
}

/* Same measure as the intro lockup, so the two read as one family. */
.dd-curtain-stage {
    position: relative;
    display: flex;
    /* Not baseline: the word sits in its own clipping box, and a box that
       clips reports its bottom edge as its baseline - which dropped the full
       stop to the foot of the descenders instead of onto the writing line. */
    align-items: flex-end;
    gap: .06em;
    font-size: clamp(38px, 9vw, 92px);
    font-weight: 800;
    letter-spacing: -.045em;
    line-height: 1;
    color: var(--text);
}

/* The word rises into place rather than fading on. The box it rises inside
   carries room for the descenders of a j or a g, so the clip hides the word
   before it arrives without slicing the tails off once it has. */
.dd-curtain-word {
    display: block;
    overflow: hidden;
    padding-bottom: .26em;
}

.dd-curtain-word i {
    display: block;
    font-style: normal;
    /* Past the padded floor, so nothing peeks below the clip at rest. */
    transform: translateY(130%);
}

/* Where the destination has its word drawn as artwork, the same box carries
   the file instead of the type. It is painted as a mask rather than dropped in
   as an image, so a single flat SVG takes the page's own ink and stays legible
   in both themes. Height is tied to the lockup's font-size and the width comes
   from the file's own proportions, so artwork and type land at one size. */
.dd-curtain.has-art .dd-curtain-word i {
    width: calc(.74em * var(--dd-art-ratio, 4));
    height: .74em;
    background-color: var(--text);
    -webkit-mask-image: var(--dd-art);
    mask-image: var(--dd-art);
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.dd-curtain.is-writing .dd-curtain-word i {
    transform: none;
    transition: transform .52s cubic-bezier(.16, .84, .44, 1) .06s;
}

/* The full stop lands last and is the thing the opening flies out of. It is
   lifted by exactly the descender room above, which puts it on the writing
   line the word is sitting on. */
.dd-curtain-dot {
    width: .15em;
    height: .15em;
    margin-bottom: .26em;
    border-radius: 50%;
    background: var(--accent-ink);
    transform: scale(0);
}

.dd-curtain.is-writing .dd-curtain-dot {
    transform: scale(1);
    transition: transform .42s cubic-bezier(.2, 1.5, .4, 1) .46s;
}

/* The opening is a hole masked into the whole layer - backdrop and lettering
   together - so the page arrives through the curtain rather than under it.
   Browsers without a registered custom property cannot animate the radius;
   they get the cross-fade below on its own, which is the same beat. */
.dd-curtain.is-open {
    --dd-hole-r: 0px;
    opacity: 0;
    transition: --dd-hole-r .72s cubic-bezier(.65, 0, .35, 1), opacity .34s ease .42s;
    -webkit-mask-image: radial-gradient(circle at var(--dd-hole-x, 50%) var(--dd-hole-y, 50%),
            rgba(0, 0, 0, 0) var(--dd-hole-r), #000 calc(var(--dd-hole-r) + 1.5px));
    mask-image: radial-gradient(circle at var(--dd-hole-x, 50%) var(--dd-hole-y, 50%),
            rgba(0, 0, 0, 0) var(--dd-hole-r), #000 calc(var(--dd-hole-r) + 1.5px));
}

@media (prefers-reduced-motion: reduce) {
    .dd-curtain {
        transition: none;
    }

    .dd-curtain-word i,
    .dd-curtain-dot {
        transform: none;
        transition: none;
    }
}


/* ==========================================================================
   21. LIQUID GLASS - PILLS

   Section 13e turns the raised panels into glass. This carries the same
   material onto every pill-shaped control, including the ones on the case
   study pages, which were still flat surfaces sitting on a glass site: the
   translucent fill, the bright rim catching light along the top-left edge and
   the softer return along the bottom-right, and the spring under the pointer.

   It sits last on purpose. .dd-cs-back and friends declare their own opaque
   background further up, and specificity alone would not beat them.

   No refraction pass here. The warp filter and the class that gates it live on
   the home page only, and a pill that referenced a filter which is not in the
   document would come out blank rather than warped.
   ========================================================================== */
.dd-btn:not(.dd-btn--primary),
.dd-cs-back,
.dd-cs-live,
.dd-cs-toggle {
    --glass-blur: 14px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.8);
    backdrop-filter: blur(var(--glass-blur)) saturate(1.8);
    box-shadow:
        inset 1px 1px 1px -.5px var(--glass-highlight),
        inset -1px -1px 1px -.5px var(--glass-highlight),
        inset 0 0 8px -2px var(--glass-highlight),
        0 0 0 1px var(--glass-edge),
        var(--glass-shadow);
    transition:
        transform .42s cubic-bezier(.2, 1.5, .4, 1),
        box-shadow .32s cubic-bezier(.2, .9, .3, 1),
        background-color .2s ease,
        border-color .2s ease,
        color .2s ease;
}

.dd-btn:not(.dd-btn--primary):hover,
.dd-cs-back:hover,
.dd-cs-toggle:hover {
    background: var(--glass-bg-strong);
    border-color: var(--glass-border);
    box-shadow:
        inset 1px 1px 2px -.5px var(--glass-highlight),
        inset -1px -1px 2px -.5px var(--glass-highlight),
        inset 0 0 16px -3px var(--glass-highlight),
        0 0 0 1px var(--glass-edge),
        var(--glass-shadow-lg);
}

/* Round or oblong, everything swells in place now. */
.dd-cs-toggle:hover {
    transform: scale(1.06);
}

.dd-btn:not(.dd-btn--primary):hover,
.dd-cs-back:hover {
    transform: scale(var(--hover-scale-sm));
}

.dd-btn:not(.dd-btn--primary):active,
.dd-cs-back:active,
.dd-cs-toggle:active {
    transform: scale(.96);
    transition-duration: .1s;
}

/* The showcase link is glass too, but tinted - it is still the accent CTA, so
   the wash rides on top of the pane rather than replacing it. */
.dd-cs-live {
    background:
        linear-gradient(var(--accent-soft), var(--accent-soft)),
        var(--glass-bg);
    border-color: var(--accent-border);
}

/* Pressed into a solid: glass over a saturated fill only muddies it, which is
   the rule the accent buttons in 13e already follow. */
.dd-cs-live:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    transform: scale(var(--hover-scale-sm));
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22), var(--glass-shadow-lg);
}

@media (prefers-reduced-motion: reduce) {

    .dd-btn,
    .dd-cs-back,
    .dd-cs-live,
    .dd-cs-toggle {
        transition: background-color .2s ease, border-color .2s ease, color .2s ease;
    }

    .dd-btn:hover,
    .dd-cs-back:hover,
    .dd-cs-live:hover,
    .dd-cs-toggle:hover,
    .dd-btn:active,
    .dd-cs-back:active,
    .dd-cs-toggle:active {
        transform: none;
    }
}


/* =========================================================================
   HEAD BALL 2 CASE STUDY (work/headball2.html)
   Page components: audio player, deck slider, popup preview, hover-swap.
   Lives here rather than in the page head because the shell (app.js) swaps
   only the body and meta - a head <style> would be lost on navigation.
   ========================================================================= */
/* ============== Page-scoped: audio player ============== */
.hb2-player {
    display: flex;
    align-items: center;
    gap: 28px;
    padding: 22px 26px;
    margin: 28px 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.hb2-disc {
    position: relative;
    flex: 0 0 auto;
    width: 132px;
    height: 132px;
}

.hb2-disc img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-md);
    opacity: 0;
    transition: opacity .35s ease;
    animation: hb2-spin 9s linear infinite;
    animation-play-state: paused;
}

.hb2-disc img.is-active {
    opacity: 1;
}

.hb2-player.is-playing .hb2-disc img.is-active {
    animation-play-state: running;
}

/* The spindle hole that makes it read as a disc. */
.hb2-disc::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 22px;
    height: 22px;
    transform: translate(-50%, -50%);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 50%;
    z-index: 1;
}

@keyframes hb2-spin {
    to {
        transform: rotate(360deg);
    }
}

.hb2-main {
    flex: 1 1 auto;
    min-width: 0;
}

.hb2-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    margin-bottom: 12px;
}

.hb2-track-name {
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--text);
}

.hb2-track-album {
    font-size: .82rem;
    color: var(--muted);
}

.hb2-seek {
    position: relative;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--surface-3);
    border: 1px solid var(--border);
    cursor: pointer;
    touch-action: none;
}

.hb2-seek:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.hb2-seek-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0%;
    border-radius: inherit;
    background: var(--accent);
    transition: width .12s linear;
}

.hb2-times {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    font-size: .78rem;
    font-variant-numeric: tabular-nums;
    color: var(--muted);
}

.hb2-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin-top: 10px;
}

.hb2-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-2);
    cursor: pointer;
    transition: background .18s ease, color .18s ease, border-color .18s ease;
}

.hb2-btn:hover {
    border-color: var(--accent-border);
    color: var(--text);
    background: var(--accent-soft);
}

.hb2-btn:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.hb2-btn svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

.hb2-btn--play {
    width: 54px;
    height: 54px;
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.hb2-btn--play:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: var(--on-accent);
}

.hb2-btn--play svg {
    width: 22px;
    height: 22px;
}

.hb2-player .icon-pause,
.hb2-player.is-playing .icon-play {
    display: none;
}

.hb2-player.is-playing .icon-pause {
    display: block;
}

@media (max-width: 560px) {
    .hb2-player {
        flex-direction: column;
        text-align: center;
    }

    .hb2-meta {
        justify-content: center;
    }
}

@media (prefers-reduced-motion: reduce) {
    .hb2-player.is-playing .hb2-disc img.is-active {
        animation-play-state: paused;
    }
}

/* A figure media that is a link rather than a div: anchors are inline
   by default and would collapse around the image. */
a.dd-fig-media {
    display: block;
}

/* ============== Page-scoped: slide deck viewer ============== */
.hb2-deck {
    margin: 24px 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}

.hb2-deck-stage {
    /* The deck exports at 2750x1550. */
    aspect-ratio: 1600 / 902;
    background: var(--surface-2);
    cursor: pointer;
    touch-action: pan-y;
    user-select: none;
    -webkit-user-select: none;
}

.hb2-deck-stage:focus-visible {
    outline: none;
    box-shadow: inset var(--ring);
}

.hb2-deck-stage img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    transition: opacity .18s ease;
}

.hb2-deck-stage img.is-loading {
    opacity: .35;
}

.hb2-deck-bar {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
}

/* The deck chevrons are stroke icons - the player's fill rule would
   paint their outlines into solid wedges. */
.hb2-deck-bar .hb2-btn svg {
    fill: none;
    width: 20px;
    height: 20px;
}

.hb2-deck-count {
    flex: 0 0 auto;
    min-width: 64px;
    text-align: center;
    font-size: .82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-2);
}

.hb2-deck-range {
    flex: 1;
    min-width: 0;
    height: 8px;
    margin: 0;
    appearance: none;
    -webkit-appearance: none;
    border-radius: var(--radius-pill);
    background: var(--surface-3);
    border: 1px solid var(--border);
    cursor: pointer;
}

.hb2-deck-range:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.hb2-deck-range::-webkit-slider-thumb {
    appearance: none;
    -webkit-appearance: none;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--surface);
    box-shadow: var(--shadow-sm);
    cursor: grab;
}

.hb2-deck-range::-moz-range-thumb {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--surface);
    box-shadow: var(--shadow-sm);
    cursor: grab;
}

@media (max-width: 560px) {
    .hb2-deck-bar {
        gap: 10px;
        padding: 10px 12px;
    }
}

/* ============== Page-scoped: browser popup preview ============== */
.hb2-popup {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(8, 9, 11, .72);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}

.hb2-popup.is-open {
    display: flex;
}

.hb2-popup-panel {
    display: flex;
    flex-direction: column;
    width: min(960px, 100%);
    max-height: 90vh;
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.hb2-popup-head {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
}

.hb2-popup-title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    font-size: .92rem;
    color: var(--text);
}

.hb2-popup-newtab {
    flex: 0 0 auto;
    font-size: .8rem;
    font-weight: 600;
    color: var(--accent-ink);
    text-decoration: none;
}

.hb2-popup-newtab:hover {
    text-decoration: underline;
}

.hb2-popup-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-2);
    cursor: pointer;
}

.hb2-popup-close:hover {
    border-color: var(--accent-border);
    color: var(--text);
}

.hb2-popup-close svg {
    width: 16px;
    height: 16px;
}

.hb2-popup-body {
    position: relative;
    flex: 1;
    min-height: 0;
}

/* Video previews keep the frame's shape; documents get reading height. */
.hb2-popup--video .hb2-popup-body {
    aspect-ratio: 16 / 9;
}

.hb2-popup--tall .hb2-popup-body {
    height: min(72vh, 760px);
}

/* A4 portrait: the panel width is derived from the available height so
   the document area keeps true 210x297 page proportions. */
.hb2-popup--page .hb2-popup-panel {
    width: min(640px, calc((92vh - 58px) * 0.7071), 100%);
}

.hb2-popup--page .hb2-popup-body {
    aspect-ratio: 210 / 297;
}

/* Portrait document: sized to the Google Forms column, using all the
   height the viewport gives. */
.hb2-popup--doc .hb2-popup-panel {
    width: min(680px, 100%);
}

.hb2-popup--doc .hb2-popup-body {
    height: min(82vh, 940px);
}

.hb2-popup-body iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    background: var(--surface-2);
}

/* Image previews scroll like a document inside the same body. */
.hb2-popup-imgwrap {
    position: absolute;
    inset: 0;
    overflow-y: auto;
    background: var(--surface-2);
}

.hb2-popup-imgwrap img {
    display: block;
    width: 100%;
    height: auto;
}

/* ============== Page-scoped: hover-swap process diagram ============== */
.hb2-swap {
    position: relative;
    display: block;
}

.hb2-swap img {
    display: block;
    width: 100%;
    height: auto;
}

.hb2-swap .top {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity .35s ease;
}

.hb2-swap:hover .top,
.hb2-swap:focus-within .top {
    opacity: 1;
}

/* =========================================================================
   CONTACT PAGE (contact.html)
   Split card: reach-me-directly rail on the left, project form on the right.
   Lives here rather than in the page head because the shell (app.js) swaps
   only the body and meta - a head <style> would be lost on navigation.
   ========================================================================= */
.dd-ct-shell {
    max-width: var(--shell);
    margin: 0 auto;
    padding: 96px 24px 40px;
}

.dd-ct-card {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}

.dd-ct-left {
    display: flex;
    flex-direction: column;
    gap: 22px;
    padding: 48px 40px;
    background: var(--bg-soft);
    border-right: 1px solid var(--border);
}

.dd-ct-left h1 {
    margin: 0;
    font-size: clamp(2rem, 4.2vw, 3rem);
    font-weight: 800;
    line-height: 1.12;
    letter-spacing: -0.02em;
    color: var(--text);
}

.dd-ct-left h1 em {
    font-style: normal;
    color: var(--accent-ink);
}

.dd-ct-lede {
    margin: 0;
    color: var(--text-2);
    line-height: 1.65;
}

.dd-ct-email {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.dd-ct-email-meta {
    flex: 1;
    min-width: 0;
}

.dd-ct-email-meta small {
    display: block;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 4px;
}

.dd-ct-email-meta b {
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--text);
    word-break: break-all;
}

.dd-ct-copy {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    flex: 0 0 auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    background: var(--surface-2);
    color: var(--text-2);
    cursor: pointer;
}

.dd-ct-copy:hover {
    border-color: var(--accent-border);
    color: var(--text);
}

.dd-ct-copy svg {
    width: 16px;
    height: 16px;
}

.dd-ct-copy.is-copied {
    color: var(--positive);
    border-color: var(--positive);
}

.dd-ct-action {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 14px 20px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
    transition: border-color .18s ease, background .18s ease;
}

.dd-ct-action:hover {
    border-color: var(--accent-border);
    background: var(--accent-soft);
}

.dd-ct-action svg {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
}

.dd-ct-mailbtn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    padding: 10px 18px;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: var(--on-accent);
    font-size: .88rem;
    font-weight: 700;
    text-decoration: none;
    transition: background .18s ease;
}

.dd-ct-mailbtn:hover {
    background: var(--accent-hover);
}

.dd-ct-mailbtn svg {
    width: 16px;
    height: 16px;
}

.dd-ct-note {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    padding-top: 20px;
    border-top: 1px solid var(--border);
    font-size: .88rem;
    color: var(--muted);
}

.dd-ct-note .dot {
    width: 8px;
    height: 8px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--positive);
}

.dd-ct-note b {
    color: var(--text-2);
}

.dd-ct-right {
    padding: 48px 44px;
}

.dd-ct-right h2 {
    margin: 0 0 6px;
    font-size: clamp(1.4rem, 2.6vw, 1.9rem);
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--text);
}

.dd-ct-right>p {
    margin: 0 0 26px;
    color: var(--muted);
}

.dd-ct-form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
}

.dd-ct-field {
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.dd-ct-field--full {
    grid-column: 1 / -1;
}

.dd-ct-field label {
    font-size: .86rem;
    font-weight: 600;
    color: var(--text);
}

.dd-ct-field label .req {
    color: #e5484d;
}

.dd-ct-field input,
.dd-ct-field select,
.dd-ct-field textarea {
    width: 100%;
    padding: 12px 14px;
    font: inherit;
    font-size: .94rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    transition: border-color .15s ease, box-shadow .15s ease;
}

.dd-ct-field input::placeholder,
.dd-ct-field textarea::placeholder {
    color: var(--muted);
}

.dd-ct-field input:focus-visible,
.dd-ct-field select:focus-visible,
.dd-ct-field textarea:focus-visible {
    outline: none;
    border-color: var(--accent-border);
    box-shadow: var(--ring);
}

.dd-ct-field select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2374787f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 16px;
    padding-right: 42px;
}

.dd-ct-field textarea {
    min-height: 150px;
    resize: vertical;
}

.dd-ct-submit {
    grid-column: 1 / -1;
    padding: 15px 24px;
    border: 0;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--on-accent);
    font: inherit;
    font-size: .92rem;
    font-weight: 800;
    letter-spacing: .08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background .18s ease;
}

.dd-ct-submit:hover {
    background: var(--accent-hover);
}

.dd-ct-submit:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.dd-ct-fine {
    grid-column: 1 / -1;
    margin: 0;
    font-size: .8rem;
    line-height: 1.55;
    color: var(--muted);
}

@media (max-width: 860px) {
    .dd-ct-shell {
        padding-top: 84px;
    }

    .dd-ct-card {
        grid-template-columns: 1fr;
    }

    .dd-ct-left {
        border-right: 0;
        border-bottom: 1px solid var(--border);
        padding: 36px 24px;
    }

    .dd-ct-right {
        padding: 36px 24px;
    }

    .dd-ct-form {
        grid-template-columns: 1fr;
    }
}
