Q: Por que os dois pontos duas vezes?  p::after

Para que serve os 2 pontos duas vezes (::)?

A: Porque o ::after e ::before são pseudo elementos e não seletores, existem outros assim também, ou seja eles não afetam o elemento em si, mas sim um pseudo elemento, atuais pseudo-elementos


*

*::after cria um pseudo-elemento no final dentro do(s) elementos indicados na regra

*::before cria um pseudo-elemento no começo dentro do(s) elementos indicados na regra

*::first-letter afeta o estilo apenas da primeira letra

*::first-line afeta o estilo apenas da primeira linha

*::selection afeta apenas o estilo do que é selecionado

*::backdrop (experimental) Esse pseudo-elemento é uma caixa renderizada imediatamente abaixo do elemento superior (e acima do elemento logo abaixo desse elemento, caso exista algum), dentro da camada superior


Ou seja em nenhum dos casos é afetado o elemento em si diretamente, mas algo que não é um elemento real, como seleção, letra, linha ou então criará um elemento.

É errado usar com apenas uma vez o :, como por exemplo :after ou :before?
Não é que seja errado, mas isso é uma maneira que podemos chamar de legado, antigamente tanto os pseudo-elementos quanto os seletores mais especificos usavam apenas uma vez o :, com o tempo para evitar confusões em pseudo elementos foi aplicado que deveria se usar ::, mas os navegadores para evitar que sites antigos quebrem ainda dão suporte para o uso de :after e :before.
Creio que o ideal se deseja retro-compatibilidade e ao mesmo tempo evitar que no futuro os navegadores abandonem de vez :after e :before, seria usar separadamente assim:
regra1:after {
   /*regra1*/
}

regra1::after {
   /*regra1*/
}

regra2:before {
   /*regra2*/
}

regra2::before {
   /*regra2*/
}

Note que não recomendo que use isto:
 regra1:after, regra1::after {
   /*regra1*/
 }

Pois dois seletores em uma mesma regra podem se anular se no futuro um deles for inválido (por os navegadores removerem os seletores legados :after e :before), eu expliquei sobre isto nesta pergunta:


*

*Por que seletores com prefixos em uma mesma regra não funcionam?
Espero realmente que no futuro com novas funcionalidades do CSS coisas como variáveis ou até o uso de seletores inválidos em uma mesma regra sem falhar seja possível, pois só assim poderemos evitar repetição de código e mantermos alguma compatibilidade com navegadores mais antigos ao mesmo tempo, como em celulares mais antigos por exemplo.

A: Os pseudo elements podem ter esses dois pontos dependendo do versão do CSS
/* CSS3 syntax */
::after

/* CSS2 syntax */
:after

Para esclarecer mais um pouco existem os Pseudo Elements e as Pseudo Classes.
As Pseudo Classes sempre tem apenas um  :  já os Pseudo Elements podem ter apenas um : para funcionar em Browsers mais antigos ou dois :: para as versões mais novas.
Pseudo Elements


*

*::after   

*::before 

*::first-letter 

*::first-line  

*::selection


Pseudo Classes (aqui a sintaxe é sempre com apena um : )


*

*:active

*:checked

*:default

*:dir()

*:disabled

*:empty

*:enabled

*:first

*:first-child

*:first-of-type

*:fullscreen

*:focus

*:hover

*:indeterminate

*:in-range

*:invalid

*:lang()

*:last-child

*:last-of-type

*:left

*:link

*:not()

*:nth-child()

*:nth-last-child()

*:nth-last-of-type()

*:nth-of-type()

*:only-child

*:only-of-type

*:optional

*:out-of-range

*:read-only

*:read-write

*:required

*:right

*:root

*:scope

*:target

*:valid

*:visited


Fonte:
https://developer.mozilla.org/pt-BR/docs/Web/CSS/Pseudo-elementos
https://developer.mozilla.org/pt-BR/docs/Web/CSS/Pseudo-classes

A: Os dois pontos :: são usados para criar um pseudo-elemento do elemento selecionado.
Como o próprio significado da palavra diz, pseudo são elementos "falsos", que só existem virtualmente e não estão presentes no DOM.
Para que usar ::?
Quando você quer criar um outro elemento que estará dentro do escopo do elemento selecionado. É como se fosse um clone-filho do elemento real, com propriedades próprias. A vantagem é que você pode definir este elemento virtual da forma que quiser mantendo o mesmo escopo do elemento real, como se fosse ele mesmo.
Exemplo:
Execute o snippet abaixo e clique na área vermelha que é um pseudo-elemento do checkbox. Clicando nela, é a mesma coisa de estar clicando no próprio checkbox.


#teste::after{
   content: 'Clique em mim, é como se estivesse clicando no checkbox';
   background: red;
   top: 20px;
   position: relative;
   display: inline-block;
}
<input type="checkbox" id="teste" />


Limitações
Por serem elementos apenas visuais não presentes no DOM, os pseudo-elementos não podem ser manipulados pelo JavaScript. Isso quer dizer que você não pode alterar as suas propriedades através de script, apenas por CSS.
