/* ==========================================================================
   Matilda Andersson Carlsten — portfolio
   Theme: dark burgundy, per portfolio-theme-spec.md.
   Four colour roles — burgundy is the environment, dusty rose is interaction,
   beige is text, blue is metadata.
   Typography is the site's own: Bricolage Grotesque display headings, a
   Newsreader body, DM Mono for labels. The spec's serif-heading/sans-body
   arrangement and its 400–500 weight rule are deliberately not applied.
   Mobile-first; breakpoints go up from here.
   ========================================================================== */

:root {
    /* Burgundy — page and surfaces */
    --page:            #3A1020;
    --surface-card:    #4E1929;
    --surface-warm:    #571A2B;
    --page-deep:       #2A0B17;

    /* Dusty rose — all interaction */
    --action-fill:     #C76E7F;
    --action-hover:    #B76573;  /* --action-fill darkened ~8% */
    --action-text:     #E39BA8;
    --on-action:       #2E0C18;

    /* Beige — all copy */
    --text-heading:    #F0E8D8;
    --text-body:       #C4B7A0;
    --beige-fill:      #DCD2BC;

    /* Blue — metadata only */
    --meta:            #7FBDE8;  /* on burgundy */
    --meta-base:       #54A4E0;  /* on light surfaces only */
    /* The spec's --meta-base is only ~1.8:1 on --beige-fill, so the beige band
       gets a darkened blue that keeps the metadata role and clears AA. */
    --meta-dark:       #1A5382;

    /* Light section (the contact band) */
    --light-heading:   #58182A;
    --light-body:      #6B5320;

    /* Borders — translucent beige, never solid grey */
    --hairline:        rgba(232, 222, 203, 0.14);
    --border-card:     rgba(232, 222, 203, 0.18);
    --border-strong:   rgba(232, 222, 203, 0.40);
    --border-action:   rgba(227, 155, 168, 0.50);

    /* Translucent tint for category badges */
    --tint-rose:       rgba(199, 110, 127, 0.28);

    /* Radii */
    --r-control:       8px;
    --r-card:          12px;
    --r-pill:          999px;

    --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
    --ease-spring: cubic-bezier(0.34, 1.45, 0.64, 1);
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

* {
    margin: 0;
    padding: 0;
}

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: 'Newsreader', Georgia, 'Times New Roman', serif;
    font-weight: 300;
    font-size: 1.0625rem;
    line-height: 1.65;
    color: var(--text-body);
    background: var(--page);
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
}

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

.container {
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 1.25rem;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--action-fill);
    color: var(--on-action);
    padding: 0.75rem 1.25rem;
    border-radius: 0 0 var(--r-control) 0;
    z-index: 100;
    text-decoration: none;
}

.skip-link:focus {
    left: 0;
}

/* Keeps the full name in the page text and the accessible name while only
   "Matilda" is drawn. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

a:focus-visible,
button:focus-visible {
    outline: 2px solid var(--action-text);
    outline-offset: 2px;
}

/* --------------------------------------------------------------- Typography */

h1,
h2,
h3,
h4,
.contact-button {
    font-family: 'Bricolage Grotesque', 'Helvetica Neue', Arial, sans-serif;
    font-weight: 800;
    letter-spacing: -0.025em;
    line-height: 1.02;
    text-wrap: balance;
}

h1,
h2,
h3,
h4 {
    color: var(--text-heading);
}

/* Eyebrows are metadata, so they take the blue role. */
.eyebrow {
    font-family: 'DM Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--meta);
    margin-bottom: 1rem;
}

.section-title {
    font-size: clamp(1.9rem, 7vw, 3rem);
    margin-bottom: 2.75rem;
}

/* -------------------------------------------------------------------- Hero */

.hero {
    position: relative;
    overflow: hidden;
    padding: 5rem 0 4rem;
    background: var(--page);
}

/* Ambient colour field. Soft washes in rose, blue and warm burgundy that drift
   behind the name — enough to keep the flat page from reading as a slab, not
   enough to read as a background image. Decorative, so no pointer events. */
.hero::before {
    content: '';
    position: absolute;
    inset: -25% -15%;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(32% 34% at 14% 28%, rgba(199, 110, 127, 0.14), transparent 76%),
        radial-gradient(28% 30% at 82% 16%, rgba(84, 164, 224, 0.07), transparent 76%),
        radial-gradient(34% 36% at 68% 82%, rgba(87, 26, 43, 0.45), transparent 76%);
    animation: hero-drift 24s var(--ease-out) infinite alternate;
}

.hero .container {
    position: relative;
    z-index: 1;
}

@keyframes hero-drift {
    0%   { transform: translate3d(0, 0, 0) scale(1); }
    50%  { transform: translate3d(-2%, 1.5%, 0) scale(1.05); }
    100% { transform: translate3d(1.5%, -1.5%, 0) scale(1.02); }
}

.hero h1 {
    /* Left-aligned and large — the point is confidence, not decoration. */
    font-size: clamp(3rem, 15vw, 7.5rem);
    letter-spacing: -0.04em;
    line-height: 0.92;
    margin-bottom: 1.75rem;
}

/* The name holds the line; the role beneath it cycles. Roles are ones actually
   held elsewhere on this page, set smaller than the name so a long title can
   never overflow the display type. */

.hero-name {
    display: block;
    animation: hero-rise 0.9s var(--ease-out) 0.1s both;
}

.hero-roles {
    display: block;
    position: relative;
    /* Row height is derived from --role-size rather than written in em, so it
       stays fixed even if an individual row ever needs its own font-size. */
    --role-size: clamp(1.5rem, 6vw, 3.2rem);
    --role-h: calc(var(--role-size) * 1.3);
    /* Clipped window. Roles travel further than the box is tall, so a role on
       its way out is already in a different band from the one arriving — that
       is what stops the hand-off reading as two overlapping words. Height has
       to clear the descender in "design". */
    overflow: hidden;
    height: var(--role-h);
    margin-top: 0.2em;
    font-size: var(--role-size);
    letter-spacing: -0.03em;
    /* The cycling role is the one live, changing thing in the hero, so it
       takes the rose. */
    color: var(--action-text);
    animation: hero-rise 0.9s var(--ease-out) 0.26s both;
}

/* The roles sit stacked in a clipped window and the whole track slides up one
   row at a time. Doing it this way rather than cross-fading absolutely
   positioned items means there is never a frame where the line is empty, and
   never a frame where two roles are drawn over each other — during a slide the
   two rows are simply in different bands of the window.

   10 roles at 3s each = 30s. One row is 100/10 = 10% of the cycle, held for
   most of that and then slid. The eleventh row repeats the first so the loop
   closes without a jump. Changing the number of roles means redoing both the
   duration and these percentages. */

.hero-role-track {
    display: block;
    animation: role-scroll 30s infinite;
}

.hero-role {
    display: block;
    height: var(--role-h);
    /* Absolute line-height centres the text in the row whatever its size. */
    line-height: var(--role-h);
    white-space: nowrap;
}

@keyframes role-scroll {
    0.000%   { transform: translate3d(0, calc(var(--role-h) * -0), 0); }
    7.800%   { transform: translate3d(0, calc(var(--role-h) * -0), 0); }
    10.000%  { transform: translate3d(0, calc(var(--role-h) * -1), 0); }
    17.800%  { transform: translate3d(0, calc(var(--role-h) * -1), 0); }
    20.000%  { transform: translate3d(0, calc(var(--role-h) * -2), 0); }
    27.800%  { transform: translate3d(0, calc(var(--role-h) * -2), 0); }
    30.000%  { transform: translate3d(0, calc(var(--role-h) * -3), 0); }
    37.800%  { transform: translate3d(0, calc(var(--role-h) * -3), 0); }
    40.000%  { transform: translate3d(0, calc(var(--role-h) * -4), 0); }
    47.800%  { transform: translate3d(0, calc(var(--role-h) * -4), 0); }
    50.000%  { transform: translate3d(0, calc(var(--role-h) * -5), 0); }
    57.800%  { transform: translate3d(0, calc(var(--role-h) * -5), 0); }
    60.000%  { transform: translate3d(0, calc(var(--role-h) * -6), 0); }
    67.800%  { transform: translate3d(0, calc(var(--role-h) * -6), 0); }
    70.000%  { transform: translate3d(0, calc(var(--role-h) * -7), 0); }
    77.800%  { transform: translate3d(0, calc(var(--role-h) * -7), 0); }
    80.000%  { transform: translate3d(0, calc(var(--role-h) * -8), 0); }
    87.800%  { transform: translate3d(0, calc(var(--role-h) * -8), 0); }
    90.000%  { transform: translate3d(0, calc(var(--role-h) * -9), 0); }
    97.800%  { transform: translate3d(0, calc(var(--role-h) * -9), 0); }
    100%     { transform: translate3d(0, calc(var(--role-h) * -10), 0); }
}

.hero .eyebrow {
    animation: hero-rise 0.8s var(--ease-out) both;
}

.hero-tagline {
    animation: hero-rise 0.9s var(--ease-out) 0.42s both;
    font-size: clamp(1.05rem, 4vw, 1.4rem);
    color: var(--text-body);
    max-width: 22ch;
}

@keyframes hero-rise {
    from { opacity: 0; transform: translate3d(0, 0.4em, 0); }
    to   { opacity: 1; transform: none; }
}

/* The count is a number, so it is metadata, not interaction. */
.counter {
    font-family: 'Bricolage Grotesque', sans-serif;
    font-weight: 800;
    color: var(--meta);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
}

/* ---------------------------------------------------------------- Featured */

.featured {
    padding: 4rem 0;
}

.featured-article {
    display: grid;
    gap: 1.75rem;
    margin-bottom: 4rem;
}

.featured-article:last-child {
    margin-bottom: 0;
}

.article-image {
    aspect-ratio: 4 / 3;
    background: var(--surface-warm);
    border: 0.5px solid var(--border-card);
    border-radius: var(--r-card);
    overflow: hidden;
}

.article-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.6s var(--ease-out);
}

.article-meta {
    display: flex;
    gap: 0.7rem;
    margin-bottom: 0.9rem;
    align-items: center;
    flex-wrap: wrap;
}

/* Year is blue metadata; role is a category badge on a rose tint. Neither is
   interactive, so neither takes a rose fill. */
.article-meta .year,
.article-meta .role {
    font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.article-meta .year {
    color: var(--meta);
}

.article-meta .role {
    font-weight: 500;
    line-height: 1;
    padding: 0.45rem 0.75rem;
    border-radius: var(--r-pill);
    background: var(--tint-rose);
    color: var(--text-heading);
}

.article-content h3 {
    font-size: clamp(1.5rem, 5.5vw, 2.1rem);
    margin-bottom: 1.1rem;
}

.article-content p {
    color: var(--text-body);
    margin-bottom: 1rem;
    max-width: 62ch;
}

.article-content p:last-child {
    margin-bottom: 0;
}

/* Third-party benchmark. A band spanning the whole article rather than a fifth
   paragraph in the text column, so it reads as outside validation. order:3
   keeps it last even where .reverse re-orders the image. Card, so it lifts off
   the page rather than sinking into it. */

.featured-article > .benchmark {
    order: 3;
    grid-column: 1 / -1;
    background: var(--surface-card);
    border: 0.5px solid var(--border-card);
    border-radius: var(--r-card);
    padding: 1.6rem 1.4rem;
}

.benchmark-quote {
    font-size: clamp(1.2rem, 5vw, 1.5rem);
    line-height: 1.4;
    color: var(--text-heading);
    max-width: 32ch;
    margin-bottom: 0.8rem;
}

.benchmark-source {
    color: var(--text-body);
    font-size: 0.92rem;
    max-width: 48ch;
    margin-bottom: 1rem;
}

/* Highlighter swipe: a wobbly band sized to sit over the text like a marker.
   Rose tint rather than a fill, and no blend mode — multiply only works over
   light paper, and on burgundy it would swallow the band entirely. */

.marker {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 24' preserveAspectRatio='none'%3E%3Cpath d='M0.5,2.8 C24,0.8 46,4.4 70,2.0 C92,0.2 106,3.4 119.5,1.6 L119.5,21.0 C99,23.4 79,20.0 55,22.6 C34,24.4 17,21.4 0.5,23.0 Z' fill='%23C76E7F' fill-opacity='0.42'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-size: 100% 1.02em;
    background-position: 0 0.1em;
    padding: 0 0.18em;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
}

.benchmark cite {
    display: block;
    font-family: 'DM Mono', ui-monospace, monospace;
    font-style: normal;
    font-size: 0.64rem;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    line-height: 1.5;
    color: var(--meta);
}

/* The only link in the block, so it takes the rose. */
.benchmark cite a {
    color: var(--action-text);
    text-decoration: none;
    border-bottom: 0.5px solid var(--border-action);
}

.benchmark cite a:hover {
    border-bottom-color: var(--action-text);
}

/* ---------------------------------------------------------------- All work */

.all-work {
    padding: 4rem 0;
}

.work-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
}

/* Cards lift, never sink: lighter than the page, plus a hairline. Shadows do
   no work on a dark ground, so the border carries the edge. */
.work-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface-card);
    border: 0.5px solid var(--border-card);
    border-radius: var(--r-card);
    overflow: hidden;
    transition: transform 0.35s var(--ease-spring), border-color 0.35s var(--ease-out);
}

.work-image {
    aspect-ratio: 16 / 10;
    background: var(--surface-warm);
    overflow: hidden;
}

.work-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.5s var(--ease-out);
}

.work-info {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 1.25rem 1.25rem 0;
}

.work-card h4 {
    font-size: 1.15rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
    letter-spacing: -0.015em;
    line-height: 1.2;
}

.work-desc {
    color: var(--text-body);
    font-size: 0.94rem;
    line-height: 1.6;
    margin-bottom: 1.2rem;
}

/* Footer rule separates the copy from its metadata. */
.work-footer {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: auto;
    padding: 0.9rem 0;
    border-top: 0.5px solid var(--hairline);
}

/* Uppercase mono runs much wider than a sans label, so the card footer sets
   its labels a step down and tracks them tighter — otherwise a long role
   pushes the year onto a second line and the grid's footers stop aligning. */
.work-role,
.work-period {
    font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 0.6rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.work-role {
    font-weight: 500;
    line-height: 1;
    padding: 0.4rem 0.6rem;
    border-radius: var(--r-pill);
    background: var(--tint-rose);
    color: var(--text-heading);
}

.work-period {
    color: var(--meta);
}

/* ----------------------------------------------------------------- Contact */

/* The one large beige fill on the page. Non-interactive block, dark burgundy
   type on top — beige is never a button. */
.contact {
    background: var(--beige-fill);
    color: var(--light-body);
    padding: 4.5rem 0;
}

.contact .eyebrow {
    color: var(--meta-dark);
}

.contact-headline {
    font-size: clamp(2.4rem, 11vw, 5rem);
    line-height: 0.95;
    letter-spacing: -0.035em;
    color: var(--light-heading);
    margin-bottom: 1.5rem;
}

.contact-intro {
    color: var(--light-body);
    font-size: 1.1rem;
    max-width: 40ch;
    margin-bottom: 2.25rem;
}

/* The page's single rose fill. */
.contact-button {
    display: inline-block;
    background: var(--action-fill);
    color: var(--on-action);
    text-decoration: none;
    font-weight: 600;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
    padding: 1.05rem 2rem;
    border-radius: var(--r-pill);
    transition: transform 0.2s var(--ease-spring), background-color 0.25s var(--ease-out);
    will-change: transform;
}

.contact-button:active {
    transform: scale(0.97);
}

/* ------------------------------------------------------------------ Footer */

.footer {
    background: var(--page-deep);
    color: var(--text-body);
    padding: 2.5rem 0;
    font-size: 0.85rem;
    border-top: 0.5px solid var(--hairline);
}

.footer-inner {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.footer-note {
    color: var(--text-body);
    opacity: 0.7;
}

.footer-hint {
    color: var(--action-text);
}

/* ------------------------------------------------------------------- Toast */

.toast {
    position: fixed;
    left: 50%;
    bottom: 1.5rem;
    transform: translate(-50%, 150%);
    background: var(--surface-card);
    border: 0.5px solid var(--border-strong);
    color: var(--text-heading);
    font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 0.78rem;
    letter-spacing: 0.06em;
    padding: 0.8rem 1.25rem;
    border-radius: var(--r-pill);
    z-index: 50;
    transition: transform 0.4s var(--ease-spring);
    pointer-events: none;
    white-space: nowrap;
    max-width: calc(100vw - 2rem);
}

.toast.show {
    transform: translate(-50%, 0);
}

/* ================================================================ Tablet up */

@media (min-width: 640px) {
    .container { padding: 0 2rem; }
    .hero { padding: 7rem 0 5rem; }
    .featured, .all-work { padding: 5.5rem 0; }
    .contact { padding: 6rem 0; }

    .work-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 1.75rem;
    }

    .footer-inner {
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
    }
}

/* =============================================================== Desktop up */

@media (min-width: 900px) {
    body { font-size: 1.125rem; }
    .hero { padding: 9rem 0 6rem; }
    .featured, .all-work { padding: 7rem 0; }

    .featured-article {
        grid-template-columns: 1fr 1fr;
        gap: 3.5rem;
        align-items: center;
        margin-bottom: 6rem;
    }

    /* Second featured item mirrors the first. */
    .featured-article.reverse .article-image { order: 2; }

    .featured-article > .benchmark {
        padding: 2.5rem;
    }

    .work-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: 2rem;
    }
}

/* ============================================================ Hover devices */

@media (hover: hover) and (pointer: fine) {
    .work-card:hover {
        /* Two degrees of tilt and a lift — enough to feel alive, not enough to
           make the grid look broken. The border brightens in place of the
           shadow a light theme would use. */
        transform: translateY(-6px) rotate(-0.7deg);
        border-color: var(--border-strong);
    }

    .work-card:hover .work-image img,
    .featured-article:hover .article-image img {
        transform: scale(1.045);
    }

    .contact-button:hover {
        background: var(--action-hover);
    }
}

/* ====================================================== Reduced motion */

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

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

    .work-card:hover {
        transform: none;
    }

    /* Pin the track to the first role — it never slides. */
    .hero-role-track {
        animation: none;
        transform: none;
    }
}

/* ================================================================ Scribbles

   Hand-drawn marks behind four elements. All of them are decorative: they sit
   at z-index 0 under the content, take no hit area, and are aria-hidden in the
   markup. Nothing overlaps type — the underlines live in space the heading
   reserves with its own margin, so they can never cross body copy.

   Motion is deliberately partial. Only two marks draw themselves in, the two
   that read as annotation — the scrawl around "work" and the underline under
   the contact headline. They bookend the page. The hero blob, the dots and the
   squiggle stay still, which is what makes the two moving ones feel chosen
   rather than systemic.
   ------------------------------------------------------------------------- */

.scribble {
    position: absolute;
    z-index: 0;
    pointer-events: none;
    overflow: visible;
}

.scribble path {
    fill: none;
    stroke: var(--action-fill);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    opacity: 0.2;
}

/* Hero — the topo blob draws nothing and drifts nowhere; it is texture, not an
   event. It bleeds off the right edge, which is the only part of the hero that
   is reliably clear of type at every width. */
.scribble-blob {
    right: -14%;
    top: -8%;
    width: 52%;
}

/* Dots are metadata-blue and filled, not stroked. Diagonally below the blob,
   so the two right-hand marks read as a pair rather than a pile. */
.scribble-dots {
    right: 4%;
    top: 8%;
    width: 26%;
}

.scribble-dots circle {
    fill: var(--meta);
    opacity: 0.22;
}

/* A heading that hugs its text, so a 100%-wide mark underneath matches the
   words rather than the container. */
.title-hug {
    display: inline-block;
}

/* The scrawl is sized to the word it loops around. */
.scribble-circled {
    position: relative;
    display: inline-block;
}

.scribble-scrawl {
    left: -14%;
    top: -30%;
    width: 128%;
    height: 160%;
}

.scribble-scrawl path {
    stroke-width: 1.4;
    opacity: 0.28;
}

/* Underline marks: pinned to the bottom edge of the heading box and drawn into
   the gap the heading's own margin-bottom already reserves. */
.scribble-under {
    position: relative;
}

.scribble-under .scribble {
    left: 0;
    top: 100%;
    width: 100%;
}

.scribble-squiggle {
    margin-top: 0.1em;
    height: 0.42em;
}

.scribble-squiggle path {
    stroke-width: 3;
    opacity: 0.3;
}

/* Contact sits on beige, so the ink is burgundy — the rose would read as an
   interactive element on this band. */
.contact {
    position: relative;
    overflow: hidden;
}

.contact-headline.scribble-under {
    /* Hugging the text is what keeps the underline the width of the words. As a
       full-width block the mark stretched across the whole container and the
       stroke flattened to nothing. */
    display: inline-block;
    /* Room for the underline plus the gap the headline had before. */
    margin-bottom: 2.6rem;
}

.scribble-underline {
    margin-top: 0.06em;
    height: 0.34em;
}

/* Stretching a 140x34 viewBox into a wide, shallow box squashes the stroke
   vertically, so it is drawn heavier than it looks here. */
.scribble-underline path {
    stroke: var(--light-heading);
    stroke-width: 4;
    opacity: 0.26;
}

.scribble-coil {
    right: 5%;
    top: 12%;
    width: 4.5rem;
}

.scribble-coil path {
    stroke: var(--light-heading);
    stroke-width: 2.2;
    opacity: 0.17;
}

/* ------------------------------------------------------------- Draw-in
   Only applied once .js-scribble is on <html>, so with JS off or an old
   browser the marks are simply there. pathLength="1" in the markup makes one
   dash length cover any path, whatever its real geometry. */

.js-scribble .scribble-scrawl path,
.js-scribble .scribble-underline path {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
}

.js-scribble .scribble-scrawl.is-drawn path,
.js-scribble .scribble-underline.is-drawn path {
    animation: scribble-draw 1.1s var(--ease-out) forwards;
}

/* The second stroke trails the first, the way a second pass of a pen does. */
.js-scribble .scribble-scrawl.is-drawn path:nth-child(2),
.js-scribble .scribble-underline.is-drawn path:nth-child(2) {
    animation-delay: 0.26s;
}

@keyframes scribble-draw {
    to { stroke-dashoffset: 0; }
}

/* ------------------------------------------------------- Scribbles, tablet up */

@media (min-width: 640px) {
    .scribble-coil { width: 5.5rem; }

    /* Room opens up on the right, so the dots sit under the blob instead of
       inside it. */
    .scribble-dots {
        top: auto;
        bottom: 12%;
        right: 7%;
        width: 16%;
    }
}

@media (min-width: 900px) {
    .scribble-blob { right: -10%; width: 44%; }
    .scribble-dots { right: 9%; width: 13%; }
    .scribble-coil { right: 7%; width: 7rem; }
}

/* The two marks that need room they don't have on a narrow screen: the blob
   crowds the name, and the coil reaches into the first line of the contact
   headline. Both come off rather than get shrunk into noise. */
@media (max-width: 639px) {
    .scribble-blob,
    .scribble-coil { display: none; }
}

/* ------------------------------------------------- Scribbles, reduced motion */

@media (prefers-reduced-motion: reduce) {
    /* No draw-in — the marks are present and still. */
    .js-scribble .scribble-scrawl path,
    .js-scribble .scribble-underline path {
        stroke-dasharray: none;
        stroke-dashoffset: 0;
    }
}
